diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:26:54 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:26:54 +0000 |
| commit | 9a199699c2fd227dae8c1ff60a70c819e9d4fdfe (patch) | |
| tree | 1953a1b292c4637ca2a5ede1494d3a5b84cccac3 /contrib/llvm/tools | |
| parent | 2cab237b5dbfe1b3e9c7aa7a3c02d2b98fcf7462 (diff) | |
| parent | 461a67fa15370a9ec88f8f8a240bf7c123bb2029 (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/tools')
729 files changed, 63130 insertions, 33727 deletions
diff --git a/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h index 3b5ea9fa539ba..587008a7210b1 100644 --- a/contrib/llvm/tools/clang/include/clang-c/Index.h +++ b/contrib/llvm/tools/clang/include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 43 +#define CINDEX_VERSION_MINOR 45 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -334,6 +334,16 @@ CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options); CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex); /** + * \brief Sets the invocation emission path option in a CXIndex. + * + * The invocation emission path specifies a path which will contain log + * files for certain libclang invocations. A null value (default) implies that + * libclang invocations are not logged.. + */ +CINDEX_LINKAGE void +clang_CXIndex_setInvocationEmissionPathOption(CXIndex, const char *Path); + +/** * \defgroup CINDEX_FILES File manipulation routines * * @{ @@ -394,6 +404,21 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, const char *file_name); /** + * \brief Retrieve the buffer associated with the given file. + * + * \param tu the translation unit + * + * \param file the file for which to retrieve the buffer. + * + * \param size [out] if non-NULL, will be set to the size of the buffer. + * + * \returns a pointer to the buffer in memory that holds the contents of + * \p file, or a NULL pointer when the file is not loaded. + */ +CINDEX_LINKAGE const char *clang_getFileContents(CXTranslationUnit tu, + CXFile file, size_t *size); + +/** * \brief Returns non-zero if the \c file1 and \c file2 point to the same file, * or they are both NULL. */ @@ -2837,6 +2862,22 @@ enum CXLanguageKind { CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor); /** + * \brief Describe the "thread-local storage (TLS) kind" of the declaration + * referred to by a cursor. + */ +enum CXTLSKind { + CXTLS_None = 0, + CXTLS_Dynamic, + CXTLS_Static +}; + +/** + * \brief Determine the "thread-local storage (TLS) kind" of the declaration + * referred to by a cursor. + */ +CINDEX_LINKAGE enum CXTLSKind clang_getCursorTLSKind(CXCursor cursor); + +/** * \brief Returns the translation unit that a cursor originated from. */ CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor); @@ -3115,8 +3156,9 @@ enum CXTypeKind { CXType_ObjCSel = 29, CXType_Float128 = 30, CXType_Half = 31, + CXType_Float16 = 32, CXType_FirstBuiltin = CXType_Void, - CXType_LastBuiltin = CXType_Half, + CXType_LastBuiltin = CXType_Float16, CXType_Complex = 100, CXType_Pointer = 101, @@ -4276,6 +4318,12 @@ CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor); CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor); /** + * \brief Retrieve the CXStrings representing the mangled symbols of the ObjC + * class interface or implementation at the cursor. + */ +CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor); + +/** * @} */ @@ -4419,6 +4467,12 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); /** + * \brief Determine if a C++ record is abstract, i.e. whether a class or struct + * has a pure virtual member function. + */ +CINDEX_LINKAGE unsigned clang_CXXRecord_isAbstract(CXCursor C); + +/** * \brief Determine if an enum declaration refers to a scoped enum. */ CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h index 703f588c56635..a5d080035df00 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h @@ -1,4 +1,4 @@ -//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- C++ -*-===// +//===- ASTContext.h - Context to hold long-lived AST nodes ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::ASTContext interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_ASTCONTEXT_H @@ -19,8 +19,8 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclarationName.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" @@ -30,32 +30,32 @@ #include "clang/AST/Type.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Linkage.h" -#include "clang/Basic/LLVM.h" -#include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/XRayLists.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" @@ -65,7 +65,6 @@ #include <cstdint> #include <iterator> #include <memory> -#include <new> #include <string> #include <type_traits> #include <utility> @@ -75,50 +74,72 @@ namespace llvm { struct fltSemantics; -} // end namespace llvm +} // namespace llvm namespace clang { +class APValue; class ASTMutationListener; class ASTRecordLayout; class AtomicExpr; class BlockExpr; +class BuiltinTemplateDecl; class CharUnits; class CXXABI; +class CXXConstructorDecl; +class CXXMethodDecl; +class CXXRecordDecl; class DiagnosticsEngine; class Expr; +class MangleContext; class MangleNumberingContext; class MaterializeTemporaryExpr; -class TargetInfo; -// Decls -class MangleContext; +class MemberSpecializationInfo; +class Module; +class ObjCCategoryDecl; +class ObjCCategoryImplDecl; +class ObjCContainerDecl; +class ObjCImplDecl; +class ObjCImplementationDecl; +class ObjCInterfaceDecl; class ObjCIvarDecl; +class ObjCMethodDecl; class ObjCPropertyDecl; +class ObjCPropertyImplDecl; +class ObjCProtocolDecl; +class ObjCTypeParamDecl; +class Preprocessor; +class Stmt; +class StoredDeclsMap; +class TemplateDecl; +class TemplateParameterList; +class TemplateTemplateParmDecl; +class TemplateTypeParmDecl; class UnresolvedSetIterator; -class UsingDecl; class UsingShadowDecl; +class VarTemplateDecl; class VTableContextBase; namespace Builtin { - class Context; +class Context; -} // end namespace Builtin +} // namespace Builtin enum BuiltinTemplateKind : int; namespace comments { - class FullComment; +class FullComment; -} // end namespace comments +} // namespace comments struct TypeInfo { - uint64_t Width; - unsigned Align; + uint64_t Width = 0; + unsigned Align = 0; bool AlignIsRequired : 1; - TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} + TypeInfo() : AlignIsRequired(false) {} TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} }; @@ -126,7 +147,7 @@ struct TypeInfo { /// \brief Holds long-lived AST nodes (such as types and decls) that can be /// referred to throughout the semantic analysis of a file. class ASTContext : public RefCountedBase<ASTContext> { - ASTContext &this_() { return *this; } + friend class NestedNameSpecifier; mutable SmallVector<Type *, 0> Types; mutable llvm::FoldingSet<ExtQuals> ExtQualNodes; @@ -143,6 +164,8 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; mutable llvm::FoldingSet<DependentSizedExtVectorType> DependentSizedExtVectorTypes; + mutable llvm::FoldingSet<DependentAddressSpaceType> + DependentAddressSpaceTypes; mutable llvm::FoldingSet<VectorType> VectorTypes; mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&> @@ -187,8 +210,7 @@ class ASTContext : public RefCountedBase<ASTContext> { /// /// This set is managed by the NestedNameSpecifier class. mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; - mutable NestedNameSpecifier *GlobalNestedNameSpecifier; - friend class NestedNameSpecifier; + mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr; /// \brief A cache mapping from RecordDecls to ASTRecordLayouts. /// @@ -199,7 +221,7 @@ class ASTContext : public RefCountedBase<ASTContext> { ObjCLayouts; /// \brief A cache from types to size and alignment information. - typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap; + using TypeInfoMap = llvm::DenseMap<const Type *, struct TypeInfo>; mutable TypeInfoMap MemoizedTypeInfo; /// \brief A cache mapping from CXXRecordDecls to key functions. @@ -233,7 +255,7 @@ class ASTContext : public RefCountedBase<ASTContext> { public: CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) - : Parm(Parm) { } + : Parm(Parm) {} TemplateTemplateParmDecl *getParam() const { return Parm; } @@ -249,32 +271,32 @@ class ASTContext : public RefCountedBase<ASTContext> { getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; /// \brief The typedef for the __int128_t type. - mutable TypedefDecl *Int128Decl; + mutable TypedefDecl *Int128Decl = nullptr; /// \brief The typedef for the __uint128_t type. - mutable TypedefDecl *UInt128Decl; + mutable TypedefDecl *UInt128Decl = nullptr; /// \brief The typedef for the target specific predefined /// __builtin_va_list type. - mutable TypedefDecl *BuiltinVaListDecl; + mutable TypedefDecl *BuiltinVaListDecl = nullptr; /// The typedef for the predefined \c __builtin_ms_va_list type. - mutable TypedefDecl *BuiltinMSVaListDecl; + mutable TypedefDecl *BuiltinMSVaListDecl = nullptr; /// \brief The typedef for the predefined \c id type. - mutable TypedefDecl *ObjCIdDecl; + mutable TypedefDecl *ObjCIdDecl = nullptr; /// \brief The typedef for the predefined \c SEL type. - mutable TypedefDecl *ObjCSelDecl; + mutable TypedefDecl *ObjCSelDecl = nullptr; /// \brief The typedef for the predefined \c Class type. - mutable TypedefDecl *ObjCClassDecl; + mutable TypedefDecl *ObjCClassDecl = nullptr; /// \brief The typedef for the predefined \c Protocol class in Objective-C. - mutable ObjCInterfaceDecl *ObjCProtocolClassDecl; + mutable ObjCInterfaceDecl *ObjCProtocolClassDecl = nullptr; /// \brief The typedef for the predefined 'BOOL' type. - mutable TypedefDecl *BOOLDecl; + mutable TypedefDecl *BOOLDecl = nullptr; // Typedefs which may be provided defining the structure of Objective-C // pseudo-builtins @@ -298,42 +320,42 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable IdentifierInfo *TypePackElementName = nullptr; QualType ObjCConstantStringType; - mutable RecordDecl *CFConstantStringTagDecl; - mutable TypedefDecl *CFConstantStringTypeDecl; + mutable RecordDecl *CFConstantStringTagDecl = nullptr; + mutable TypedefDecl *CFConstantStringTypeDecl = nullptr; mutable QualType ObjCSuperType; QualType ObjCNSStringType; /// \brief The typedef declaration for the Objective-C "instancetype" type. - TypedefDecl *ObjCInstanceTypeDecl; + TypedefDecl *ObjCInstanceTypeDecl = nullptr; /// \brief The type for the C FILE type. - TypeDecl *FILEDecl; + TypeDecl *FILEDecl = nullptr; /// \brief The type for the C jmp_buf type. - TypeDecl *jmp_bufDecl; + TypeDecl *jmp_bufDecl = nullptr; /// \brief The type for the C sigjmp_buf type. - TypeDecl *sigjmp_bufDecl; + TypeDecl *sigjmp_bufDecl = nullptr; /// \brief The type for the C ucontext_t type. - TypeDecl *ucontext_tDecl; + TypeDecl *ucontext_tDecl = nullptr; /// \brief Type for the Block descriptor for Blocks CodeGen. /// /// Since this is only used for generation of debug info, it is not /// serialized. - mutable RecordDecl *BlockDescriptorType; + mutable RecordDecl *BlockDescriptorType = nullptr; /// \brief Type for the Block descriptor for Blocks CodeGen. /// /// Since this is only used for generation of debug info, it is not /// serialized. - mutable RecordDecl *BlockDescriptorExtendedType; + mutable RecordDecl *BlockDescriptorExtendedType = nullptr; /// \brief Declaration for the CUDA cudaConfigureCall function. - FunctionDecl *cudaConfigureCallDecl; + FunctionDecl *cudaConfigureCallDecl = nullptr; /// \brief Keeps track of all declaration attributes. /// @@ -363,12 +385,19 @@ class ASTContext : public RefCountedBase<ASTContext> { }; llvm::DenseMap<Module*, PerModuleInitializers*> ModuleInitializers; + ASTContext &this_() { return *this; } + public: /// \brief A type synonym for the TemplateOrInstantiation mapping. - typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *> - TemplateOrSpecializationInfo; + using TemplateOrSpecializationInfo = + llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>; private: + friend class ASTDeclReader; + friend class ASTReader; + friend class ASTWriter; + friend class CXXRecordDecl; + /// \brief A mapping to contain the template or declaration that /// a variable declaration describes or was instantiated from, /// respectively. @@ -438,7 +467,7 @@ private: /// Since most C++ member functions aren't virtual and therefore /// don't override anything, we store the overridden functions in /// this map on the side rather than within the CXXMethodDecl structure. - typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector; + using CXXMethodVector = llvm::TinyPtrVector<const CXXMethodDecl *>; llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods; /// \brief Mapping from each declaration context to its corresponding @@ -454,18 +483,18 @@ private: /// \brief Mapping that stores parameterIndex values for ParmVarDecls when /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. - typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable; + using ParameterIndexTable = llvm::DenseMap<const VarDecl *, unsigned>; ParameterIndexTable ParamIndices; - ImportDecl *FirstLocalImport; - ImportDecl *LastLocalImport; + ImportDecl *FirstLocalImport = nullptr; + ImportDecl *LastLocalImport = nullptr; TranslationUnitDecl *TUDecl; - mutable ExternCContextDecl *ExternCContext; - mutable BuiltinTemplateDecl *MakeIntegerSeqDecl; - mutable BuiltinTemplateDecl *TypePackElementDecl; + mutable ExternCContextDecl *ExternCContext = nullptr; + mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr; + mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr; - /// \brief The associated SourceManager object.a + /// \brief The associated SourceManager object. SourceManager &SourceMgr; /// \brief The language options used to create the AST associated with @@ -494,19 +523,14 @@ private: CXXABI *createCXXABI(const TargetInfo &T); /// \brief The logical -> physical address space map. - const LangAS::Map *AddrSpaceMap; + const LangASMap *AddrSpaceMap = nullptr; /// \brief Address space map mangling must be used with language specific /// address spaces (e.g. OpenCL/CUDA) bool AddrSpaceMapMangling; - friend class ASTDeclReader; - friend class ASTReader; - friend class ASTWriter; - friend class CXXRecordDecl; - - const TargetInfo *Target; - const TargetInfo *AuxTarget; + const TargetInfo *Target = nullptr; + const TargetInfo *AuxTarget = nullptr; clang::PrintingPolicy PrintingPolicy; public: @@ -515,31 +539,33 @@ public: Builtin::Context &BuiltinInfo; mutable DeclarationNameTable DeclarationNames; IntrusiveRefCntPtr<ExternalASTSource> ExternalSource; - ASTMutationListener *Listener; + ASTMutationListener *Listener = nullptr; /// \brief Contains parents of a node. - typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 2> ParentVector; + using ParentVector = llvm::SmallVector<ast_type_traits::DynTypedNode, 2>; /// \brief 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. - typedef llvm::DenseMap<const void *, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, - ParentVector *>> ParentMapPointers; + 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. - typedef llvm::DenseMap< - ast_type_traits::DynTypedNode, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, ParentVector *>> - ParentMapOtherNodes; + 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 { - typedef ast_type_traits::DynTypedNode DynTypedNode; + using DynTypedNode = ast_type_traits::DynTypedNode; + llvm::AlignedCharArrayUnion<ast_type_traits::DynTypedNode, ArrayRef<DynTypedNode>> Storage; bool IsSingleNode; @@ -548,6 +574,7 @@ public: DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) { new (Storage.buffer) DynTypedNode(N); } + DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) { new (Storage.buffer) ArrayRef<DynTypedNode>(A); } @@ -626,13 +653,14 @@ public: template <typename T> T *Allocate(size_t Num = 1) const { return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T))); } - void Deallocate(void *Ptr) const { } + void Deallocate(void *Ptr) const {} /// Return the total amount of physical memory allocated for representing /// AST nodes and type information. size_t getASTAllocatedMemory() const { return BumpAlloc.getTotalMemory(); } + /// Return the total memory used for various side tables. size_t getSideTableAllocatedMemory() const; @@ -649,6 +677,7 @@ public: /// Returns empty type if there is no appropriate target types. QualType getIntTypeForBitwidth(unsigned DestWidth, unsigned Signed) const; + /// getRealTypeForBitwidth - /// sets floating point QualTy according to specified bitwidth. /// Returns empty type if there is no appropriate target types. @@ -676,7 +705,7 @@ public: RawCommentList Comments; /// \brief True if comments are already loaded from ExternalASTSource. - mutable bool CommentsLoaded; + mutable bool CommentsLoaded = false; class RawCommentAndCacheFlags { public: @@ -759,24 +788,24 @@ public: } /// \brief Return the documentation comment attached to a given declaration. - /// Returns NULL if no comment is attached. + /// Returns nullptr if no comment is attached. /// - /// \param OriginalDecl if not NULL, is set to declaration AST node that had - /// the comment, if the comment we found comes from a redeclaration. + /// \param OriginalDecl if not nullptr, is set to declaration AST node that + /// had the comment, if the comment we found comes from a redeclaration. const RawComment * getRawCommentForAnyRedecl(const Decl *D, const Decl **OriginalDecl = nullptr) const; /// Return parsed documentation comment attached to a given declaration. - /// Returns NULL if no comment is attached. + /// Returns nullptr if no comment is attached. /// - /// \param PP the Preprocessor used with this TU. Could be NULL if + /// \param PP the Preprocessor used with this TU. Could be nullptr if /// preprocessor is not available. comments::FullComment *getCommentForDecl(const Decl *D, const Preprocessor *PP) const; /// Return parsed documentation comment attached to a given declaration. - /// Returns NULL if no comment is attached. Does not look at any + /// Returns nullptr if no comment is attached. Does not look at any /// redeclarations of the declaration. comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const; @@ -788,16 +817,16 @@ private: /// \brief Iterator that visits import declarations. class import_iterator { - ImportDecl *Import; + ImportDecl *Import = nullptr; public: - typedef ImportDecl *value_type; - typedef ImportDecl *reference; - typedef ImportDecl *pointer; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = ImportDecl *; + using reference = ImportDecl *; + using pointer = ImportDecl *; + using difference_type = int; + using iterator_category = std::forward_iterator_tag; - import_iterator() : Import() {} + import_iterator() = default; explicit import_iterator(ImportDecl *Import) : Import(Import) {} reference operator*() const { return Import; } @@ -876,7 +905,7 @@ public: void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); // Access to the set of methods overridden by the given C++ method. - typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator; + using overridden_cxx_method_iterator = CXXMethodVector::const_iterator; overridden_cxx_method_iterator overridden_methods_begin(const CXXMethodDecl *Method) const; @@ -884,8 +913,10 @@ public: overridden_methods_end(const CXXMethodDecl *Method) const; unsigned overridden_methods_size(const CXXMethodDecl *Method) const; - typedef llvm::iterator_range<overridden_cxx_method_iterator> - overridden_method_range; + + using overridden_method_range = + llvm::iterator_range<overridden_cxx_method_iterator>; + overridden_method_range overridden_methods(const CXXMethodDecl *Method) const; /// \brief Note that the given C++ \p Method overrides the given \p @@ -912,7 +943,8 @@ public: return Import->NextLocalImport; } - typedef llvm::iterator_range<import_iterator> import_range; + using import_range = llvm::iterator_range<import_iterator>; + import_range local_imports() const { return import_range(import_iterator(FirstLocalImport), import_iterator()); } @@ -929,6 +961,7 @@ public: /// and should be visible whenever \p M is visible. void mergeDefinitionIntoModule(NamedDecl *ND, Module *M, bool NotifyListeners = true); + /// \brief Clean up the merged definition list. Call this if you might have /// added duplicates into the list. void deduplicateMergedDefinitonsFor(NamedDecl *ND); @@ -973,6 +1006,7 @@ public: CanQualType UnsignedLongLongTy, UnsignedInt128Ty; CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty; CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON + CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType Float128ComplexTy; CanQualType VoidPtrTy, NullPtrTy; @@ -1067,7 +1101,14 @@ public: /// The resulting type has a union of the qualifiers from T and the address /// space. If T already has an address space specifier, it is silently /// replaced. - QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const; + + /// \brief Remove any existing address space on the type and returns the type + /// with qualifiers intact (or that's the idea anyway) + /// + /// The return type should be T with all prior qualifiers minus the address + /// space. + QualType removeAddrSpaceQualType(QualType T) const; /// \brief Apply Objective-C protocol qualifiers to the given type. /// \param allowOnPointerType specifies if we can apply protocol @@ -1175,6 +1216,7 @@ public: /// \brief Return a read_only pipe type for the specified type. QualType getReadPipeType(QualType T) const; + /// \brief Return a write_only pipe type for the specified type. QualType getWritePipeType(QualType T) const; @@ -1182,9 +1224,16 @@ public: /// pointer to blocks. QualType getBlockDescriptorExtendedType() const; + /// Map an AST Type to an OpenCLTypeKind enum value. + TargetInfo::OpenCLTypeKind getOpenCLTypeKind(const Type *T) const; + + /// Get address space for OpenCL type. + LangAS getOpenCLTypeAddrSpace(const Type *T) const; + void setcudaConfigureCallDecl(FunctionDecl *FD) { cudaConfigureCallDecl = FD; } + FunctionDecl *getcudaConfigureCallDecl() { return cudaConfigureCallDecl; } @@ -1192,7 +1241,6 @@ public: /// Returns true iff we need copy/dispose helpers for the given type. bool BlockRequiresCopying(QualType Ty, const VarDecl *D); - /// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set /// to false in this case. If HasByrefExtendedLayout returns true, byref variable /// has extended lifetime. @@ -1269,6 +1317,10 @@ public: Expr *SizeExpr, SourceLocation AttrLoc) const; + QualType getDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttrLoc) const; + /// \brief Return a K&R style C function type like 'int()'. QualType getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const; @@ -1396,6 +1448,7 @@ public: QualType Canonical = QualType()) const; bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); + /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in /// QT's qualified-id protocol list adopt all protocols in IDecl's list /// of protocols. @@ -1426,7 +1479,7 @@ public: /// \brief C++11 deduction pattern for 'auto &&' type. QualType getAutoRRefDeductType() const; - /// \brief C++1z deduced class template specialization type. + /// \brief C++17 deduced class template specialization type. QualType getDeducedTemplateSpecializationType(TemplateName Template, QualType DeducedType, bool IsDependent) const; @@ -1488,6 +1541,11 @@ public: /// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; + /// \brief Return the unique unsigned counterpart of "ptrdiff_t" + /// integer type. The standard (C11 7.21.6.1p7) refers to this type + /// in the definition of %tu format specifier. + QualType getUnsignedPointerDiffType() const; + /// \brief Return the unique type for "pid_t" defined in /// <sys/types.h>. We need this to compute the correct type for vfork(). QualType getProcessIDType() const; @@ -1581,6 +1639,24 @@ public: return NSCopyingName; } + CanQualType getNSUIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return UnsignedLongLongTy; + return UnsignedLongTy; + } + + CanQualType getNSIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return LongLongTy; + return LongTy; + } + /// Retrieve the identifier 'bool'. IdentifierInfo *getBoolName() const { if (!BoolName) @@ -1865,10 +1941,17 @@ public: const TemplateArgument &ArgPack) const; enum GetBuiltinTypeError { - GE_None, ///< No error - GE_Missing_stdio, ///< Missing a type from <stdio.h> - GE_Missing_setjmp, ///< Missing a type from <setjmp.h> - GE_Missing_ucontext ///< Missing a type from <ucontext.h> + /// No error + GE_None, + + /// Missing a type from <stdio.h> + GE_Missing_stdio, + + /// Missing a type from <setjmp.h> + GE_Missing_setjmp, + + /// Missing a type from <ucontext.h> + GE_Missing_ucontext }; /// \brief Return the type for the specified builtin. @@ -2019,7 +2102,7 @@ public: getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const; /// \brief Get our current best idea for the key function of the - /// given record decl, or NULL if there isn't one. + /// given record decl, or nullptr if there isn't one. /// /// The key function is, according to the Itanium C++ ABI section 5.2.3: /// ...the first non-pure virtual function that is not inline at the @@ -2072,6 +2155,10 @@ public: void CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols); + /// \brief Return true if the specified type has unique object representations + /// according to (C++17 [meta.unary.prop]p9) + bool hasUniqueObjectRepresentations(QualType Ty) const; + //===--------------------------------------------------------------------===// // Type Operators //===--------------------------------------------------------------------===// @@ -2103,7 +2190,6 @@ public: bool hasSameType(QualType T1, QualType T2) const { return getCanonicalType(T1) == getCanonicalType(T2); } - bool hasSameType(const Type *T1, const Type *T2) const { return getCanonicalType(T1) == getCanonicalType(T2); } @@ -2192,7 +2278,7 @@ public: getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; /// \brief Retrieves the default calling convention for the current target. - CallingConv getDefaultCallingConvention(bool isVariadic, + CallingConv getDefaultCallingConvention(bool IsVariadic, bool IsCXXMethod) const; /// \brief Retrieves the "canonical" template name that refers to a @@ -2326,14 +2412,14 @@ public: return getTargetAddressSpace(Q.getAddressSpace()); } - unsigned getTargetAddressSpace(unsigned AS) const; + unsigned getTargetAddressSpace(LangAS AS) const; /// Get target-dependent integer value for null pointer which is used for /// constant folding. uint64_t getTargetNullPointerValue(QualType QT) const; - bool addressSpaceMapManglingFor(unsigned AS) const { - return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace; + bool addressSpaceMapManglingFor(LangAS AS) const { + return AddrSpaceMapMangling || isTargetAddressSpace(AS); } private: @@ -2355,12 +2441,15 @@ public: bool isObjCIdType(QualType T) const { return T == getObjCIdType(); } + bool isObjCClassType(QualType T) const { return T == getObjCClassType(); } + bool isObjCSelType(QualType T) const { return T == getObjCSelType(); } + bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, bool ForCompare); @@ -2394,9 +2483,30 @@ public: QualType mergeObjCGCQualifiers(QualType, QualType); - bool doFunctionTypesMatchOnExtParameterInfos( - const FunctionProtoType *FromFunctionType, - const FunctionProtoType *ToFunctionType); + /// This function merges the ExtParameterInfo lists of two functions. It + /// returns true if the lists are compatible. The merged list is returned in + /// NewParamInfos. + /// + /// \param FirstFnType The type of the first function. + /// + /// \param SecondFnType The type of the second function. + /// + /// \param CanUseFirst This flag is set to true if the first function's + /// ExtParameterInfo list can be used as the composite list of + /// ExtParameterInfo. + /// + /// \param CanUseSecond This flag is set to true if the second function's + /// ExtParameterInfo list can be used as the composite list of + /// ExtParameterInfo. + /// + /// \param NewParamInfos The composite list of ExtParameterInfo. The list is + /// empty if none of the flags are set. + /// + bool mergeExtParameterInfo( + const FunctionProtoType *FirstFnType, + const FunctionProtoType *SecondFnType, + bool &CanUseFirst, bool &CanUseSecond, + SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos); void ResetObjCLayout(const ObjCContainerDecl *CD); @@ -2432,12 +2542,13 @@ public: bool isSentinelNullExpr(const Expr *E); - /// \brief Get the implementation of the ObjCInterfaceDecl \p D, or NULL if + /// \brief Get the implementation of the ObjCInterfaceDecl \p D, or nullptr if /// none exists. ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D); - /// \brief Get the implementation of the ObjCCategoryDecl \p D, or NULL if + + /// \brief Get the implementation of the ObjCCategoryDecl \p D, or nullptr if /// none exists. - ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); /// \brief Return true if there is at least one \@implementation in the TU. bool AnyObjCImplementation() { @@ -2447,6 +2558,7 @@ public: /// \brief Set the implementation of ObjCInterfaceDecl. void setObjCImplementation(ObjCInterfaceDecl *IFaceD, ObjCImplementationDecl *ImplD); + /// \brief Set the implementation of ObjCCategoryDecl. void setObjCImplementation(ObjCCategoryDecl *CatD, ObjCCategoryImplDecl *ImplD); @@ -2466,8 +2578,9 @@ public: /// \brief Set the copy inialization expression of a block var decl. void setBlockVarCopyInits(VarDecl*VD, Expr* Init); + /// \brief Get the copy initialization expression of the VarDecl \p VD, or - /// NULL if none exists. + /// nullptr if none exists. Expr *getBlockVarCopyInits(const VarDecl* VD); /// \brief Allocate an uninitialized TypeSourceInfo. @@ -2636,6 +2749,7 @@ private: const FieldDecl *Field, bool includeVBases = true, QualType *NotEncodedT=nullptr) const; + public: // Adds the encoding of a method parameter or return type. void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, @@ -2647,11 +2761,19 @@ public: bool isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const; enum class InlineVariableDefinitionKind { - None, ///< Not an inline variable. - Weak, ///< Weak definition of inline variable. - WeakUnknown, ///< Weak for now, might become strong later in this TU. - Strong ///< Strong definition. + /// Not an inline variable. + None, + + /// Weak definition of inline variable. + Weak, + + /// Weak for now, might become strong later in this TU. + WeakUnknown, + + /// Strong definition. + Strong }; + /// \brief Determine whether a definition of this inline variable should /// be treated as a weak or strong definition. For compatibility with /// C++14 and before, for a constexpr static data member, if there is an @@ -2661,6 +2783,9 @@ public: getInlineVariableDefinitionKind(const VarDecl *VD) const; private: + friend class DeclarationNameTable; + friend class DeclContext; + const ASTRecordLayout & getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) const; @@ -2673,26 +2798,23 @@ private: // into the datastructures which avoids this mess during deallocation but is // wasteful of memory, and here we require a lot of error prone book keeping // in order to track and run destructors while we're tearing things down. - typedef llvm::SmallVector<std::pair<void (*)(void *), void *>, 16> - DeallocationFunctionsAndArguments; + using DeallocationFunctionsAndArguments = + llvm::SmallVector<std::pair<void (*)(void *), void *>, 16>; DeallocationFunctionsAndArguments Deallocations; // FIXME: This currently contains the set of StoredDeclMaps used // by DeclContext objects. This probably should not be in ASTContext, // but we include it here so that ASTContext can quickly deallocate them. - llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; - - friend class DeclContext; - friend class DeclarationNameTable; - - void ReleaseDeclContextMaps(); - void ReleaseParentMapEntries(); + llvm::PointerIntPair<StoredDeclsMap *, 1> LastSDM; std::unique_ptr<ParentMapPointers> PointerParents; std::unique_ptr<ParentMapOtherNodes> OtherParents; std::unique_ptr<VTableContextBase> VTContext; + void ReleaseDeclContextMaps(); + void ReleaseParentMapEntries(); + public: enum PragmaSectionFlag : unsigned { PSF_None = 0, @@ -2712,27 +2834,26 @@ public: SectionInfo(DeclaratorDecl *Decl, SourceLocation PragmaSectionLocation, int SectionFlags) - : Decl(Decl), - PragmaSectionLocation(PragmaSectionLocation), - SectionFlags(SectionFlags) {} + : Decl(Decl), PragmaSectionLocation(PragmaSectionLocation), + SectionFlags(SectionFlags) {} }; llvm::StringMap<SectionInfo> SectionInfos; }; /// \brief Utility function for constructing a nullary selector. -static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) { +inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); } /// \brief Utility function for constructing an unary selector. -static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) { +inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(1, &II); } -} // end namespace clang +} // namespace clang // operator new and delete aren't allowed inside namespaces. @@ -2763,11 +2884,12 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) { /// @param C The ASTContext that provides the allocator. /// @param Alignment The alignment of the allocated memory (if the underlying /// allocator supports it). -/// @return The allocated memory. Could be NULL. +/// @return The allocated memory. Could be nullptr. inline void *operator new(size_t Bytes, const clang::ASTContext &C, size_t Alignment) { return C.Allocate(Bytes, Alignment); } + /// @brief Placement delete companion to the new above. /// /// This operator is just a companion to the new above. There is no way of @@ -2800,7 +2922,7 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) { /// @param C The ASTContext that provides the allocator. /// @param Alignment The alignment of the allocated memory (if the underlying /// allocator supports it). -/// @return The allocated memory. Could be NULL. +/// @return The allocated memory. Could be nullptr. inline void *operator new[](size_t Bytes, const clang::ASTContext& C, size_t Alignment = 8) { return C.Allocate(Bytes, Alignment); diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h b/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h index a8eff1a2fcbb5..9395d36d87e58 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h @@ -22,6 +22,7 @@ namespace clang { class CXXRecordDecl; class Decl; class DeclContext; + class Expr; class FieldDecl; class FunctionDecl; class FunctionTemplateDecl; @@ -35,6 +36,7 @@ namespace clang { class QualType; class RecordDecl; class TagDecl; + class ValueDecl; class VarDecl; class VarTemplateDecl; class VarTemplateSpecializationDecl; @@ -80,13 +82,19 @@ public: /// \brief A virtual destructor's operator delete has been resolved. virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) {} + const FunctionDecl *Delete, + Expr *ThisArg) {} /// \brief An implicit member got a definition. virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} - /// \brief A static data member was implicitly instantiated. - virtual void StaticDataMemberInstantiated(const VarDecl *D) {} + /// \brief The instantiation of a templated function or variable was + /// requested. In particular, the point of instantiation and template + /// specialization kind of \p D may have changed. + virtual void InstantiationRequested(const ValueDecl *D) {} + + /// \brief A templated variable's definition was implicitly instantiated. + virtual void VariableDefinitionInstantiated(const VarDecl *D) {} /// \brief A function template's definition was instantiated. virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {} diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h b/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h index 9078a0e80299c..3693aeccfe14f 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTUnresolvedSet.h @@ -1,4 +1,4 @@ -//===-- ASTUnresolvedSet.h - Unresolved sets of declarations ---*- C++ -*-===// +//===- ASTUnresolvedSet.h - Unresolved sets of declarations -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,14 +16,22 @@ #define LLVM_CLANG_AST_ASTUNRESOLVEDSET_H #include "clang/AST/ASTVector.h" +#include "clang/AST/DeclAccessPair.h" #include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/Specifiers.h" +#include <cassert> +#include <cstdint> namespace clang { +class NamedDecl; + /// \brief An UnresolvedSet-like class which uses the ASTContext's allocator. class ASTUnresolvedSet { + friend class LazyASTUnresolvedSet; + struct DeclsTy : ASTVector<DeclAccessPair> { - DeclsTy() {} + DeclsTy() = default; DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {} bool isLazy() const { return getTag(); } @@ -32,14 +40,12 @@ class ASTUnresolvedSet { DeclsTy Decls; - friend class LazyASTUnresolvedSet; - public: - ASTUnresolvedSet() {} + ASTUnresolvedSet() = default; ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {} - typedef UnresolvedSetIterator iterator; - typedef UnresolvedSetIterator const_iterator; + using iterator = UnresolvedSetIterator; + using const_iterator = UnresolvedSetIterator; iterator begin() { return iterator(Decls.begin()); } iterator end() { return iterator(Decls.end()); } @@ -98,13 +104,14 @@ public: } void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); } + void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) { assert(Impl.empty() || Impl.Decls.isLazy()); Impl.Decls.setLazy(true); - Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS); + Impl.addDecl(C, reinterpret_cast<NamedDecl *>(ID << 2), AS); } }; } // namespace clang -#endif +#endif // LLVM_CLANG_AST_ASTUNRESOLVEDSET_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h index 717a9e9dff340..80cd6b7007a6d 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h @@ -1,4 +1,4 @@ -//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=// +//===- ASTVector.h - Vector that uses ASTContext for allocation ---*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -18,22 +18,26 @@ #ifndef LLVM_CLANG_AST_ASTVECTOR_H #define LLVM_CLANG_AST_ASTVECTOR_H -#include "clang/AST/AttrIterator.h" #include "llvm/ADT/PointerIntPair.h" -#include "llvm/Support/type_traits.h" #include <algorithm> +#include <cassert> #include <cstddef> #include <cstring> +#include <iterator> #include <memory> +#include <type_traits> +#include <utility> namespace clang { - class ASTContext; + +class ASTContext; template<typename T> class ASTVector { private: - T *Begin, *End; - llvm::PointerIntPair<T*, 1, bool> Capacity; + T *Begin = nullptr; + T *End = nullptr; + llvm::PointerIntPair<T *, 1, bool> Capacity; void setEnd(T *P) { this->End = P; } @@ -45,7 +49,7 @@ protected: public: // Default ctor - Initialize to empty. - ASTVector() : Begin(nullptr), End(nullptr), Capacity(nullptr, false) {} + ASTVector() : Capacity(nullptr, false) {} ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) { O.Begin = O.End = nullptr; @@ -53,14 +57,15 @@ public: O.Capacity.setInt(false); } - ASTVector(const ASTContext &C, unsigned N) - : Begin(nullptr), End(nullptr), Capacity(nullptr, false) { + ASTVector(const ASTContext &C, unsigned N) : Capacity(nullptr, false) { reserve(C, N); } ASTVector &operator=(ASTVector &&RHS) { ASTVector O(std::move(RHS)); + using std::swap; + swap(Begin, O.Begin); swap(End, O.End); swap(Capacity, O.Capacity); @@ -74,19 +79,19 @@ public: } } - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T* iterator; - typedef const T* const_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = T; + using iterator = T *; + using const_iterator = const T *; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = std::reverse_iterator<iterator>; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; // forward iterator creation methods. iterator begin() { return Begin; } @@ -175,7 +180,6 @@ public: size_t capacity() const { return this->capacity_ptr() - Begin; } /// append - Add the specified range to the end of the SmallVector. - /// template<typename in_iter> void append(const ASTContext &C, in_iter in_start, in_iter in_end) { size_type NumInputs = std::distance(in_start, in_end); @@ -195,7 +199,6 @@ public: } /// append - Add the specified range to the end of the SmallVector. - /// void append(const ASTContext &C, size_type NumInputs, const T &Elt) { // Grow allocated space if needed. if (NumInputs > size_type(this->capacity_ptr()-this->end())) @@ -368,6 +371,7 @@ protected: const_iterator capacity_ptr() const { return (iterator) Capacity.getPointer(); } + iterator capacity_ptr() { return (iterator)Capacity.getPointer(); } }; @@ -401,5 +405,6 @@ void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) { Capacity.setPointer(Begin+NewCapacity); } -} // end: clang namespace -#endif +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTVECTOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h b/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h index fb9b049e5d6b1..56807b4590d37 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h +++ b/contrib/llvm/tools/clang/include/clang/AST/AttrIterator.h @@ -1,4 +1,4 @@ -//===--- AttrIterator.h - Classes for attribute iteration -------*- C++ -*-===// +//===- AttrIterator.h - Classes for attribute iteration ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,16 +15,23 @@ #define LLVM_CLANG_AST_ATTRITERATOR_H #include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstddef> #include <iterator> namespace clang { - class ASTContext; - class Attr; -} + +class ASTContext; +class Attr; + +} // namespace clang // Defined in ASTContext.h void *operator new(size_t Bytes, const clang::ASTContext &C, size_t Alignment = 8); + // FIXME: Being forced to not have a default argument here due to redeclaration // rules on default arguments sucks void *operator new[](size_t Bytes, const clang::ASTContext &C, @@ -39,13 +46,13 @@ void operator delete[](void *Ptr, const clang::ASTContext &C, size_t); namespace clang { /// AttrVec - A vector of Attr, which is how they are stored on the AST. -typedef SmallVector<Attr *, 4> AttrVec; +using AttrVec = SmallVector<Attr *, 4>; /// specific_attr_iterator - Iterates over a subrange of an AttrVec, only /// providing attributes that are of a specific type. template <typename SpecificAttr, typename Container = AttrVec> class specific_attr_iterator { - typedef typename Container::const_iterator Iterator; + using Iterator = typename Container::const_iterator; /// Current - The current, underlying iterator. /// In order to ensure we don't dereference an invalid iterator unless @@ -67,14 +74,14 @@ class specific_attr_iterator { } public: - typedef SpecificAttr* value_type; - typedef SpecificAttr* reference; - typedef SpecificAttr* pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = SpecificAttr *; + using reference = SpecificAttr *; + using pointer = SpecificAttr *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - specific_attr_iterator() : Current() { } - explicit specific_attr_iterator(Iterator i) : Current(i) { } + specific_attr_iterator() = default; + explicit specific_attr_iterator(Iterator i) : Current(i) {} reference operator*() const { AdvanceToNext(); @@ -136,6 +143,6 @@ inline SpecificAttr *getSpecificAttr(const Container& container) { return nullptr; } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_ATTRITERATOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h b/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h index 66af023c828e4..fdb7e718fe9e4 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h +++ b/contrib/llvm/tools/clang/include/clang/AST/BaseSubobject.h @@ -1,4 +1,4 @@ -//===--- BaseSubobject.h - BaseSubobject class ----------------------------===// +//===- BaseSubobject.h - BaseSubobject class --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,12 +15,15 @@ #define LLVM_CLANG_AST_BASESUBOBJECT_H #include "clang/AST/CharUnits.h" -#include "clang/AST/DeclCXX.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/type_traits.h" +#include <cstdint> +#include <utility> namespace clang { + +class CXXRecordDecl; + // BaseSubobject - Uniquely identifies a direct or indirect base class. // Stores both the base class decl and the offset from the most derived class to // the base class. Used for vtable and VTT generation. @@ -32,9 +35,9 @@ class BaseSubobject { CharUnits BaseOffset; public: - BaseSubobject() { } + BaseSubobject() = default; BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset) - : Base(Base), BaseOffset(BaseOffset) { } + : Base(Base), BaseOffset(BaseOffset) {} /// getBase - Returns the base class declaration. const CXXRecordDecl *getBase() const { return Base; } @@ -47,7 +50,7 @@ public: } }; -} // end namespace clang +} // namespace clang namespace llvm { @@ -65,7 +68,8 @@ template<> struct DenseMapInfo<clang::BaseSubobject> { } static unsigned getHashValue(const clang::BaseSubobject &Base) { - typedef std::pair<const clang::CXXRecordDecl *, clang::CharUnits> PairTy; + using PairTy = std::pair<const clang::CXXRecordDecl *, clang::CharUnits>; + return DenseMapInfo<PairTy>::getHashValue(PairTy(Base.getBase(), Base.getBaseOffset())); } @@ -81,6 +85,6 @@ template <> struct isPodLike<clang::BaseSubobject> { static const bool value = true; }; -} +} // namespace llvm -#endif +#endif // LLVM_CLANG_AST_BASESUBOBJECT_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def index 181131aba07f7..e4f5f7db2f73c 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def +++ b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def @@ -133,6 +133,9 @@ FLOATING_TYPE(Double, DoubleTy) // 'long double' FLOATING_TYPE(LongDouble, LongDoubleTy) +// '_Float16' +FLOATING_TYPE(Float16, HalfTy) + // '__float128' FLOATING_TYPE(Float128, Float128Ty) diff --git a/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h index 980608570fd68..11fb229f0c091 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h +++ b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h @@ -1,4 +1,4 @@ -//===------ CXXInheritance.h - C++ Inheritance ------------------*- C++ -*-===// +//===- CXXInheritance.h - C++ Inheritance -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,19 +16,23 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include <cassert> +#include "llvm/ADT/iterator_range.h" #include <list> +#include <memory> +#include <utility> namespace clang { - -class CXXBaseSpecifier; -class CXXMethodDecl; -class CXXRecordDecl; + +class ASTContext; class NamedDecl; /// \brief Represents an element in a path from a derived class to a @@ -66,12 +70,12 @@ struct CXXBasePathElement { /// subobject is being used. class CXXBasePath : public SmallVector<CXXBasePathElement, 4> { public: - CXXBasePath() : Access(AS_public) {} - /// \brief The access along this inheritance path. This is only /// calculated when recording paths. AS_none is a special value /// used to indicate a path which permits no legal access. - AccessSpecifier Access; + AccessSpecifier Access = AS_public; + + CXXBasePath() = default; /// \brief The set of declarations found inside this base class /// subobject. @@ -113,8 +117,10 @@ public: /// refer to the same base class subobject of type A (the virtual /// one), there is no ambiguity. class CXXBasePaths { + friend class CXXRecordDecl; + /// \brief The type from which this search originated. - CXXRecordDecl *Origin; + CXXRecordDecl *Origin = nullptr; /// Paths - The actual set of paths that can be taken from the /// derived class to the same base class. @@ -152,15 +158,13 @@ class CXXBasePaths { CXXBasePath ScratchPath; /// DetectedVirtual - The base class that is virtual. - const RecordType *DetectedVirtual; + const RecordType *DetectedVirtual = nullptr; /// \brief Array of the declarations that have been found. This /// array is constructed only if needed, e.g., to iterate over the /// results within LookupResult. std::unique_ptr<NamedDecl *[]> DeclsFound; - unsigned NumDeclsFound; - - friend class CXXRecordDecl; + unsigned NumDeclsFound = 0; void ComputeDeclsFound(); @@ -169,17 +173,16 @@ class CXXBasePaths { bool LookupInDependent = false); public: - typedef std::list<CXXBasePath>::iterator paths_iterator; - typedef std::list<CXXBasePath>::const_iterator const_paths_iterator; - typedef NamedDecl **decl_iterator; + using paths_iterator = std::list<CXXBasePath>::iterator; + using const_paths_iterator = std::list<CXXBasePath>::const_iterator; + using decl_iterator = NamedDecl **; /// BasePaths - Construct a new BasePaths structure to record the /// paths for a derived-to-base search. explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true, bool DetectVirtual = true) - : Origin(), FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), - DetectVirtual(DetectVirtual), DetectedVirtual(nullptr), - NumDeclsFound(0) {} + : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + DetectVirtual(DetectVirtual) {} paths_iterator begin() { return Paths.begin(); } paths_iterator end() { return Paths.end(); } @@ -189,7 +192,8 @@ public: CXXBasePath& front() { return Paths.front(); } const CXXBasePath& front() const { return Paths.front(); } - typedef llvm::iterator_range<decl_iterator> decl_range; + using decl_range = llvm::iterator_range<decl_iterator>; + decl_range found_decls(); /// \brief Determine whether the path from the most-derived type to the @@ -231,25 +235,24 @@ public: /// \brief Uniquely identifies a virtual method within a class /// hierarchy by the method itself and a class subobject number. struct UniqueVirtualMethod { - UniqueVirtualMethod() - : Method(nullptr), Subobject(0), InVirtualSubobject(nullptr) { } - - UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject, - const CXXRecordDecl *InVirtualSubobject) - : Method(Method), Subobject(Subobject), - InVirtualSubobject(InVirtualSubobject) { } - /// \brief The overriding virtual method. - CXXMethodDecl *Method; + CXXMethodDecl *Method = nullptr; /// \brief The subobject in which the overriding virtual method /// resides. - unsigned Subobject; + unsigned Subobject = 0; /// \brief The virtual base class subobject of which this overridden /// virtual method is a part. Note that this records the closest /// derived virtual base class subobject. - const CXXRecordDecl *InVirtualSubobject; + const CXXRecordDecl *InVirtualSubobject = nullptr; + + UniqueVirtualMethod() = default; + + UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject, + const CXXRecordDecl *InVirtualSubobject) + : Method(Method), Subobject(Subobject), + InVirtualSubobject(InVirtualSubobject) {} friend bool operator==(const UniqueVirtualMethod &X, const UniqueVirtualMethod &Y) { @@ -271,14 +274,16 @@ struct UniqueVirtualMethod { /// pair is the virtual method that overrides it (including the /// subobject in which that virtual function occurs). class OverridingMethods { - typedef SmallVector<UniqueVirtualMethod, 4> ValuesT; - typedef llvm::MapVector<unsigned, ValuesT> MapType; + using ValuesT = SmallVector<UniqueVirtualMethod, 4>; + using MapType = llvm::MapVector<unsigned, ValuesT>; + MapType Overrides; public: // Iterate over the set of subobjects that have overriding methods. - typedef MapType::iterator iterator; - typedef MapType::const_iterator const_iterator; + using iterator = MapType::iterator; + using const_iterator = MapType::const_iterator; + iterator begin() { return Overrides.begin(); } const_iterator begin() const { return Overrides.begin(); } iterator end() { return Overrides.end(); } @@ -287,10 +292,10 @@ public: // Iterate over the set of overriding virtual methods in a given // subobject. - typedef SmallVectorImpl<UniqueVirtualMethod>::iterator - overriding_iterator; - typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator - overriding_const_iterator; + using overriding_iterator = + SmallVectorImpl<UniqueVirtualMethod>::iterator; + using overriding_const_iterator = + SmallVectorImpl<UniqueVirtualMethod>::const_iterator; // Add a new overriding method for a particular subobject. void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding); @@ -357,12 +362,12 @@ public: /// subobject numbers greater than 0 refer to non-virtual base class /// subobjects of that type. class CXXFinalOverriderMap - : public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { }; + : public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> {}; /// \brief A set of all the primary bases for a class. class CXXIndirectPrimaryBaseSet - : public llvm::SmallSet<const CXXRecordDecl*, 32> { }; + : public llvm::SmallSet<const CXXRecordDecl*, 32> {}; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_CXXINHERITANCE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h b/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h index 25f6172be9b19..6487613200de3 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h +++ b/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h @@ -1,4 +1,4 @@ -//===-- CanonicalType.h - C Language Family Type Representation -*- C++ -*-===// +//===- CanonicalType.h - C Language Family Type Representation --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,13 +16,29 @@ #define LLVM_CLANG_AST_CANONICALTYPE_H #include "clang/AST/Type.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> +#include <iterator> +#include <type_traits> namespace clang { template<typename T> class CanProxy; template<typename T> struct CanProxyAdaptor; +class CXXRecordDecl; +class EnumDecl; +class Expr; +class IdentifierInfo; +class ObjCInterfaceDecl; +class RecordDecl; +class TagDecl; +class TemplateTypeParmDecl; //----------------------------------------------------------------------------// // Canonical, qualified type template @@ -46,8 +62,6 @@ template<typename T> struct CanProxyAdaptor; /// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can /// be implicitly converted to a QualType, but the reverse operation requires /// a call to ASTContext::getCanonicalType(). -/// -/// template<typename T = Type> class CanQual { /// \brief The actual, canonical type. @@ -55,7 +69,7 @@ class CanQual { public: /// \brief Constructs a NULL canonical type. - CanQual() : Stored() { } + CanQual() = default; /// \brief Converting constructor that permits implicit upcasting of /// canonical type pointers. @@ -66,12 +80,11 @@ public: /// \brief Retrieve the underlying type pointer, which refers to a /// canonical type. /// - /// The underlying pointer must not be NULL. + /// The underlying pointer must not be nullptr. const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); } /// \brief Retrieve the underlying type pointer, which refers to a - /// canonical type, or NULL. - /// + /// canonical type, or nullptr. const T *getTypePtrOrNull() const { return cast_or_null<T>(Stored.getTypePtrOrNull()); } @@ -125,9 +138,11 @@ public: bool isConstQualified() const { return Stored.isLocalConstQualified(); } + bool isVolatileQualified() const { return Stored.isLocalVolatileQualified(); } + bool isRestrictQualified() const { return Stored.isLocalRestrictQualified(); } @@ -195,7 +210,7 @@ inline bool operator!=(CanQual<T> x, CanQual<U> y) { } /// \brief Represents a canonical, potentially-qualified type. -typedef CanQual<Type> CanQualType; +using CanQualType = CanQual<Type>; inline CanQualType Type::getCanonicalTypeUnqualified() const { return CanQualType::CreateUnsafe(getCanonicalTypeInternal()); @@ -320,7 +335,7 @@ public: /// than the more typical @c QualType, to propagate the notion of "canonical" /// through the system. template<typename T> -struct CanProxyAdaptor : CanProxyBase<T> { }; +struct CanProxyAdaptor : CanProxyBase<T> {}; /// \brief Canonical proxy type returned when retrieving the members of a /// canonical type or as the result of the @c CanQual<T>::getAs member @@ -333,7 +348,7 @@ template<typename T> class CanProxy : public CanProxyAdaptor<T> { public: /// \brief Build a NULL proxy. - CanProxy() { } + CanProxy() = default; /// \brief Build a proxy to the given canonical type. CanProxy(CanQual<T> Stored) { this->Stored = Stored; } @@ -342,7 +357,7 @@ public: operator CanQual<T>() const { return this->Stored; } }; -} // end namespace clang +} // namespace clang namespace llvm { @@ -350,8 +365,9 @@ namespace llvm { /// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc. /// to return smart pointer (proxies?). template<typename T> -struct simplify_type< ::clang::CanQual<T> > { - typedef const T *SimpleType; +struct simplify_type< ::clang::CanQual<T>> { + using SimpleType = const T *; + static SimpleType getSimplifiedValue(::clang::CanQual<T> Val) { return Val.getTypePtr(); } @@ -359,19 +375,20 @@ struct simplify_type< ::clang::CanQual<T> > { // Teach SmallPtrSet that CanQual<T> is "basically a pointer". template<typename T> -class PointerLikeTypeTraits<clang::CanQual<T> > { -public: - static inline void *getAsVoidPointer(clang::CanQual<T> P) { +struct PointerLikeTypeTraits<clang::CanQual<T>> { + static void *getAsVoidPointer(clang::CanQual<T> P) { return P.getAsOpaquePtr(); } - static inline clang::CanQual<T> getFromVoidPointer(void *P) { + + static clang::CanQual<T> getFromVoidPointer(void *P) { return clang::CanQual<T>::getFromOpaquePtr(P); } + // qualifier information is encoded in the low bits. enum { NumLowBitsAvailable = 0 }; }; -} // end namespace llvm +} // namespace llvm namespace clang { @@ -389,7 +406,7 @@ struct CanTypeIterator CanQualType, typename std::iterator_traits<InputIterator>::difference_type, CanProxy<Type>, CanQualType> { - CanTypeIterator() {} + CanTypeIterator() = default; explicit CanTypeIterator(InputIterator Iter) : CanTypeIterator::iterator_adaptor_base(std::move(Iter)) {} @@ -487,6 +504,7 @@ struct CanProxyAdaptor<FunctionProtoType> LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasExtParameterInfos) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR( ArrayRef<FunctionProtoType::ExtParameterInfo>, getExtParameterInfos) + CanQualType getParamType(unsigned i) const { return CanQualType::CreateUnsafe(this->getTypePtr()->getParamType(i)); } @@ -494,8 +512,8 @@ struct CanProxyAdaptor<FunctionProtoType> LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals) - typedef CanTypeIterator<FunctionProtoType::param_type_iterator> - param_type_iterator; + using param_type_iterator = + CanTypeIterator<FunctionProtoType::param_type_iterator>; param_type_iterator param_type_begin() const { return param_type_iterator(this->getTypePtr()->param_type_begin()); @@ -567,7 +585,8 @@ struct CanProxyAdaptor<ObjCObjectType> LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass) - typedef ObjCObjectPointerType::qual_iterator qual_iterator; + using qual_iterator = ObjCObjectPointerType::qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) @@ -585,7 +604,8 @@ struct CanProxyAdaptor<ObjCObjectPointerType> LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType) - typedef ObjCObjectPointerType::qual_iterator qual_iterator; + using qual_iterator = ObjCObjectPointerType::qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) @@ -662,7 +682,6 @@ CanProxy<Type> CanTypeIterator<InputIterator>::operator->() const { return CanProxy<Type>(*this); } -} - +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_CANONICALTYPE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h b/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h index 564c8ec9b9ea0..ddead6046a147 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h +++ b/contrib/llvm/tools/clang/include/clang/AST/CharUnits.h @@ -40,14 +40,14 @@ namespace clang { typedef int64_t QuantityType; private: - QuantityType Quantity; + QuantityType Quantity = 0; explicit CharUnits(QuantityType C) : Quantity(C) {} public: /// CharUnits - A default constructor. - CharUnits() : Quantity(0) {} + CharUnits() = default; /// Zero - Construct a CharUnits quantity of zero. static CharUnits Zero() { diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h index 21641bfeb89f0..d1cc2d0a4e5e1 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/AST/CommentVisitor.h @@ -1,4 +1,4 @@ -//===--- CommentVisitor.h - Visitor for Comment subclasses ------*- C++ -*-===// +//===- CommentVisitor.h - Visitor for Comment subclasses --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,8 +16,8 @@ namespace clang { namespace comments { -template <typename T> struct make_ptr { typedef T *type; }; -template <typename T> struct make_const_ptr { typedef const T *type; }; +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> class CommentVisitorBase { @@ -64,7 +64,7 @@ template<typename ImplClass, typename RetTy=void> class ConstCommentVisitor : public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {}; -} // end namespace comments -} // end namespace clang +} // namespace comments +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_COMMENTVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DataCollection.h b/contrib/llvm/tools/clang/include/clang/AST/DataCollection.h new file mode 100644 index 0000000000000..229ac2bd0f22d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/DataCollection.h @@ -0,0 +1,65 @@ +//===--- DatatCollection.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file declares helper methods for collecting data from AST nodes. +/// +/// To collect data from Stmt nodes, subclass ConstStmtVisitor and include +/// StmtDataCollectors.inc after defining the macros that you need. This +/// provides data collection implementations for most Stmt kinds. Note +/// that that code requires some conditions to be met: +/// +/// - There must be a method addData(const T &Data) that accepts strings, +/// integral types as well as QualType. All data is forwarded using +/// to this method. +/// - The ASTContext of the Stmt must be accessible by the name Context. +/// +/// It is also possible to override individual visit methods. Have a look at +/// the DataCollector in lib/Analysis/CloneDetection.cpp for a usage example. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DATACOLLECTION_H +#define LLVM_CLANG_AST_DATACOLLECTION_H + +#include "clang/AST/ASTContext.h" + +namespace clang { +namespace data_collection { + +/// Returns a string that represents all macro expansions that expanded into the +/// given SourceLocation. +/// +/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations +/// A and B are expanded from the same macros in the same order. +std::string getMacroStack(SourceLocation Loc, ASTContext &Context); + +/// Utility functions for implementing addData() for a consumer that has a +/// method update(StringRef) +template <class T> +void addDataToConsumer(T &DataConsumer, llvm::StringRef Str) { + DataConsumer.update(Str); +} + +template <class T> void addDataToConsumer(T &DataConsumer, const QualType &QT) { + addDataToConsumer(DataConsumer, QT.getAsString()); +} + +template <class T, class Type> +typename std::enable_if< + std::is_integral<Type>::value || std::is_enum<Type>::value || + std::is_convertible<Type, size_t>::value // for llvm::hash_code + >::type +addDataToConsumer(T &DataConsumer, Type Data) { + DataConsumer.update(StringRef(reinterpret_cast<char *>(&Data), sizeof(Data))); +} + +} // end namespace data_collection +} // end namespace clang + +#endif // LLVM_CLANG_AST_DATACOLLECTION_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Decl.h b/contrib/llvm/tools/clang/include/clang/AST/Decl.h index 54e6ebcd8af2a..4db0b1ef949ba 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Decl.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Decl.h @@ -1,4 +1,4 @@ -//===--- Decl.h - Classes for representing declarations ---------*- C++ -*-===// +//===- Decl.h - Classes for representing declarations -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,33 +18,58 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/Linkage.h" -#include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/PragmaKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <string> +#include <utility> namespace clang { + +class ASTContext; struct ASTTemplateArgumentListInfo; -class CXXTemporary; +class Attr; class CompoundStmt; class DependentFunctionTemplateSpecializationInfo; +class EnumDecl; class Expr; class FunctionTemplateDecl; class FunctionTemplateSpecializationInfo; class LabelStmt; class MemberSpecializationInfo; -class NestedNameSpecifier; +class Module; +class NamespaceDecl; class ParmVarDecl; +class RecordDecl; class Stmt; class StringLiteral; +class TagDecl; class TemplateArgumentList; +class TemplateArgumentListInfo; class TemplateParameterList; class TypeAliasTemplateDecl; class TypeLoc; @@ -58,13 +83,15 @@ class VarTemplateDecl; /// TypeLoc TL = TypeSourceInfo->getTypeLoc(); /// TL.getStartLoc().print(OS, SrcMgr); /// @endcode -/// class TypeSourceInfo { - QualType Ty; // Contains a memory block after the class, used for type source information, // allocated by ASTContext. friend class ASTContext; - TypeSourceInfo(QualType ty) : Ty(ty) { } + + QualType Ty; + + TypeSourceInfo(QualType ty) : Ty(ty) {} + public: /// \brief Return the type wrapped by this type source info. QualType getType() const { return Ty; } @@ -78,14 +105,16 @@ public: /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { - virtual void anchor(); ASTContext &Ctx; /// The (most recently entered) anonymous namespace for this /// translation unit, if one has been created. - NamespaceDecl *AnonymousNamespace; + NamespaceDecl *AnonymousNamespace = nullptr; explicit TranslationUnitDecl(ASTContext &ctx); + + virtual void anchor(); + public: ASTContext &getASTContext() const { return Ctx; } @@ -93,6 +122,7 @@ public: void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; } static TranslationUnitDecl *Create(ASTContext &C); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TranslationUnit; } @@ -109,18 +139,18 @@ public: class PragmaCommentDecl final : public Decl, private llvm::TrailingObjects<PragmaCommentDecl, char> { - virtual void anchor(); - - PragmaMSCommentKind CommentKind; - - friend TrailingObjects; friend class ASTDeclReader; friend class ASTDeclWriter; + friend TrailingObjects; + + PragmaMSCommentKind CommentKind; PragmaCommentDecl(TranslationUnitDecl *TU, SourceLocation CommentLoc, PragmaMSCommentKind CommentKind) : Decl(PragmaComment, TU, CommentLoc), CommentKind(CommentKind) {} + virtual void anchor(); + public: static PragmaCommentDecl *Create(const ASTContext &C, TranslationUnitDecl *DC, SourceLocation CommentLoc, @@ -143,18 +173,18 @@ public: class PragmaDetectMismatchDecl final : public Decl, private llvm::TrailingObjects<PragmaDetectMismatchDecl, char> { - virtual void anchor(); - - size_t ValueStart; - - friend TrailingObjects; friend class ASTDeclReader; friend class ASTDeclWriter; + friend TrailingObjects; + + size_t ValueStart; PragmaDetectMismatchDecl(TranslationUnitDecl *TU, SourceLocation Loc, size_t ValueStart) : Decl(PragmaDetectMismatch, TU, Loc), ValueStart(ValueStart) {} + virtual void anchor(); + public: static PragmaDetectMismatchDecl *Create(const ASTContext &C, TranslationUnitDecl *DC, @@ -189,14 +219,16 @@ public: /// The declaration at #3 finds it is a redeclaration of \c N::f through /// lookup in the extern "C" context. class ExternCContextDecl : public Decl, public DeclContext { - virtual void anchor(); - explicit ExternCContextDecl(TranslationUnitDecl *TU) : Decl(ExternCContext, TU, SourceLocation()), DeclContext(ExternCContext) {} + + virtual void anchor(); + public: static ExternCContextDecl *Create(const ASTContext &C, TranslationUnitDecl *TU); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ExternCContext; } @@ -211,18 +243,19 @@ public: /// NamedDecl - This represents a decl with a name. Many decls have names such /// as ObjCMethodDecl, but not \@class, etc. class NamedDecl : public Decl { - virtual void anchor(); /// Name - The name of this declaration, which is typically a normal /// identifier but may also be a special kind of name (C++ /// constructor, Objective-C selector, etc.) DeclarationName Name; + virtual void anchor(); + private: NamedDecl *getUnderlyingDeclImpl() LLVM_READONLY; protected: NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) - : Decl(DK, DC, L), Name(N) { } + : Decl(DK, DC, L), Name(N) {} public: /// getIdentifier - Get the identifier that names this declaration, @@ -272,8 +305,7 @@ public: // FIXME: Remove string version. std::string getQualifiedNameAsString() const; - /// getNameForDiagnostic - Appends a human-readable name for this - /// declaration into the given stream. + /// Appends a human-readable name for this declaration into the given stream. /// /// This is the method invoked by Sema when displaying a NamedDecl /// in a diagnostic. It does not necessarily produce the same @@ -339,6 +371,12 @@ public: return clang::isExternallyVisible(getLinkageInternal()); } + /// Determine whether this declaration can be redeclared in a + /// different translation unit. + bool isExternallyDeclarable() const { + return isExternallyVisible() && !getOwningModuleForLinkage(); + } + /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); @@ -349,7 +387,14 @@ public: /// Kinds of explicit visibility. enum ExplicitVisibilityKind { + /// Do an LV computation for, ultimately, a type. + /// Visibility may be restricted by type visibility settings and + /// the visibility of template arguments. VisibilityForType, + + /// Do an LV computation for, ultimately, a non-type declaration. + /// Visibility may be restricted by value visibility settings and + /// the visibility of template arguments. VisibilityForValue }; @@ -412,10 +457,10 @@ inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { /// location of the statement. For GNU local labels (__label__), the decl /// location is where the __label__ is. class LabelDecl : public NamedDecl { - void anchor() override; LabelStmt *TheStmt; StringRef MSAsmName; - bool MSAsmNameResolved; + bool MSAsmNameResolved = false; + /// LocStart - For normal labels, this is the same as the main declaration /// label, i.e., the location of the identifier; for GNU local labels, /// this is the location of the __label__ keyword. @@ -423,10 +468,9 @@ class LabelDecl : public NamedDecl { LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, LabelStmt *S, SourceLocation StartL) - : NamedDecl(Label, DC, IdentL, II), - TheStmt(S), - MSAsmNameResolved(false), - LocStart(StartL) {} + : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {} + + void anchor() override; public: static LabelDecl *Create(ASTContext &C, DeclContext *DC, @@ -446,7 +490,7 @@ public: return SourceRange(LocStart, getLocation()); } - bool isMSAsmLabel() const { return MSAsmName.size() != 0; } + bool isMSAsmLabel() const { return !MSAsmName.empty(); } bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; } void setMSAsmLabel(StringRef Name); StringRef getMSAsmLabel() const { return MSAsmName; } @@ -464,6 +508,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext, /// LocStart - The starting location of the source range, pointing /// to either the namespace or the inline keyword. SourceLocation LocStart; + /// RBraceLoc - The ending location of the source range. SourceLocation RBraceLoc; @@ -477,12 +522,16 @@ class NamespaceDecl : public NamedDecl, public DeclContext, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl); - typedef Redeclarable<NamespaceDecl> redeclarable_base; + using redeclarable_base = Redeclarable<NamespaceDecl>; + NamespaceDecl *getNextRedeclarationImpl() override; NamespaceDecl *getPreviousDeclImpl() override; NamespaceDecl *getMostRecentDeclImpl() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, @@ -490,8 +539,9 @@ public: static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -569,22 +619,21 @@ public: static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC)); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// ValueDecl - Represent the declaration of a variable (in which case it is /// an lvalue) a function (in which case it is a function designator) or /// an enum constant. class ValueDecl : public NamedDecl { - void anchor() override; QualType DeclType; + void anchor() override; + protected: ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T) : NamedDecl(DK, DC, L, N), DeclType(T) {} + public: QualType getType() const { return DeclType; } void setType(QualType newType) { DeclType = newType; } @@ -607,28 +656,23 @@ struct QualifierInfo { /// The count includes all of the template parameter lists that were matched /// against the template-ids occurring into the NNS and possibly (in the /// case of an explicit specialization) a final "template <>". - unsigned NumTemplParamLists; + unsigned NumTemplParamLists = 0; /// TemplParamLists - A new-allocated array of size NumTemplParamLists, /// containing pointers to the "outer" template parameter lists. /// It includes all of the template parameter lists that were matched /// against the template-ids occurring into the NNS and possibly (in the /// case of an explicit specialization) a final "template <>". - TemplateParameterList** TemplParamLists; + TemplateParameterList** TemplParamLists = nullptr; - /// Default constructor. - QualifierInfo() - : QualifierLoc(), NumTemplParamLists(0), TemplParamLists(nullptr) {} + QualifierInfo() = default; + QualifierInfo(const QualifierInfo &) = delete; + QualifierInfo& operator=(const QualifierInfo &) = delete; /// setTemplateParameterListsInfo - Sets info about "outer" template /// parameter lists. void setTemplateParameterListsInfo(ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists); - -private: - // Copy constructor and copy assignment are disabled. - QualifierInfo(const QualifierInfo&) = delete; - QualifierInfo& operator=(const QualifierInfo&) = delete; }; /// \brief Represents a ValueDecl that came out of a declarator. @@ -640,7 +684,7 @@ class DeclaratorDecl : public ValueDecl { TypeSourceInfo *TInfo; }; - llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo; + llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo; /// InnerLocStart - The start of the source range for this declaration, /// ignoring outer template declarations. @@ -654,15 +698,18 @@ protected: DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, SourceLocation StartL) - : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) { - } + : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) {} public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + TypeSourceInfo *getTypeSourceInfo() const { return hasExtInfo() ? getExtInfo()->TInfo : DeclInfo.get<TypeSourceInfo*>(); } + void setTypeSourceInfo(TypeSourceInfo *TI) { if (hasExtInfo()) getExtInfo()->TInfo = TI; @@ -680,6 +727,7 @@ public: SourceLocation getOuterLocStart() const; SourceRange getSourceRange() const override LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY { return getOuterLocStart(); } @@ -704,10 +752,12 @@ public: unsigned getNumTemplateParameterLists() const { return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; } + TemplateParameterList *getTemplateParameterList(unsigned index) const { assert(index < getNumTemplateParameterLists()); return getExtInfo()->TemplParamLists[index]; } + void setTemplateParameterListsInfo(ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists); @@ -718,18 +768,12 @@ public: static bool classofKind(Kind K) { return K >= firstDeclarator && K <= lastDeclarator; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Structure used to store a statement, the constant value to /// which it was evaluated (if any), and whether or not the statement /// is an integral constant expression (if known). struct EvaluatedStmt { - EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), - CheckingICE(false), IsICE(false) { } - /// \brief Whether this statement was already evaluated. bool WasEvaluated : 1; @@ -751,32 +795,46 @@ struct EvaluatedStmt { Stmt *Value; APValue Evaluated; + + EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), + CheckingICE(false), IsICE(false) {} + }; /// VarDecl - An instance of this class is created to represent a variable /// declaration or definition. class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { public: - /// getStorageClassSpecifierString - Return the string used to - /// specify the storage class \p SC. - /// - /// It is illegal to call this function with SC == None. - static const char *getStorageClassSpecifierString(StorageClass SC); - /// \brief Initialization styles. enum InitializationStyle { - CInit, ///< C-style initialization with assignment - CallInit, ///< Call-style initialization (C++98) - ListInit ///< Direct list-initialization (C++11) + /// C-style initialization with assignment + CInit, + + /// Call-style initialization (C++98) + CallInit, + + /// Direct list-initialization (C++11) + ListInit }; /// \brief Kinds of thread-local storage. enum TLSKind { - TLS_None, ///< Not a TLS variable. - TLS_Static, ///< TLS with a known-constant initializer. - TLS_Dynamic ///< TLS with a dynamic initializer. + /// Not a TLS variable. + TLS_None, + + /// TLS with a known-constant initializer. + TLS_Static, + + /// TLS with a dynamic initializer. + TLS_Dynamic }; + /// getStorageClassSpecifierString - Return the string used to + /// specify the storage class \p SC. + /// + /// It is illegal to call this function with SC == None. + static const char *getStorageClassSpecifierString(StorageClass SC); + protected: // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we // have allocated the auxiliary struct of information there. @@ -785,16 +843,20 @@ protected: // this as *many* VarDecls are ParmVarDecls that don't have default // arguments. We could save some space by moving this pointer union to be // allocated in trailing space when necessary. - typedef llvm::PointerUnion<Stmt *, EvaluatedStmt *> InitType; + using InitType = llvm::PointerUnion<Stmt *, EvaluatedStmt *>; /// \brief The initializer for this variable or, for a ParmVarDecl, the /// C++ default argument. mutable InitType Init; private: + friend class ASTDeclReader; + friend class ASTNodeImporter; + friend class StmtIteratorBase; + class VarDeclBitfields { - friend class VarDecl; friend class ASTDeclReader; + friend class VarDecl; unsigned SClass : 3; unsigned TSCSpec : 2; @@ -802,10 +864,6 @@ private: }; enum { NumVarDeclBits = 7 }; - friend class ASTDeclReader; - friend class StmtIteratorBase; - friend class ASTNodeImporter; - protected: enum { NumParameterIndexBits = 8 }; @@ -817,8 +875,8 @@ protected: }; class ParmVarDeclBitfields { - friend class ParmVarDecl; friend class ASTDeclReader; + friend class ParmVarDecl; unsigned : NumVarDeclBits; @@ -850,9 +908,9 @@ protected: }; class NonParmVarDeclBitfields { - friend class VarDecl; - friend class ImplicitParamDecl; friend class ASTDeclReader; + friend class ImplicitParamDecl; + friend class VarDecl; unsigned : NumVarDeclBits; @@ -912,20 +970,24 @@ protected: SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC); - typedef Redeclarable<VarDecl> redeclarable_base; + using redeclarable_base = Redeclarable<VarDecl>; + VarDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + VarDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + VarDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -1030,7 +1092,6 @@ public: /// inside of functions. It also includes variables inside blocks. /// /// void foo() { int x; static int y; extern int z; } - /// bool isLocalVarDecl() const { if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; @@ -1073,9 +1134,14 @@ public: } enum DefinitionKind { - DeclarationOnly, ///< This declaration is only a declaration. - TentativeDefinition, ///< This declaration is a tentative definition. - Definition ///< This declaration is definitely a definition. + /// This declaration is only a declaration. + DeclarationOnly, + + /// This declaration is a tentative definition. + TentativeDefinition, + + /// This declaration is definitely a definition. + Definition }; /// \brief Check whether this declaration is a definition. If this could be @@ -1205,6 +1271,7 @@ public: InitializationStyle getInitStyle() const { return static_cast<InitializationStyle>(VarDeclBits.InitStyle); } + /// \brief Whether the initializer is a direct-initializer (list or call). bool isDirectInit() const { return getInitStyle() != CInit; @@ -1222,8 +1289,8 @@ public: /// definitions one of which needs to be demoted to a declaration to keep /// the AST invariants. void demoteThisDefinitionToDeclaration() { - assert (isThisDeclarationADefinition() && "Not a definition!"); - assert (!isa<ParmVarDecl>(this) && "Cannot demote ParmVarDecls!"); + assert(isThisDeclarationADefinition() && "Not a definition!"); + assert(!isa<ParmVarDecl>(this) && "Cannot demote ParmVarDecls!"); NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = 1; } @@ -1387,12 +1454,23 @@ public: /// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured /// context or something else. enum ImplicitParamKind : unsigned { - ObjCSelf, /// Parameter for Objective-C 'self' argument - ObjCCmd, /// Parameter for Objective-C '_cmd' argument - CXXThis, /// Parameter for C++ 'this' argument - CXXVTT, /// Parameter for C++ virtual table pointers - CapturedContext, /// Parameter for captured context - Other, /// Other implicit parameter + /// Parameter for Objective-C 'self' argument + ObjCSelf, + + /// Parameter for Objective-C '_cmd' argument + ObjCCmd, + + /// Parameter for C++ 'this' argument + CXXThis, + + /// Parameter for C++ virtual table pointers + CXXVTT, + + /// Parameter for captured context + CapturedContext, + + /// Other implicit parameter + Other, }; /// Create implicit parameter. @@ -1425,6 +1503,7 @@ public: ImplicitParamKind getParameterKind() const { return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind); } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ImplicitParam; } @@ -1604,8 +1683,8 @@ private: unsigned getParameterIndexLarge() const; }; -/// FunctionDecl - An instance of this class is created to represent a -/// function declaration or definition. +/// An instance of this class is created to represent a function declaration or +/// definition. /// /// Since a given function can be declared several times in a program, /// there may be several FunctionDecls that correspond to that @@ -1631,7 +1710,7 @@ private: /// ParamInfo - new[]'d array of pointers to VarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. - ParmVarDecl **ParamInfo; + ParmVarDecl **ParamInfo = nullptr; LazyDeclStmtPtr Body; @@ -1640,10 +1719,12 @@ private: unsigned SClass : 3; unsigned IsInline : 1; unsigned IsInlineSpecified : 1; + protected: // This is shared by CXXConstructorDecl, CXXConversionDecl, and // CXXDeductionGuideDecl. unsigned IsExplicitSpecified : 1; + private: unsigned IsVirtualAsWritten : 1; unsigned IsPure : 1; @@ -1656,7 +1737,7 @@ private: unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; - unsigned InstantiationIsPending:1; + unsigned InstantiationIsPending : 1; /// \brief Indicates if the function uses __try. unsigned UsesSEHTry : 1; @@ -1669,6 +1750,15 @@ private: /// parsing it. unsigned WillHaveBody : 1; +protected: + /// [C++17] Only used by CXXDeductionGuideDecl. Declared here to avoid + /// increasing the size of CXXDeductionGuideDecl by the size of an unsigned + /// int as opposed to adding a single bit to FunctionDecl. + /// Indicates that the Deduction Guide is the implicitly generated 'copy + /// deduction candidate' (is used during overload resolution). + unsigned IsCopyDeductionCandidate : 1; + +private: /// \brief End part of this FunctionDecl's source range. /// /// We could compute the full range in getSourceRange(). However, when we're @@ -1696,8 +1786,8 @@ private: DependentFunctionTemplateSpecializationInfo *> TemplateOrSpecialization; - /// DNLoc - Provides source/type location info for the - /// declaration name embedded in the DeclaratorDecl base class. + /// Provides source/type location info for the declaration name embedded in + /// the DeclaratorDecl base class. DeclarationNameLoc DNLoc; /// \brief Specify that this function declaration is actually a function @@ -1743,33 +1833,38 @@ protected: bool isConstexprSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), - DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(), - SClass(S), IsInline(isInlineSpecified), - IsInlineSpecified(isInlineSpecified), IsExplicitSpecified(false), - IsVirtualAsWritten(false), IsPure(false), + DeclContext(DK), redeclarable_base(C), SClass(S), + IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), + IsExplicitSpecified(false), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), - InstantiationIsPending(false), - UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), - EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), - DNLoc(NameInfo.getInfo()) {} + InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false), + WillHaveBody(false), IsCopyDeductionCandidate(false), + EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {} + + using redeclarable_base = Redeclarable<FunctionDecl>; - typedef Redeclarable<FunctionDecl> redeclarable_base; FunctionDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + FunctionDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + FunctionDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + friend class ASTDeclReader; + friend class ASTDeclWriter; + + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -1826,13 +1921,13 @@ public: return hasBody(Definition); } - /// hasTrivialBody - Returns whether the function has a trivial body that does - /// not require any specific codegen. + /// Returns whether the function has a trivial body that does not require any + /// specific codegen. bool hasTrivialBody() const; - /// isDefined - Returns true if the function is defined at all, including - /// a deleted definition. Except for the behavior when the function is - /// deleted, behaves like hasBody. + /// Returns true if the function is defined at all, including a deleted + /// definition. Except for the behavior when the function is deleted, behaves + /// like hasBody. bool isDefined(const FunctionDecl *&Definition) const; virtual bool isDefined() const { @@ -1851,11 +1946,10 @@ public: return const_cast<FunctionDecl *>(this)->getDefinition(); } - /// getBody - Retrieve the body (definition) of the function. The - /// function body might be in any of the (re-)declarations of this - /// function. The variant that accepts a FunctionDecl pointer will - /// set that function declaration to the actual declaration - /// containing the body (if there is one). + /// Retrieve the body (definition) of the function. The function body might be + /// in any of the (re-)declarations of this function. The variant that accepts + /// a FunctionDecl pointer will set that function declaration to the actual + /// declaration containing the body (if there is one). /// NOTE: For checking if there is a body, use hasBody() instead, to avoid /// unnecessary AST de-serialization of the body. Stmt *getBody(const FunctionDecl *&Definition) const; @@ -1870,15 +1964,13 @@ public: /// /// This does not determine whether the function has been defined (e.g., in a /// previous definition); for that information, use isDefined. - /// bool isThisDeclarationADefinition() const { - return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed || - WillHaveBody || hasDefiningAttr(); + return IsDeleted || IsDefaulted || Body || HasSkippedBody || + IsLateTemplateParsed || WillHaveBody || hasDefiningAttr(); } - /// doesThisDeclarationHaveABody - Returns whether this specific - /// declaration of the function has a body - that is, if it is a non- - /// deleted definition. + /// Returns whether this specific declaration of the function has a body - + /// that is, if it is a non-deleted definition. bool doesThisDeclarationHaveABody() const { return Body || IsLateTemplateParsed; } @@ -2023,6 +2115,9 @@ public: /// true through IsAligned. bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; + /// \brief Determine whether this is a destroying operator delete. + bool isDestroyingOperatorDelete() const; + /// Compute the language linkage. LanguageLinkage getLanguageLinkage() const; @@ -2071,8 +2166,9 @@ public: } // Iterator access to formal parameters. - typedef MutableArrayRef<ParmVarDecl *>::iterator param_iterator; - typedef ArrayRef<ParmVarDecl *>::const_iterator param_const_iterator; + using param_iterator = MutableArrayRef<ParmVarDecl *>::iterator; + using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; + bool param_empty() const { return parameters().empty(); } param_iterator param_begin() { return parameters().begin(); } param_iterator param_end() { return parameters().end(); } @@ -2080,9 +2176,9 @@ public: param_const_iterator param_end() const { return parameters().end(); } size_t param_size() const { return parameters().size(); } - /// getNumParams - Return the number of parameters this function must have - /// based on its FunctionType. This is the length of the ParamInfo array - /// after it has been created. + /// Return the number of parameters this function must have based on its + /// FunctionType. This is the length of the ParamInfo array after it has been + /// created. unsigned getNumParams() const; const ParmVarDecl *getParamDecl(unsigned i) const { @@ -2097,10 +2193,9 @@ public: setParams(getASTContext(), NewParamInfo); } - /// getMinRequiredArguments - Returns the minimum number of arguments - /// needed to call this function. This may be fewer than the number of - /// function parameters, if some of the parameters have default - /// arguments (in C++). + /// Returns the minimum number of arguments needed to call this function. This + /// may be fewer than the number of function parameters, if some of the + /// parameters have default arguments (in C++). unsigned getMinRequiredArguments() const; QualType getReturnType() const { @@ -2355,18 +2450,14 @@ public: static FunctionDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC)); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; - /// FieldDecl - An instance of this class is created by Sema::ActOnField to /// represent a member of a struct/union/class. class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { - // FIXME: This can be packed into the bitfields in Decl. + unsigned BitField : 1; unsigned Mutable : 1; - mutable unsigned CachedFieldIndex : 31; + mutable unsigned CachedFieldIndex : 30; /// The kinds of value we can store in InitializerOrBitWidth. /// @@ -2376,7 +2467,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { /// If the pointer is null, there's nothing special. Otherwise, /// this is a bitfield and the pointer is the Expr* storing the /// bit-width. - ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit, + ISK_NoInit = (unsigned) ICIS_NoInit, /// The pointer is an (optional due to delayed parsing) Expr* /// holding the copy-initializer. @@ -2391,30 +2482,40 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { ISK_CapturedVLAType, }; - /// \brief Storage for either the bit-width, the in-class - /// initializer, or the captured variable length array bound. - /// - /// We can safely combine these because in-class initializers are - /// not permitted for bit-fields, and both are exclusive with VLA - /// captures. + /// If this is a bitfield with a default member initializer, this + /// structure is used to represent the two expressions. + struct InitAndBitWidth { + Expr *Init; + Expr *BitWidth; + }; + + /// \brief Storage for either the bit-width, the in-class initializer, or + /// both (via InitAndBitWidth), or the captured variable length array bound. /// /// If the storage kind is ISK_InClassCopyInit or /// ISK_InClassListInit, but the initializer is null, then this - /// field has an in-class initializer which has not yet been parsed + /// field has an in-class initializer that has not yet been parsed /// and attached. + // FIXME: Tail-allocate this to reduce the size of FieldDecl in the + // overwhelmingly common case that we have none of these things. llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage; + protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - Mutable(Mutable), CachedFieldIndex(0), - InitStorage(BW, (InitStorageKind) InitStyle) { - assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); + BitField(false), Mutable(Mutable), CachedFieldIndex(0), + InitStorage(nullptr, (InitStorageKind) InitStyle) { + if (BW) + setBitWidth(BW); } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static FieldDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, @@ -2431,10 +2532,7 @@ public: bool isMutable() const { return Mutable; } /// \brief Determines whether this field is a bitfield. - bool isBitField() const { - return InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() != nullptr; - } + bool isBitField() const { return BitField; } /// @brief Determines whether this is an unnamed bitfield. bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } @@ -2446,66 +2544,77 @@ public: bool isAnonymousStructOrUnion() const; Expr *getBitWidth() const { - return isBitField() - ? static_cast<Expr *>(InitStorage.getPointer()) - : nullptr; + if (!BitField) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (getInClassInitStyle()) + return static_cast<InitAndBitWidth*>(Ptr)->BitWidth; + return static_cast<Expr*>(Ptr); } + unsigned getBitWidthValue(const ASTContext &Ctx) const; /// setBitWidth - Set the bit-field width for this member. // Note: used by some clients (i.e., do not remove it). void setBitWidth(Expr *Width) { - assert(InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); - InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); + assert(!hasCapturedVLAType() && !BitField && + "bit width or captured type already set"); + assert(Width && "no bit width specified"); + InitStorage.setPointer( + InitStorage.getInt() + ? new (getASTContext()) + InitAndBitWidth{getInClassInitializer(), Width} + : static_cast<void*>(Width)); + BitField = true; } /// removeBitWidth - Remove the bit-field width from this member. // Note: used by some clients (i.e., do not remove it). void removeBitWidth() { assert(isBitField() && "no bitfield width to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + InitStorage.setPointer(getInClassInitializer()); + BitField = false; } - /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which - /// this field has. + /// Get the kind of (C++11) default member initializer that this field has. InClassInitStyle getInClassInitStyle() const { InitStorageKind storageKind = InitStorage.getInt(); return (storageKind == ISK_CapturedVLAType ? ICIS_NoInit : (InClassInitStyle) storageKind); } - /// hasInClassInitializer - Determine whether this member has a C++11 in-class - /// initializer. + /// Determine whether this member has a C++11 default member initializer. bool hasInClassInitializer() const { return getInClassInitStyle() != ICIS_NoInit; } - /// getInClassInitializer - Get the C++11 in-class initializer for this - /// member, or null if one has not been set. If a valid declaration has an - /// in-class initializer, but this returns null, then we have not parsed and - /// attached it yet. + /// Get the C++11 default member initializer for this member, or null if one + /// has not been set. If a valid declaration has a default member initializer, + /// but this returns null, then we have not parsed and attached it yet. Expr *getInClassInitializer() const { - return hasInClassInitializer() - ? static_cast<Expr *>(InitStorage.getPointer()) - : nullptr; + if (!hasInClassInitializer()) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (BitField) + return static_cast<InitAndBitWidth*>(Ptr)->Init; + return static_cast<Expr*>(Ptr); } /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. void setInClassInitializer(Expr *Init) { - assert(hasInClassInitializer() && - InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); - InitStorage.setPointer(Init); + assert(hasInClassInitializer() && !getInClassInitializer()); + if (BitField) + static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init; + else + InitStorage.setPointer(Init); } /// removeInClassInitializer - Remove the C++11 in-class initializer from this /// member. void removeInClassInitializer() { assert(hasInClassInitializer() && "no initializer to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit); } /// \brief Determine whether this member captures the variable length array @@ -2520,6 +2629,7 @@ public: InitStorage.getPointer()) : nullptr; } + /// \brief Set the captured variable length array type for this field. void setCapturedVLAType(const VariableArrayType *VLAType); @@ -2542,9 +2652,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// EnumConstantDecl - An instance of this object exists for each enum constant @@ -2554,6 +2661,7 @@ public: class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> { Stmt *Init; // an integer constant expression llvm::APSInt Val; // The value. + protected: EnumConstantDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E, @@ -2561,6 +2669,7 @@ protected: : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {} public: + friend class StmtIteratorBase; static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC, SourceLocation L, IdentifierInfo *Id, @@ -2584,8 +2693,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == EnumConstant; } - - friend class StmtIteratorBase; }; /// IndirectFieldDecl - An instance of this class is created to represent a @@ -2593,7 +2700,6 @@ public: /// IndirectFieldDecl are always implicit. class IndirectFieldDecl : public ValueDecl, public Mergeable<IndirectFieldDecl> { - void anchor() override; NamedDecl **Chaining; unsigned ChainingSize; @@ -2601,14 +2707,18 @@ class IndirectFieldDecl : public ValueDecl, DeclarationName N, QualType T, MutableArrayRef<NamedDecl *> CH); + void anchor() override; + public: + friend class ASTDeclReader; + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, llvm::MutableArrayRef<NamedDecl *> CH); static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); - typedef ArrayRef<NamedDecl *>::const_iterator chain_iterator; + using chain_iterator = ArrayRef<NamedDecl *>::const_iterator; ArrayRef<NamedDecl *> chain() const { return llvm::makeArrayRef(Chaining, ChainingSize); @@ -2634,26 +2744,27 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == IndirectField; } - friend class ASTDeclReader; }; /// TypeDecl - Represents a declaration of a type. -/// class TypeDecl : public NamedDecl { - void anchor() override; + friend class ASTContext; + /// TypeForDecl - This indicates the Type object that represents /// this TypeDecl. It is a cache maintained by /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. - mutable const Type *TypeForDecl; + mutable const Type *TypeForDecl = nullptr; + /// LocStart - The start of the source range for this declaration. SourceLocation LocStart; - friend class ASTContext; + + void anchor() override; protected: TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation StartL = SourceLocation()) - : NamedDecl(DK, DC, L, Id), TypeForDecl(nullptr), LocStart(StartL) {} + : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} public: // Low-level accessor. If you just want the type defined by this node, @@ -2677,18 +2788,18 @@ public: static bool classofKind(Kind K) { return K >= firstType && K <= lastType; } }; - /// Base class for declarations which introduce a typedef-name. class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { - void anchor() override; - typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo; - llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo; + using ModedTInfo = std::pair<TypeSourceInfo *, QualType>; + llvm::PointerUnion<TypeSourceInfo *, ModedTInfo *> MaybeModedTInfo; // FIXME: This can be packed into the bitfields in Decl. /// If 0, we have not computed IsTransparentTag. /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1). mutable unsigned CacheIsTransparentTag : 2; + void anchor() override; + protected: TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -2696,20 +2807,24 @@ protected: : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {} - typedef Redeclarable<TypedefNameDecl> redeclarable_base; + using redeclarable_base = Redeclarable<TypedefNameDecl>; + TypedefNameDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + TypedefNameDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + TypedefNameDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -2724,14 +2839,17 @@ public: ? MaybeModedTInfo.get<ModedTInfo*>()->first : MaybeModedTInfo.get<TypeSourceInfo*>(); } + QualType getUnderlyingType() const { return isModed() ? MaybeModedTInfo.get<ModedTInfo*>()->second : MaybeModedTInfo.get<TypeSourceInfo*>()->getType(); } + void setTypeSourceInfo(TypeSourceInfo *newType) { MaybeModedTInfo = newType; } + void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) { MaybeModedTInfo = new (getASTContext()) ModedTInfo(unmodedTSI, modedTy); } @@ -2817,7 +2935,7 @@ class TagDecl : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { public: // This is really ugly. - typedef TagTypeKind TagKind; + using TagKind = TagTypeKind; private: // FIXME: This can be packed into the bitfields in Decl. @@ -2850,6 +2968,7 @@ protected: /// IsScoped - True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. unsigned IsScoped : 1; + /// IsScopedUsingClassTag - If this tag declaration is a scoped enum, /// then this is true if the scoped enum was declared using the class /// tag, false if it was declared with the struct tag. No meaning is @@ -2869,12 +2988,13 @@ protected: /// Has the full definition of this type been required by a use somewhere in /// the TU. unsigned IsCompleteDefinitionRequired : 1; + private: SourceRange BraceRange; // A struct representing syntactic qualifier info, // to be used for the (uncommon) case of out-of-line declarations. - typedef QualifierInfo ExtInfo; + using ExtInfo = QualifierInfo; /// \brief If the (out-of-line) tag declaration name /// is qualified, it points to the qualifier info (nns and range); @@ -2906,13 +3026,16 @@ protected: setPreviousDecl(PrevDecl); } - typedef Redeclarable<TagDecl> redeclarable_base; + using redeclarable_base = Redeclarable<TagDecl>; + TagDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + TagDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + TagDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } @@ -2923,8 +3046,12 @@ protected: void completeDefinition(); public: - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + friend class ASTDeclReader; + friend class ASTDeclWriter; + + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -3074,10 +3201,12 @@ public: unsigned getNumTemplateParameterLists() const { return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; } + TemplateParameterList *getTemplateParameterList(unsigned i) const { assert(i < getNumTemplateParameterLists()); return getExtInfo()->TemplParamLists[i]; } + void setTemplateParameterListsInfo(ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists); @@ -3088,19 +3217,16 @@ public: static DeclContext *castToDeclContext(const TagDecl *D) { return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); } + static TagDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// EnumDecl - Represents an enum. In C++11, enums can be forward-declared /// with a fixed underlying type, and in C we allow them to be forward-declared /// with no underlying type as an extension. class EnumDecl : public TagDecl { - void anchor() override; /// IntegerType - This represent the integer type that the enum corresponds /// to for code generation purposes. Note that the enumerator constants may /// have a different type than this does. @@ -3115,8 +3241,7 @@ class EnumDecl : public TagDecl { /// The underlying type of an enumeration never has any qualifiers, so /// we can get away with just storing a raw Type*, and thus save an /// extra pointer when TypeSourceInfo is needed. - - llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType; + llvm::PointerUnion<const Type *, TypeSourceInfo *> IntegerType; /// PromotionType - The integer type that values of this type should /// promote to. In C, enumerators are generally of an integer type @@ -3127,13 +3252,12 @@ class EnumDecl : public TagDecl { /// \brief If this enumeration is an instantiation of a member enumeration /// of a class template specialization, this is the member specialization /// information. - MemberSpecializationInfo *SpecializationInfo; + MemberSpecializationInfo *SpecializationInfo = nullptr; EnumDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, bool Scoped, bool ScopedUsingClassTag, bool Fixed) - : TagDecl(Enum, TTK_Enum, C, DC, IdLoc, Id, PrevDecl, StartLoc), - SpecializationInfo(nullptr) { + : TagDecl(Enum, TTK_Enum, C, DC, IdLoc, Id, PrevDecl, StartLoc) { assert(Scoped || !ScopedUsingClassTag); IntegerType = (const Type *)nullptr; NumNegativeBits = 0; @@ -3143,9 +3267,13 @@ class EnumDecl : public TagDecl { IsFixed = Fixed; } + void anchor() override; + void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, TemplateSpecializationKind TSK); public: + friend class ASTDeclReader; + EnumDecl *getCanonicalDecl() override { return cast<EnumDecl>(TagDecl::getCanonicalDecl()); } @@ -3191,9 +3319,9 @@ public: // enumerator_iterator - Iterates through the enumerators of this // enumeration. - typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; - typedef llvm::iterator_range<specific_decl_iterator<EnumConstantDecl>> - enumerator_range; + using enumerator_iterator = specific_decl_iterator<EnumConstantDecl>; + using enumerator_range = + llvm::iterator_range<specific_decl_iterator<EnumConstantDecl>>; enumerator_range enumerators() const { return enumerator_range(enumerator_begin(), enumerator_end()); @@ -3341,17 +3469,15 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Enum; } - - friend class ASTDeclReader; }; - /// RecordDecl - Represents a struct/union/class. For example: /// struct X; // Forward declaration, no "body". /// union Y { int A, B; }; // Has body with members A and B (FieldDecls). /// This decl will be marked invalid if *any* members are invalid. -/// class RecordDecl : public TagDecl { + friend class DeclContext; + // FIXME: This can be packed into the bitfields in Decl. /// HasFlexibleArrayMember - This is true if this struct ends with a flexible /// array member (e.g. int X[]) or if this union contains a struct that does. @@ -3375,7 +3501,6 @@ class RecordDecl : public TagDecl { /// methods/nested types we allow deserialization of just the fields /// when needed. mutable bool LoadedFieldsFromExternalStorage : 1; - friend class DeclContext; protected: RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, @@ -3458,6 +3583,7 @@ public: /// \brief Determine whether this record is a record for captured variables in /// CapturedStmt construct. bool isCapturedRecord() const; + /// \brief Mark the record as a record for captured variables in CapturedStmt /// construct. void setCapturedRecord(); @@ -3477,8 +3603,8 @@ public: // Iterator access to field members. The field iterator only visits // the non-static data members of this class, ignoring any static // data members, functions, constructors, destructors, etc. - typedef specific_decl_iterator<FieldDecl> field_iterator; - typedef llvm::iterator_range<specific_decl_iterator<FieldDecl>> field_range; + using field_iterator = specific_decl_iterator<FieldDecl>; + using field_range = llvm::iterator_range<specific_decl_iterator<FieldDecl>>; field_range fields() const { return field_range(field_begin(), field_end()); } field_iterator field_begin() const; @@ -3502,7 +3628,7 @@ public: return K >= firstRecord && K <= lastRecord; } - /// isMsStrust - Get whether or not this is an ms_struct which can + /// \brief Get whether or not this is an ms_struct which can /// be turned on with an attribute, pragma, or -mms-bitfields /// commandline option. bool isMsStruct(const ASTContext &C) const; @@ -3522,12 +3648,15 @@ private: }; class FileScopeAsmDecl : public Decl { - virtual void anchor(); StringLiteral *AsmString; SourceLocation RParenLoc; + FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring, SourceLocation StartL, SourceLocation EndL) : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {} + + virtual void anchor(); + public: static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC, StringLiteral *Str, SourceLocation AsmLoc, @@ -3553,7 +3682,6 @@ public: /// BlockDecl - This represents a block literal declaration, which is like an /// unnamed FunctionDecl. For example: /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } -/// class BlockDecl : public Decl, public DeclContext { public: /// A class which contains all the information about a particular @@ -3600,29 +3728,27 @@ private: bool CapturesCXXThis : 1; bool BlockMissingReturnType : 1; bool IsConversionFromLambda : 1; + /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. - ParmVarDecl **ParamInfo; - unsigned NumParams; + ParmVarDecl **ParamInfo = nullptr; + unsigned NumParams = 0; - Stmt *Body; - TypeSourceInfo *SignatureAsWritten; + Stmt *Body = nullptr; + TypeSourceInfo *SignatureAsWritten = nullptr; - const Capture *Captures; - unsigned NumCaptures; + const Capture *Captures = nullptr; + unsigned NumCaptures = 0; - unsigned ManglingNumber; - Decl *ManglingContextDecl; + unsigned ManglingNumber = 0; + Decl *ManglingContextDecl = nullptr; protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) - : Decl(Block, DC, CaretLoc), DeclContext(Block), - IsVariadic(false), CapturesCXXThis(false), - BlockMissingReturnType(true), IsConversionFromLambda(false), - ParamInfo(nullptr), NumParams(0), Body(nullptr), - SignatureAsWritten(nullptr), Captures(nullptr), NumCaptures(0), - ManglingNumber(0), ManglingContextDecl(nullptr) {} + : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), + CapturesCXXThis(false), BlockMissingReturnType(true), + IsConversionFromLambda(false) {} public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -3649,8 +3775,9 @@ public: } // Iterator access to formal parameters. - typedef MutableArrayRef<ParmVarDecl *>::iterator param_iterator; - typedef ArrayRef<ParmVarDecl *>::const_iterator param_const_iterator; + using param_iterator = MutableArrayRef<ParmVarDecl *>::iterator; + using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; + bool param_empty() const { return parameters().empty(); } param_iterator param_begin() { return parameters().begin(); } param_iterator param_end() { return parameters().end(); } @@ -3659,6 +3786,7 @@ public: size_t param_size() const { return parameters().size(); } unsigned getNumParams() const { return NumParams; } + const ParmVarDecl *getParamDecl(unsigned i) const { assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; @@ -3667,6 +3795,7 @@ public: assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; } + void setParams(ArrayRef<ParmVarDecl *> NewParamInfo); /// hasCaptures - True if this block (or its nested blocks) captures @@ -3677,7 +3806,7 @@ public: /// Does not include an entry for 'this'. unsigned getNumCaptures() const { return NumCaptures; } - typedef ArrayRef<Capture>::const_iterator capture_const_iterator; + using capture_const_iterator = ArrayRef<Capture>::const_iterator; ArrayRef<Capture> captures() const { return {Captures, NumCaptures}; } @@ -3699,6 +3828,7 @@ public: unsigned getBlockManglingNumber() const { return ManglingNumber; } + Decl *getBlockManglingContextDecl() const { return ManglingContextDecl; } @@ -3735,8 +3865,10 @@ protected: private: /// \brief The number of parameters to the outlined function. unsigned NumParams; + /// \brief The position of context parameter in list of parameters. unsigned ContextParam; + /// \brief The body of the outlined function. llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow; @@ -3751,6 +3883,10 @@ private: } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + static CapturedDecl *Create(ASTContext &C, DeclContext *DC, unsigned NumParams); static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID, @@ -3793,8 +3929,8 @@ public: } unsigned getContextParamPosition() const { return ContextParam; } - typedef ImplicitParamDecl *const *param_iterator; - typedef llvm::iterator_range<param_iterator> param_range; + using param_iterator = ImplicitParamDecl *const *; + using param_range = llvm::iterator_range<param_iterator>; /// \brief Retrieve an iterator pointing to the first parameter decl. param_iterator param_begin() const { return getParams(); } @@ -3810,10 +3946,6 @@ public: static CapturedDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<CapturedDecl *>(const_cast<DeclContext *>(DC)); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend TrailingObjects; }; /// \brief Describes a module import declaration, which makes the contents @@ -3828,6 +3960,11 @@ public: /// \#include/\#import directives. class ImportDecl final : public Decl, llvm::TrailingObjects<ImportDecl, SourceLocation> { + friend class ASTContext; + friend class ASTDeclReader; + friend class ASTReader; + friend TrailingObjects; + /// \brief The imported module, along with a bit that indicates whether /// we have source-location information for each identifier in the module /// name. @@ -3838,20 +3975,15 @@ class ImportDecl final : public Decl, /// \brief The next import in the list of imports local to the translation /// unit being parsed (not loaded from an AST file). - ImportDecl *NextLocalImport; + ImportDecl *NextLocalImport = nullptr; - friend class ASTReader; - friend class ASTDeclReader; - friend class ASTContext; - friend TrailingObjects; - ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef<SourceLocation> IdentifierLocs); ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc); - ImportDecl(EmptyShell Empty) : Decl(Import, Empty), NextLocalImport() { } + ImportDecl(EmptyShell Empty) : Decl(Import, Empty) {} public: /// \brief Create a new module import declaration. @@ -3893,15 +4025,16 @@ public: /// \endcode class ExportDecl final : public Decl, public DeclContext { virtual void anchor(); + private: + friend class ASTDeclReader; + /// \brief The source location for the right brace (if valid). SourceLocation RBraceLoc; ExportDecl(DeclContext *DC, SourceLocation ExportLoc) - : Decl(Export, DC, ExportLoc), DeclContext(Export), - RBraceLoc(SourceLocation()) { } - - friend class ASTDeclReader; + : Decl(Export, DC, ExportLoc), DeclContext(Export), + RBraceLoc(SourceLocation()) {} public: static ExportDecl *Create(ASTContext &C, DeclContext *DC, @@ -3936,9 +4069,9 @@ public: /// \brief Represents an empty-declaration. class EmptyDecl : public Decl { + EmptyDecl(DeclContext *DC, SourceLocation L) : Decl(Empty, DC, L) {} + virtual void anchor(); - EmptyDecl(DeclContext *DC, SourceLocation L) - : Decl(Empty, DC, L) { } public: static EmptyDecl *Create(ASTContext &C, DeclContext *DC, @@ -4015,6 +4148,6 @@ inline bool IsEnumDeclScoped(EnumDecl *ED) { return ED->isScoped(); } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECL_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h index 041f0fd484d45..f93c9f0b9aaa1 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h @@ -1,4 +1,4 @@ -//===-- DeclBase.h - Base Classes for representing declarations -*- C++ -*-===// +//===- DeclBase.h - Base Classes for representing declarations --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,33 +16,40 @@ #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <string> +#include <type_traits> +#include <utility> namespace clang { + +class ASTContext; class ASTMutationListener; -class BlockDecl; -class CXXRecordDecl; -class CompoundStmt; +class Attr; class DeclContext; -class DeclarationName; -class DependentDiagnostic; -class EnumDecl; -class ExportDecl; class ExternalSourceSymbolAttr; class FunctionDecl; class FunctionType; +class IdentifierInfo; enum Linkage : unsigned char; -class LinkageComputer; class LinkageSpecDecl; class Module; class NamedDecl; -class NamespaceDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCContainerDecl; @@ -53,23 +60,21 @@ class ObjCMethodDecl; class ObjCProtocolDecl; struct PrintingPolicy; class RecordDecl; +class SourceManager; class Stmt; class StoredDeclsMap; class TemplateDecl; class TranslationUnitDecl; class UsingDirectiveDecl; -} - -namespace clang { - /// \brief Captures the result of checking the availability of a - /// declaration. - enum AvailabilityResult { - AR_Available = 0, - AR_NotYetIntroduced, - AR_Deprecated, - AR_Unavailable - }; +/// \brief Captures the result of checking the availability of a +/// declaration. +enum AvailabilityResult { + AR_Available = 0, + AR_NotYetIntroduced, + AR_Deprecated, + AR_Unavailable +}; /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. @@ -94,7 +99,7 @@ public: /// \brief A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). - struct EmptyShell { }; + struct EmptyShell {}; /// IdentifierNamespace - The different namespaces in which /// declarations may appear. According to C99 6.2.3, there are @@ -208,15 +213,18 @@ public: enum class ModuleOwnershipKind : unsigned { /// This declaration is not owned by a module. Unowned, + /// This declaration has an owning module, but is globally visible /// (typically because its owning module is visible and we know that /// modules cannot later become hidden in this compilation). /// After serialization and deserialization, this will be converted /// to VisibleWhenImported. Visible, + /// This declaration has an owning module, and is visible when that /// module is imported. VisibleWhenImported, + /// This declaration has an owning module, but is only visible to /// lookups that occur within that module. ModulePrivate @@ -238,7 +246,6 @@ private: DeclContext *LexicalDC; }; - /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the Decl was declared. @@ -254,12 +261,14 @@ private: /// // LexicalDC == global namespace llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx; - inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); } - inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); } - inline MultipleDC *getMultipleDC() const { + bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); } + bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); } + + MultipleDC *getMultipleDC() const { return DeclCtx.get<MultipleDC*>(); } - inline DeclContext *getSemanticDC() const { + + DeclContext *getSemanticDC() const { return DeclCtx.get<DeclContext*>(); } @@ -298,10 +307,16 @@ private: static bool StatisticsEnabled; protected: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + friend class CXXClassMemberWrapper; + friend class LinkageComputer; + template<typename decl_type> friend class Redeclarable; + /// Access - Used by C++ decls for the access specifier. // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum unsigned Access : 2; - friend class CXXClassMemberWrapper; /// \brief Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; @@ -313,13 +328,6 @@ protected: /// Otherwise, it is the linkage + 1. mutable unsigned CacheValidAndLinkage : 3; - friend class ASTDeclWriter; - friend class ASTDeclReader; - friend class ASTReader; - friend class LinkageComputer; - - template<typename decl_type> friend class Redeclarable; - /// \brief Allocate memory for a deserialized declaration. /// /// This routine must be used to allocate memory for any declaration that is @@ -357,7 +365,7 @@ private: protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)), - DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), + DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), @@ -366,9 +374,9 @@ protected: } Decl(Kind DK, EmptyShell Empty) - : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false), - Implicit(false), Used(false), Referenced(false), - TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), + : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), + Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), + Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); @@ -392,14 +400,15 @@ protected: } public: - /// \brief Source range that this declaration covers. virtual SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocation(), getLocation()); } + SourceLocation getLocStart() const LLVM_READONLY { return getSourceRange().getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getSourceRange().getEnd(); } @@ -460,12 +469,15 @@ public: } bool hasAttrs() const { return HasAttrs; } + void setAttrs(const AttrVec& Attrs) { return setAttrsImpl(Attrs, getASTContext()); } + AttrVec &getAttrs() { return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs()); } + const AttrVec &getAttrs() const; void dropAttrs(); @@ -476,8 +488,8 @@ public: setAttrs(AttrVec(1, A)); } - typedef AttrVec::const_iterator attr_iterator; - typedef llvm::iterator_range<attr_iterator> attr_range; + using attr_iterator = AttrVec::const_iterator; + using attr_range = llvm::iterator_range<attr_iterator>; attr_range attrs() const { return attr_range(attr_begin(), attr_end()); @@ -510,6 +522,7 @@ public: specific_attr_iterator<T> specific_attr_begin() const { return specific_attr_iterator<T>(attr_begin()); } + template <typename T> specific_attr_iterator<T> specific_attr_end() const { return specific_attr_iterator<T>(attr_end()); @@ -518,6 +531,7 @@ public: template<typename T> T *getAttr() const { return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : nullptr; } + template<typename T> bool hasAttr() const { return hasAttrs() && hasSpecificAttr<T>(getAttrs()); } @@ -616,7 +630,6 @@ protected: } public: - /// \brief Determine the availability of the given declaration. /// /// This routine will determine the most restrictive availability of @@ -698,6 +711,7 @@ public: private: Module *getOwningModuleSlow() const; + protected: bool hasLocalOwningModuleStorage() const; @@ -733,11 +747,18 @@ public: return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; } - /// Get the module that owns this declaration. + /// Get the module that owns this declaration (for visibility purposes). Module *getOwningModule() const { return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } + /// Get the module that owns this declaration for linkage purposes. + /// There only ever is such a module under the C++ Modules TS. + /// + /// \param IgnoreLinkage Ignore the linkage of the entity; assume that + /// all declarations in a global module fragment are unowned. + Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; + /// \brief Determine whether this declaration might be hidden from name /// lookup. Note that the declaration might be visible even if this returns /// \c false, if the owning module is visible within the query context. @@ -770,14 +791,17 @@ public: unsigned getIdentifierNamespace() const { return IdentifierNamespace; } + bool isInIdentifierNamespace(unsigned NS) const { return getIdentifierNamespace() & NS; } + static unsigned getIdentifierNamespaceForKind(Kind DK); bool hasTagIdentifierNamespace() const { return isTagIdentifierNamespace(getIdentifierNamespace()); } + static bool isTagIdentifierNamespace(unsigned NS) { // TagDecls have Tag and Type set and may also have TagFriend. return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); @@ -865,18 +889,18 @@ public: /// \brief Iterates through all the redeclarations of the same decl. class redecl_iterator { /// Current - The current declaration. - Decl *Current; + Decl *Current = nullptr; Decl *Starter; public: - typedef Decl *value_type; - typedef const value_type &reference; - typedef const value_type *pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = Decl *; + using reference = const value_type &; + using pointer = const value_type *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - redecl_iterator() : Current(nullptr) { } - explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { } + redecl_iterator() = default; + explicit redecl_iterator(Decl *C) : Current(C), Starter(C) {} reference operator*() const { return Current; } value_type operator->() const { return Current; } @@ -899,12 +923,13 @@ public: friend bool operator==(redecl_iterator x, redecl_iterator y) { return x.Current == y.Current; } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { return x.Current != y.Current; } }; - typedef llvm::iterator_range<redecl_iterator> redecl_range; + using redecl_range = llvm::iterator_range<redecl_iterator>; /// \brief Returns an iterator range for all the redeclarations of the same /// decl. It will iterate at least once (when this decl is the only one). @@ -915,6 +940,7 @@ public: redecl_iterator redecls_begin() const { return redecl_iterator(const_cast<Decl *>(this)); } + redecl_iterator redecls_end() const { return redecl_iterator(); } /// \brief Retrieve the previous declaration that declares the same entity @@ -1002,13 +1028,15 @@ public: /// declaration, but in the semantic context of the enclosing namespace /// scope. void setLocalExternDecl() { - assert((IdentifierNamespace == IDNS_Ordinary || - IdentifierNamespace == IDNS_OrdinaryFriend) && - "namespace is not ordinary"); - Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~IDNS_Ordinary; + // It's OK for the declaration to still have the "invisible friend" flag or + // the "conflicts with tag declarations in this scope" flag for the outer + // scope. + assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 && + "namespace is not ordinary"); + IdentifierNamespace |= IDNS_LocalExtern; if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) IdentifierNamespace |= IDNS_Ordinary; @@ -1094,10 +1122,13 @@ public: static void printGroup(Decl** Begin, unsigned NumDecls, raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); + // Debuggers don't usually respect default arguments. void dump() const; + // Same as dump(), but forces color printing. void dumpColor() const; + void dump(raw_ostream &Out, bool Deserialize = false) const; /// \brief Looks through the Decl's underlying type to extract a FunctionType @@ -1132,10 +1163,11 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { SourceLocation Loc; SourceManager &SM; const char *Message; + public: PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) - : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} + : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} void print(raw_ostream &OS) const override; }; @@ -1144,30 +1176,35 @@ public: /// single result (with no stable storage) or a collection of results (with /// stable storage provided by the lookup table). class DeclContextLookupResult { - typedef ArrayRef<NamedDecl *> ResultTy; + using ResultTy = ArrayRef<NamedDecl *>; + ResultTy Result; + // If there is only one lookup result, it would be invalidated by // reallocations of the name table, so store it separately. - NamedDecl *Single; + NamedDecl *Single = nullptr; static NamedDecl *const SingleElementDummyList; public: - DeclContextLookupResult() : Result(), Single() {} + DeclContextLookupResult() = default; DeclContextLookupResult(ArrayRef<NamedDecl *> Result) - : Result(Result), Single() {} + : Result(Result) {} DeclContextLookupResult(NamedDecl *Single) : Result(SingleElementDummyList), Single(Single) {} class iterator; - typedef llvm::iterator_adaptor_base<iterator, ResultTy::iterator, - std::random_access_iterator_tag, - NamedDecl *const> IteratorBase; + + using IteratorBase = + llvm::iterator_adaptor_base<iterator, ResultTy::iterator, + std::random_access_iterator_tag, + NamedDecl *const>; + class iterator : public IteratorBase { value_type SingleElement; public: - iterator() : IteratorBase(), SingleElement() {} + iterator() = default; explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} @@ -1175,9 +1212,10 @@ public: return SingleElement ? SingleElement : IteratorBase::operator*(); } }; - typedef iterator const_iterator; - typedef iterator::pointer pointer; - typedef iterator::reference reference; + + using const_iterator = iterator; + using pointer = iterator::pointer; + using reference = iterator::reference; iterator begin() const { return iterator(Result.begin(), Single); } iterator end() const { return iterator(Result.end(), Single); } @@ -1211,7 +1249,6 @@ public: /// ExportDecl /// BlockDecl /// OMPDeclareReductionDecl -/// class DeclContext { /// DeclKind - This indicates which class this is. unsigned DeclKind : 8; @@ -1251,22 +1288,22 @@ class DeclContext { /// contains an entry for a DeclarationName (and we haven't lazily /// omitted anything), then it contains all relevant entries for that /// name (modulo the hasExternalDecls() flag). - mutable StoredDeclsMap *LookupPtr; + mutable StoredDeclsMap *LookupPtr = nullptr; protected: + friend class ASTDeclReader; + friend class ASTWriter; + friend class ExternalASTSource; + /// FirstDecl - The first declaration stored within this declaration /// context. - mutable Decl *FirstDecl; + mutable Decl *FirstDecl = nullptr; /// LastDecl - The last declaration stored within this declaration /// context. FIXME: We could probably cache this value somewhere /// outside of the DeclContext, to reduce the size of DeclContext by /// another pointer. - mutable Decl *LastDecl; - - friend class ExternalASTSource; - friend class ASTDeclReader; - friend class ASTWriter; + mutable Decl *LastDecl = nullptr; /// \brief Build up a chain of declarations. /// @@ -1279,8 +1316,7 @@ protected: ExternalVisibleStorage(false), NeedToReconcileExternalVisibleStorage(false), HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false), - UseQualifiedLookup(false), - LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {} + UseQualifiedLookup(false) {} public: ~DeclContext(); @@ -1288,6 +1324,7 @@ public: Decl::Kind getDeclKind() const { return static_cast<Decl::Kind>(DeclKind); } + const char *getDeclKindName() const; /// getParent - Returns the containing DeclContext. @@ -1495,19 +1532,20 @@ public: /// within this context. class decl_iterator { /// Current - The current declaration. - Decl *Current; + Decl *Current = nullptr; public: - typedef Decl *value_type; - typedef const value_type &reference; - typedef const value_type *pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = Decl *; + using reference = const value_type &; + using pointer = const value_type *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - decl_iterator() : Current(nullptr) { } - explicit decl_iterator(Decl *C) : Current(C) { } + decl_iterator() = default; + explicit decl_iterator(Decl *C) : Current(C) {} reference operator*() const { return Current; } + // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return Current; } @@ -1525,12 +1563,13 @@ public: friend bool operator==(decl_iterator x, decl_iterator y) { return x.Current == y.Current; } + friend bool operator!=(decl_iterator x, decl_iterator y) { return x.Current != y.Current; } }; - typedef llvm::iterator_range<decl_iterator> decl_range; + using decl_range = llvm::iterator_range<decl_iterator>; /// decls_begin/decls_end - Iterate over the declarations stored in /// this context. @@ -1569,16 +1608,16 @@ public: } public: - typedef SpecificDecl *value_type; - // TODO: Add reference and pointer typedefs (with some appropriate proxy - // type) if we ever have a need for them. - typedef void reference; - typedef void pointer; - typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type - difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = SpecificDecl *; + // TODO: Add reference and pointer types (with some appropriate proxy type) + // if we ever have a need for them. + using reference = void; + using pointer = void; + using difference_type = + std::iterator_traits<DeclContext::decl_iterator>::difference_type; + using iterator_category = std::forward_iterator_tag; - specific_decl_iterator() : Current() { } + specific_decl_iterator() = default; /// specific_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, @@ -1593,6 +1632,7 @@ public: } value_type operator*() const { return cast<SpecificDecl>(*Current); } + // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return **this; } @@ -1646,16 +1686,16 @@ public: } public: - typedef SpecificDecl *value_type; - // TODO: Add reference and pointer typedefs (with some appropriate proxy - // type) if we ever have a need for them. - typedef void reference; - typedef void pointer; - typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type - difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = SpecificDecl *; + // TODO: Add reference and pointer types (with some appropriate proxy type) + // if we ever have a need for them. + using reference = void; + using pointer = void; + using difference_type = + std::iterator_traits<DeclContext::decl_iterator>::difference_type; + using iterator_category = std::forward_iterator_tag; - filtered_decl_iterator() : Current() { } + filtered_decl_iterator() = default; /// filtered_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, @@ -1733,8 +1773,8 @@ public: /// @brief Checks whether a declaration is in this context. bool containsDecl(Decl *D) const; - typedef DeclContextLookupResult lookup_result; - typedef lookup_result::iterator lookup_iterator; + using lookup_result = DeclContextLookupResult; + using lookup_iterator = lookup_result::iterator; /// lookup - Find the declarations (if any) with the given Name in /// this context. Returns a range of iterators that contains all of @@ -1780,7 +1820,7 @@ public: /// of looking up every possible name. class all_lookups_iterator; - typedef llvm::iterator_range<all_lookups_iterator> lookups_range; + using lookups_range = llvm::iterator_range<all_lookups_iterator>; lookups_range lookups() const; lookups_range noload_lookups() const; @@ -1796,21 +1836,26 @@ public: all_lookups_iterator noload_lookups_end() const; struct udir_iterator; - typedef llvm::iterator_adaptor_base<udir_iterator, lookup_iterator, - std::random_access_iterator_tag, - UsingDirectiveDecl *> udir_iterator_base; + + using udir_iterator_base = + llvm::iterator_adaptor_base<udir_iterator, lookup_iterator, + std::random_access_iterator_tag, + UsingDirectiveDecl *>; + struct udir_iterator : udir_iterator_base { udir_iterator(lookup_iterator I) : udir_iterator_base(I) {} + UsingDirectiveDecl *operator*() const; }; - typedef llvm::iterator_range<udir_iterator> udir_range; + using udir_range = llvm::iterator_range<udir_iterator>; udir_range using_directives() const; // These are all defined in DependentDiagnostic.h. class ddiag_iterator; - typedef llvm::iterator_range<DeclContext::ddiag_iterator> ddiag_range; + + using ddiag_range = llvm::iterator_range<DeclContext::ddiag_iterator>; inline ddiag_range ddiags() const; @@ -1883,6 +1928,8 @@ public: bool Deserialize = false) const; private: + friend class DependentDiagnostic; + void reconcileExternalVisibleStorage() const; bool LoadLexicalDeclsFromExternalStorage() const; @@ -1894,7 +1941,6 @@ private: /// use of addDeclInternal(). void makeDeclVisibleInContextInternal(NamedDecl *D); - friend class DependentDiagnostic; StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; void buildLookupImpl(DeclContext *DCtx, bool Internal); @@ -1933,8 +1979,7 @@ struct cast_convert_decl_context<ToTy, true> { } }; - -} // end clang. +} // namespace clang namespace llvm { @@ -1954,12 +1999,14 @@ struct cast_convert_val<ToTy, return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); } }; + template<class ToTy> struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> { static ToTy &doit(::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); } }; + template<class ToTy> struct cast_convert_val<ToTy, const ::clang::DeclContext*, const ::clang::DeclContext*> { @@ -1967,6 +2014,7 @@ struct cast_convert_val<ToTy, return ::clang::cast_convert_decl_context<ToTy>::doit(Val); } }; + template<class ToTy> struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> { static ToTy *doit(::clang::DeclContext *Val) { @@ -2003,6 +2051,6 @@ struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { } }; -} // end namespace llvm +} // namespace llvm -#endif +#endif // LLVM_CLANG_AST_DECLBASE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h index 2f735c5506c46..88dc9a6559172 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h @@ -1,4 +1,4 @@ -//===-- DeclCXX.h - Classes for representing C++ declarations -*- C++ -*-=====// +//===- DeclCXX.h - Classes for representing C++ declarations --*- C++ -*-=====// // // The LLVM Compiler Infrastructure // @@ -6,11 +6,11 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the C++ Decl subclasses, other than those for templates /// (found in DeclTemplate.h) and friends (in DeclFriend.h). -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLCXX_H @@ -20,29 +20,56 @@ #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <memory> +#include <vector> namespace clang { class ClassTemplateDecl; -class ClassTemplateSpecializationDecl; class ConstructorUsingShadowDecl; class CXXBasePath; class CXXBasePaths; class CXXConstructorDecl; -class CXXConversionDecl; class CXXDestructorDecl; -class CXXMethodDecl; -class CXXRecordDecl; -class CXXMemberLookupCriteria; class CXXFinalOverriderMap; class CXXIndirectPrimaryBaseSet; +class CXXMethodDecl; +class DiagnosticBuilder; class FriendDecl; -class LambdaExpr; +class FunctionTemplateDecl; +class IdentifierInfo; +class MemberSpecializationInfo; +class TemplateDecl; +class TemplateParameterList; class UsingDecl; /// \brief Represents any kind of function declaration, whether it is a @@ -50,10 +77,10 @@ class UsingDecl; class AnyFunctionDecl { NamedDecl *Function; - AnyFunctionDecl(NamedDecl *ND) : Function(ND) { } + AnyFunctionDecl(NamedDecl *ND) : Function(ND) {} public: - AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { } + AnyFunctionDecl(FunctionDecl *FD) : Function(FD) {} AnyFunctionDecl(FunctionTemplateDecl *FTD); /// \brief Implicily converts any function or function template into a @@ -68,17 +95,18 @@ public: } }; -} // end namespace clang +} // namespace clang namespace llvm { + // Provide PointerLikeTypeTraits for non-cvr pointers. template<> - class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { - public: - static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) { + struct PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { + static void *getAsVoidPointer(::clang::AnyFunctionDecl F) { return F.get(); } - static inline ::clang::AnyFunctionDecl getFromVoidPointer(void *P) { + + static ::clang::AnyFunctionDecl getFromVoidPointer(void *P) { return ::clang::AnyFunctionDecl::getFromNamedDecl( static_cast< ::clang::NamedDecl*>(P)); } @@ -86,7 +114,7 @@ namespace llvm { enum { NumLowBitsAvailable = 2 }; }; -} // end namespace llvm +} // namespace llvm namespace clang { @@ -101,7 +129,6 @@ namespace clang { /// Also note that this class has nothing to do with so-called /// "access declarations" (C++98 11.3 [class.access.dcl]). class AccessSpecDecl : public Decl { - virtual void anchor(); /// \brief The location of the ':'. SourceLocation ColonLoc; @@ -110,16 +137,21 @@ class AccessSpecDecl : public Decl { : Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) { setAccess(AS); } - AccessSpecDecl(EmptyShell Empty) - : Decl(AccessSpec, Empty) { } + + AccessSpecDecl(EmptyShell Empty) : Decl(AccessSpec, Empty) {} + + virtual void anchor(); + public: /// \brief The location of the access specifier. SourceLocation getAccessSpecifierLoc() const { return getLocation(); } + /// \brief Sets the location of the access specifier. void setAccessSpecifierLoc(SourceLocation ASLoc) { setLocation(ASLoc); } /// \brief The location of the colon following the access specifier. SourceLocation getColonLoc() const { return ColonLoc; } + /// \brief Sets the location of the colon. void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; } @@ -132,6 +164,7 @@ public: SourceLocation ColonLoc) { return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); } + static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); // Implement isa/cast/dyncast/etc. @@ -191,12 +224,11 @@ class CXXBaseSpecifier { TypeSourceInfo *BaseTypeInfo; public: - CXXBaseSpecifier() { } - + CXXBaseSpecifier() = default; CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), - Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { } + Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) {} /// \brief Retrieves the source range that contains the entire base specifier. SourceRange getSourceRange() const LLVM_READONLY { return Range; } @@ -265,7 +297,16 @@ public: /// \brief Represents a C++ struct/union/class. class CXXRecordDecl : public RecordDecl { + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTNodeImporter; + friend class ASTReader; + friend class ASTRecordWriter; + friend class ASTWriter; + friend class DeclContext; + friend class LambdaExpr; + friend void FunctionDecl::setPure(bool); friend void TagDecl::startDefinition(); /// Values used in DefinitionData fields to represent special members. @@ -280,8 +321,6 @@ class CXXRecordDecl : public RecordDecl { }; struct DefinitionData { - DefinitionData(CXXRecordDecl *D); - /// \brief True if this class has any user-declared constructors. unsigned UserDeclaredConstructor : 1; @@ -475,13 +514,13 @@ class CXXRecordDecl : public RecordDecl { unsigned HasODRHash : 1; /// \brief A hash of parts of the class to help in ODR checking. - unsigned ODRHash; + unsigned ODRHash = 0; /// \brief The number of base class specifiers in Bases. - unsigned NumBases; + unsigned NumBases = 0; /// \brief The number of virtual base class specifiers in VBases. - unsigned NumVBases; + unsigned NumVBases = 0; /// \brief Base classes of this class. /// @@ -513,6 +552,8 @@ class CXXRecordDecl : public RecordDecl { /// This is actually currently stored in reverse order. LazyDeclPtr FirstFriend; + DefinitionData(CXXRecordDecl *D); + /// \brief Retrieve the set of direct base classes. CXXBaseSpecifier *getBases() const { if (!Bases.isOffset()) @@ -530,6 +571,7 @@ class CXXRecordDecl : public RecordDecl { ArrayRef<CXXBaseSpecifier> bases() const { return llvm::makeArrayRef(getBases(), NumBases); } + ArrayRef<CXXBaseSpecifier> vbases() const { return llvm::makeArrayRef(getVBases(), NumVBases); } @@ -543,22 +585,7 @@ class CXXRecordDecl : public RecordDecl { /// \brief Describes a C++ closure type (generated by a lambda expression). struct LambdaDefinitionData : public DefinitionData { - typedef LambdaCapture Capture; - - LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, - bool Dependent, bool IsGeneric, - LambdaCaptureDefault CaptureDefault) - : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric), - CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0), - ManglingNumber(0), ContextDecl(nullptr), Captures(nullptr), - MethodTyInfo(Info) { - IsLambda = true; - - // C++1z [expr.prim.lambda]p4: - // This class type is not an aggregate type. - Aggregate = false; - PlainOldData = false; - } + using Capture = LambdaCapture; /// \brief Whether this lambda is known to be dependent, even if its /// context isn't dependent. @@ -584,7 +611,7 @@ class CXXRecordDecl : public RecordDecl { /// \brief The number used to indicate this lambda expression for name /// mangling in the Itanium C++ ABI. - unsigned ManglingNumber; + unsigned ManglingNumber = 0; /// \brief The declaration that provides context for this lambda, if the /// actual DeclContext does not suffice. This is used for lambdas that @@ -594,11 +621,24 @@ class CXXRecordDecl : public RecordDecl { /// \brief The list of captures, both explicit and implicit, for this /// lambda. - Capture *Captures; + Capture *Captures = nullptr; /// \brief The type of the call method. TypeSourceInfo *MethodTyInfo; - + + LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, + bool Dependent, bool IsGeneric, + LambdaCaptureDefault CaptureDefault) + : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric), + CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0), + MethodTyInfo(Info) { + IsLambda = true; + + // C++1z [expr.prim.lambda]p4: + // This class type is not an aggregate type. + Aggregate = false; + PlainOldData = false; + } }; struct DefinitionData *dataPtr() const { @@ -630,11 +670,8 @@ class CXXRecordDecl : public RecordDecl { /// classes of class template specializations, this will be the /// MemberSpecializationInfo referring to the member class that was /// instantiated or specialized. - llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> - TemplateOrInstantiation; - - friend class DeclContext; - friend class LambdaExpr; + llvm::PointerUnion<ClassTemplateDecl *, MemberSpecializationInfo *> + TemplateOrInstantiation; /// \brief Called from setBases and addedMember to notify the class that a /// direct or virtual base class or a member of class type has been added. @@ -648,9 +685,6 @@ class CXXRecordDecl : public RecordDecl { void addedMember(Decl *D); void markedVirtualFunctionPure(); - friend void FunctionDecl::setPure(bool); - - friend class ASTNodeImporter; /// \brief Get the head of our list of friend declarations, possibly /// deserializing the friends from an external AST source. @@ -663,14 +697,15 @@ protected: public: /// \brief Iterator that traverses the base classes of a class. - typedef CXXBaseSpecifier* base_class_iterator; + using base_class_iterator = CXXBaseSpecifier *; /// \brief Iterator that traverses the base classes of a class. - typedef const CXXBaseSpecifier* base_class_const_iterator; + using base_class_const_iterator = const CXXBaseSpecifier *; CXXRecordDecl *getCanonicalDecl() override { return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); } + const CXXRecordDecl *getCanonicalDecl() const { return const_cast<CXXRecordDecl*>(this)->getCanonicalDecl(); } @@ -679,6 +714,7 @@ public: return cast_or_null<CXXRecordDecl>( static_cast<RecordDecl *>(this)->getPreviousDecl()); } + const CXXRecordDecl *getPreviousDecl() const { return const_cast<CXXRecordDecl*>(this)->getPreviousDecl(); } @@ -730,9 +766,9 @@ public: /// \brief Retrieves the number of base classes of this class. unsigned getNumBases() const { return data().NumBases; } - typedef llvm::iterator_range<base_class_iterator> base_class_range; - typedef llvm::iterator_range<base_class_const_iterator> - base_class_const_range; + using base_class_range = llvm::iterator_range<base_class_iterator>; + using base_class_const_range = + llvm::iterator_range<base_class_const_iterator>; base_class_range bases() { return base_class_range(bases_begin(), bases_end()); @@ -772,9 +808,9 @@ public: /// Iterator access to method members. The method iterator visits /// all method members of the class, including non-instance methods, /// special methods, etc. - typedef specific_decl_iterator<CXXMethodDecl> method_iterator; - typedef llvm::iterator_range<specific_decl_iterator<CXXMethodDecl>> - method_range; + using method_iterator = specific_decl_iterator<CXXMethodDecl>; + using method_range = + llvm::iterator_range<specific_decl_iterator<CXXMethodDecl>>; method_range methods() const { return method_range(method_begin(), method_end()); @@ -785,21 +821,23 @@ public: method_iterator method_begin() const { return method_iterator(decls_begin()); } + /// \brief Method past-the-end iterator. method_iterator method_end() const { return method_iterator(decls_end()); } /// Iterator access to constructor members. - typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator; - typedef llvm::iterator_range<specific_decl_iterator<CXXConstructorDecl>> - ctor_range; + using ctor_iterator = specific_decl_iterator<CXXConstructorDecl>; + using ctor_range = + llvm::iterator_range<specific_decl_iterator<CXXConstructorDecl>>; ctor_range ctors() const { return ctor_range(ctor_begin(), ctor_end()); } ctor_iterator ctor_begin() const { return ctor_iterator(decls_begin()); } + ctor_iterator ctor_end() const { return ctor_iterator(decls_end()); } @@ -807,7 +845,7 @@ public: /// An iterator over friend declarations. All of these are defined /// in DeclFriend.h. class friend_iterator; - typedef llvm::iterator_range<friend_iterator> friend_range; + using friend_range = llvm::iterator_range<friend_iterator>; friend_range friends() const; friend_iterator friend_begin() const; @@ -839,7 +877,10 @@ public: /// \brief \c true if a defaulted destructor for this class would be deleted. bool defaultedDestructorIsDeleted() const { - return !data().DefaultedDestructorIsDeleted; + assert((!needsOverloadResolutionForDestructor() || + (data().DeclaredSpecialMembers & SMF_Destructor)) && + "this property has not yet been computed by Sema"); + return data().DefaultedDestructorIsDeleted; } /// \brief \c true if we know for sure that this class has a single, @@ -986,6 +1027,15 @@ public: data().DefaultedMoveConstructorIsDeleted = true; } + /// \brief Set that we attempted to declare an implicit destructor, + /// but overload resolution failed so we deleted it. + void setImplicitDestructorIsDeleted() { + assert((data().DefaultedDestructorIsDeleted || + needsOverloadResolutionForDestructor()) && + "destructor should not be deleted"); + data().DefaultedDestructorIsDeleted = true; + } + /// \brief Determine whether this class should get an implicit move /// constructor or if any existing special member function inhibits this. bool needsImplicitMoveConstructor() const { @@ -1144,24 +1194,28 @@ public: void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, FieldDecl *&ThisCapture) const; - typedef const LambdaCapture *capture_const_iterator; - typedef llvm::iterator_range<capture_const_iterator> capture_const_range; + using capture_const_iterator = const LambdaCapture *; + using capture_const_range = llvm::iterator_range<capture_const_iterator>; capture_const_range captures() const { return capture_const_range(captures_begin(), captures_end()); } + capture_const_iterator captures_begin() const { return isLambda() ? getLambdaData().Captures : nullptr; } + capture_const_iterator captures_end() const { return isLambda() ? captures_begin() + getLambdaData().NumCaptures : nullptr; } - typedef UnresolvedSetIterator conversion_iterator; + using conversion_iterator = UnresolvedSetIterator; + conversion_iterator conversion_begin() const { return data().Conversions.get(getASTContext()).begin(); } + conversion_iterator conversion_end() const { return data().Conversions.get(getASTContext()).end(); } @@ -1433,10 +1487,10 @@ public: /// We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by /// treating types with trivial default constructors as literal types. /// - /// Only in C++1z and beyond, are lambdas literal types. + /// Only in C++17 and beyond, are lambdas literal types. bool isLiteral() const { return hasTrivialDestructor() && - (!isLambda() || getASTContext().getLangOpts().CPlusPlus1z) && + (!isLambda() || getASTContext().getLangOpts().CPlusPlus17) && !hasNonLiteralTypeFieldsOrBases() && (isAggregate() || isLambda() || hasConstexprNonCopyMoveConstructor() || @@ -1585,8 +1639,8 @@ public: /// \param BaseDefinition the definition of the base class /// /// \returns true if this base matched the search criteria - typedef llvm::function_ref<bool(const CXXRecordDecl *BaseDefinition)> - ForallBasesCallback; + using ForallBasesCallback = + llvm::function_ref<bool(const CXXRecordDecl *BaseDefinition)>; /// \brief Determines if the given callback holds for all the direct /// or indirect base classes of this type. @@ -1614,8 +1668,9 @@ public: /// base named by the \p Specifier. /// /// \returns true if this base matched the search criteria, false otherwise. - typedef llvm::function_ref<bool(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path)> BaseMatchesCallback; + using BaseMatchesCallback = + llvm::function_ref<bool(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path)>; /// \brief Look for entities within the base classes of this C++ class, /// transitively searching all base class subobjects. @@ -1794,6 +1849,7 @@ public: /// \brief Returns the inheritance model used for this record. MSInheritanceAttr::Spelling getMSInheritanceModel() const; + /// \brief Calculate what the inheritance model would be for this class. MSInheritanceAttr::Spelling calculateInheritanceModel() const; @@ -1832,16 +1888,14 @@ public: return getLambdaData().MethodTyInfo; } + // \brief Determine whether this type is an Interface Like type for + // __interface inheritence purposes. + bool isInterfaceLike() const; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstCXXRecord && K <= lastCXXRecord; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend class ASTRecordWriter; - friend class ASTReader; - friend class ASTWriter; }; /// \brief Represents a C++ deduction guide declaration. @@ -1856,6 +1910,7 @@ public: /// the constructors of \c A. class CXXDeductionGuideDecl : public FunctionDecl { void anchor() override; + private: CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit, const DeclarationNameInfo &NameInfo, @@ -1869,6 +1924,9 @@ private: } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit, const DeclarationNameInfo &NameInfo, @@ -1888,12 +1946,15 @@ public: return getDeclName().getCXXDeductionGuideTemplate(); } + void setIsCopyDeductionCandidate() { + IsCopyDeductionCandidate = true; + } + + bool isCopyDeductionCandidate() const { return IsCopyDeductionCandidate; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXDeductionGuide; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a static or instance method of a struct/union/class. @@ -1902,6 +1963,7 @@ public: /// non-static) member functions, whether virtual or not. class CXXMethodDecl : public FunctionDecl { void anchor() override; + protected: CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, @@ -1953,7 +2015,7 @@ public: if (CD->isVirtualAsWritten() || CD->isPure()) return true; - return (CD->begin_overridden_methods() != CD->end_overridden_methods()); + return CD->size_overridden_methods() != 0; } /// If it's possible to devirtualize a call to this method, return the called @@ -1999,18 +2061,23 @@ public: /// True if this method is user-declared and was not /// deleted or defaulted on its first declaration. bool isUserProvided() const { - return !(isDeleted() || getCanonicalDecl()->isDefaulted()); + auto *DeclAsWritten = this; + if (auto *Pattern = getTemplateInstantiationPattern()) + DeclAsWritten = cast<CXXMethodDecl>(Pattern); + return !(DeclAsWritten->isDeleted() || + DeclAsWritten->getCanonicalDecl()->isDefaulted()); } - /// void addOverriddenMethod(const CXXMethodDecl *MD); - typedef const CXXMethodDecl *const* method_iterator; + using method_iterator = const CXXMethodDecl *const *; method_iterator begin_overridden_methods() const; method_iterator end_overridden_methods() const; unsigned size_overridden_methods() const; - typedef ASTContext::overridden_method_range overridden_method_range; + + using overridden_method_range= ASTContext::overridden_method_range; + overridden_method_range overridden_methods() const; /// Returns the parent of this method declaration, which @@ -2240,6 +2307,7 @@ public: return Initializee.get<FieldDecl*>(); return nullptr; } + FieldDecl *getAnyMember() const { if (isMemberInitializer()) return Initializee.get<FieldDecl*>(); @@ -2301,11 +2369,11 @@ public: /// Description of a constructor that was inherited from a base class. class InheritedConstructor { - ConstructorUsingShadowDecl *Shadow; - CXXConstructorDecl *BaseCtor; + ConstructorUsingShadowDecl *Shadow = nullptr; + CXXConstructorDecl *BaseCtor = nullptr; public: - InheritedConstructor() : Shadow(), BaseCtor() {} + InheritedConstructor() = default; InheritedConstructor(ConstructorUsingShadowDecl *Shadow, CXXConstructorDecl *BaseCtor) : Shadow(Shadow), BaseCtor(BaseCtor) {} @@ -2329,8 +2397,6 @@ public: class CXXConstructorDecl final : public CXXMethodDecl, private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> { - void anchor() override; - /// \name Support for base and member initializers. /// \{ /// \brief The arguments used to initialize the base or member. @@ -2350,15 +2416,20 @@ class CXXConstructorDecl final InheritedConstructor Inherited) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, SC_None, isInline, isConstexpr, SourceLocation()), - CtorInitializers(nullptr), NumCtorInitializers(0), - IsInheritingConstructor((bool)Inherited) { + NumCtorInitializers(0), IsInheritingConstructor((bool)Inherited) { setImplicit(isImplicitlyDeclared); if (Inherited) *getTrailingObjects<InheritedConstructor>() = Inherited; IsExplicitSpecified = isExplicitSpecified; } + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID, bool InheritsConstructor); static CXXConstructorDecl * @@ -2369,13 +2440,13 @@ public: InheritedConstructor Inherited = InheritedConstructor()); /// \brief Iterates through the member/base initializer list. - typedef CXXCtorInitializer **init_iterator; + using init_iterator = CXXCtorInitializer **; /// \brief Iterates through the member/base initializer list. - typedef CXXCtorInitializer *const *init_const_iterator; + using init_const_iterator = CXXCtorInitializer *const *; - typedef llvm::iterator_range<init_iterator> init_range; - typedef llvm::iterator_range<init_const_iterator> init_const_range; + using init_range = llvm::iterator_range<init_iterator>; + using init_const_range = llvm::iterator_range<init_const_iterator>; init_range inits() { return init_range(init_begin(), init_end()); } init_const_range inits() const { @@ -2387,6 +2458,7 @@ public: const auto *ConstThis = this; return const_cast<init_iterator>(ConstThis->init_begin()); } + /// \brief Retrieve an iterator to the first initializer. init_const_iterator init_begin() const; @@ -2394,14 +2466,15 @@ public: init_iterator init_end() { return init_begin() + NumCtorInitializers; } + /// \brief Retrieve an iterator past the last initializer. init_const_iterator init_end() const { return init_begin() + NumCtorInitializers; } - typedef std::reverse_iterator<init_iterator> init_reverse_iterator; - typedef std::reverse_iterator<init_const_iterator> - init_const_reverse_iterator; + using init_reverse_iterator = std::reverse_iterator<init_iterator>; + using init_const_reverse_iterator = + std::reverse_iterator<init_const_iterator>; init_reverse_iterator init_rbegin() { return init_reverse_iterator(init_end()); @@ -2532,10 +2605,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXConstructor; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend TrailingObjects; }; /// \brief Represents a C++ destructor within a class. @@ -2549,20 +2618,26 @@ public: /// }; /// \endcode class CXXDestructorDecl : public CXXMethodDecl { - void anchor() override; + friend class ASTDeclReader; + friend class ASTDeclWriter; - FunctionDecl *OperatorDelete; + // FIXME: Don't allocate storage for these except in the first declaration + // of a virtual destructor. + FunctionDecl *OperatorDelete = nullptr; + Expr *OperatorDeleteThisArg = nullptr; CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, /*isConstexpr=*/false, SourceLocation()), - OperatorDelete(nullptr) { + SC_None, isInline, /*isConstexpr=*/false, SourceLocation()) + { setImplicit(isImplicitlyDeclared); } + void anchor() override; + public: static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, @@ -2572,11 +2647,16 @@ public: bool isImplicitlyDeclared); static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); - void setOperatorDelete(FunctionDecl *OD); + void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg); + const FunctionDecl *getOperatorDelete() const { return getCanonicalDecl()->OperatorDelete; } + Expr *getOperatorDeleteThisArg() const { + return getCanonicalDecl()->OperatorDeleteThisArg; + } + CXXDestructorDecl *getCanonicalDecl() override { return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl()); } @@ -2587,9 +2667,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXDestructor; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a C++ conversion function within a class. @@ -2603,8 +2680,6 @@ public: /// }; /// \endcode class CXXConversionDecl : public CXXMethodDecl { - void anchor() override; - CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, @@ -2615,7 +2690,12 @@ class CXXConversionDecl : public CXXMethodDecl { IsExplicitSpecified = isExplicitSpecified; } + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, @@ -2652,9 +2732,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXConversion; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a linkage specification. @@ -2665,6 +2742,7 @@ public: /// \endcode class LinkageSpecDecl : public Decl, public DeclContext { virtual void anchor(); + public: /// \brief Represents the language in a linkage specification. /// @@ -2676,25 +2754,29 @@ public: lang_c = /* DW_LANG_C */ 0x0002, lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 }; + private: /// \brief The language for this linkage specification. unsigned Language : 3; + /// \brief True if this linkage spec has braces. /// /// This is needed so that hasBraces() returns the correct result while the /// linkage spec body is being parsed. Once RBraceLoc has been set this is /// not used, so it doesn't need to be serialized. unsigned HasBraces : 1; + /// \brief The source location for the extern keyword. SourceLocation ExternLoc; + /// \brief The source location for the right brace (if valid). SourceLocation RBraceLoc; LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs lang, bool HasBraces) - : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), - Language(lang), HasBraces(HasBraces), ExternLoc(ExternLoc), - RBraceLoc(SourceLocation()) { } + : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), + Language(lang), HasBraces(HasBraces), ExternLoc(ExternLoc), + RBraceLoc(SourceLocation()) {} public: static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, @@ -2705,6 +2787,7 @@ public: /// \brief Return the language specified by this linkage specification. LanguageIDs getLanguage() const { return LanguageIDs(Language); } + /// \brief Set the language specified by this linkage specification. void setLanguage(LanguageIDs L) { Language = L; } @@ -2737,9 +2820,11 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == LinkageSpec; } + static DeclContext *castToDeclContext(const LinkageSpecDecl *D) { return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D)); } + static LinkageSpecDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<LinkageSpecDecl *>(const_cast<DeclContext*>(DC)); } @@ -2756,7 +2841,6 @@ public: /// artificial names for all using-directives in order to store /// them in DeclContext effectively. class UsingDirectiveDecl : public NamedDecl { - void anchor() override; /// \brief The location of the \c using keyword. SourceLocation UsingLoc; @@ -2773,6 +2857,16 @@ class UsingDirectiveDecl : public NamedDecl { /// namespace. DeclContext *CommonAncestor; + UsingDirectiveDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation NamespcLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Nominated, + DeclContext *CommonAncestor) + : NamedDecl(UsingDirective, DC, IdentLoc, getName()), UsingLoc(UsingLoc), + NamespaceLoc(NamespcLoc), QualifierLoc(QualifierLoc), + NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) {} + /// \brief Returns special DeclarationName used by using-directives. /// /// This is only used by DeclContext for storing UsingDirectiveDecls in @@ -2781,17 +2875,14 @@ class UsingDirectiveDecl : public NamedDecl { return DeclarationName::getUsingDirectiveName(); } - UsingDirectiveDecl(DeclContext *DC, SourceLocation UsingLoc, - SourceLocation NamespcLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation IdentLoc, - NamedDecl *Nominated, - DeclContext *CommonAncestor) - : NamedDecl(UsingDirective, DC, IdentLoc, getName()), UsingLoc(UsingLoc), - NamespaceLoc(NamespcLoc), QualifierLoc(QualifierLoc), - NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) { } + void anchor() override; public: + friend class ASTDeclReader; + + // Friend for getUsingDirectiveName. + friend class DeclContext; + /// \brief Retrieve the nested-name-specifier that qualifies the /// name of the namespace, with source-location information. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } @@ -2844,11 +2935,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == UsingDirective; } - - // Friend for getUsingDirectiveName. - friend class DeclContext; - - friend class ASTDeclReader; }; /// \brief Represents a C++ namespace alias. @@ -2860,7 +2946,7 @@ public: /// \endcode class NamespaceAliasDecl : public NamedDecl, public Redeclarable<NamespaceAliasDecl> { - void anchor() override; + friend class ASTDeclReader; /// \brief The location of the \c namespace keyword. SourceLocation NamespaceLoc; @@ -2885,13 +2971,14 @@ class NamespaceAliasDecl : public NamedDecl, NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), QualifierLoc(QualifierLoc), Namespace(Namespace) {} - typedef Redeclarable<NamespaceAliasDecl> redeclarable_base; + void anchor() override; + + using redeclarable_base = Redeclarable<NamespaceAliasDecl>; + NamespaceAliasDecl *getNextRedeclarationImpl() override; NamespaceAliasDecl *getPreviousDeclImpl() override; NamespaceAliasDecl *getMostRecentDeclImpl() override; - friend class ASTDeclReader; - public: static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation NamespaceLoc, @@ -2903,8 +2990,9 @@ public: static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -2976,23 +3064,27 @@ public: /// } /// \endcode class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> { - void anchor() override; + friend class UsingDecl; /// The referenced declaration. - NamedDecl *Underlying; + NamedDecl *Underlying = nullptr; /// \brief The using declaration which introduced this decl or the next using /// shadow declaration contained in the aforementioned using declaration. - NamedDecl *UsingOrNextShadow; - friend class UsingDecl; + NamedDecl *UsingOrNextShadow = nullptr; + + void anchor() override; + + using redeclarable_base = Redeclarable<UsingShadowDecl>; - typedef Redeclarable<UsingShadowDecl> redeclarable_base; UsingShadowDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + UsingShadowDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + UsingShadowDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } @@ -3003,6 +3095,9 @@ protected: UsingShadowDecl(Kind K, ASTContext &C, EmptyShell); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target) { @@ -3011,8 +3106,9 @@ public: static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID); - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -3052,9 +3148,6 @@ public: static bool classofKind(Kind K) { return K == Decl::UsingShadow || K == Decl::ConstructorUsingShadow; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a shadow constructor declaration introduced into a @@ -3068,18 +3161,16 @@ public: /// }; /// \endcode class ConstructorUsingShadowDecl final : public UsingShadowDecl { - void anchor() override; - /// \brief If this constructor using declaration inherted the constructor /// from an indirect base class, this is the ConstructorUsingShadowDecl /// in the named direct base class from which the declaration was inherited. - ConstructorUsingShadowDecl *NominatedBaseClassShadowDecl; + ConstructorUsingShadowDecl *NominatedBaseClassShadowDecl = nullptr; /// \brief If this constructor using declaration inherted the constructor /// from an indirect base class, this is the ConstructorUsingShadowDecl /// that will be used to construct the unique direct or virtual base class /// that receives the constructor arguments. - ConstructorUsingShadowDecl *ConstructedBaseClassShadowDecl; + ConstructorUsingShadowDecl *ConstructedBaseClassShadowDecl = nullptr; /// \brief \c true if the constructor ultimately named by this using shadow /// declaration is within a virtual base class subobject of the class that @@ -3105,12 +3196,16 @@ class ConstructorUsingShadowDecl final : public UsingShadowDecl { IsVirtual = true; } } + ConstructorUsingShadowDecl(ASTContext &C, EmptyShell Empty) - : UsingShadowDecl(ConstructorUsingShadow, C, Empty), - NominatedBaseClassShadowDecl(), ConstructedBaseClassShadowDecl(), - IsVirtual(false) {} + : UsingShadowDecl(ConstructorUsingShadow, C, Empty), IsVirtual(false) {} + + void anchor() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ConstructorUsingShadowDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target, @@ -3169,9 +3264,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ConstructorUsingShadow; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a C++ using-declaration. @@ -3181,8 +3273,6 @@ public: /// using someNameSpace::someIdentifier; /// \endcode class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> { - void anchor() override; - /// \brief The source location of the 'using' keyword itself. SourceLocation UsingLocation; @@ -3208,7 +3298,12 @@ class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> { DNLoc(NameInfo.getInfo()), FirstUsingShadow(nullptr, HasTypenameKeyword) { } + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// \brief Return the source location of the 'using' keyword. SourceLocation getUsingLoc() const { return UsingLocation; } @@ -3241,17 +3336,17 @@ public: /// this using declaration. class shadow_iterator { /// \brief The current using shadow declaration. - UsingShadowDecl *Current; + UsingShadowDecl *Current = nullptr; public: - typedef UsingShadowDecl* value_type; - typedef UsingShadowDecl* reference; - typedef UsingShadowDecl* pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = UsingShadowDecl *; + using reference = UsingShadowDecl *; + using pointer = UsingShadowDecl *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - shadow_iterator() : Current(nullptr) { } - explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { } + shadow_iterator() = default; + explicit shadow_iterator(UsingShadowDecl *C) : Current(C) {} reference operator*() const { return Current; } pointer operator->() const { return Current; } @@ -3275,14 +3370,16 @@ public: } }; - typedef llvm::iterator_range<shadow_iterator> shadow_range; + using shadow_range = llvm::iterator_range<shadow_iterator>; shadow_range shadows() const { return shadow_range(shadow_begin(), shadow_end()); } + shadow_iterator shadow_begin() const { return shadow_iterator(FirstUsingShadow.getPointer()); } + shadow_iterator shadow_end() const { return shadow_iterator(); } /// \brief Return the number of shadowed declarations associated with this @@ -3310,9 +3407,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Using; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Represents a pack of using declarations that a single @@ -3331,8 +3425,6 @@ public: class UsingPackDecl final : public NamedDecl, public Mergeable<UsingPackDecl>, private llvm::TrailingObjects<UsingPackDecl, NamedDecl *> { - void anchor() override; - /// The UnresolvedUsingValueDecl or UnresolvedUsingTypenameDecl from /// which this waas instantiated. NamedDecl *InstantiatedFrom; @@ -3352,7 +3444,13 @@ class UsingPackDecl final getTrailingObjects<NamedDecl *>()); } + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + /// Get the using declaration from which this was instantiated. This will /// always be an UnresolvedUsingValueDecl or an UnresolvedUsingTypenameDecl /// that is a pack expansion. @@ -3380,10 +3478,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == UsingPack; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend TrailingObjects; }; /// \brief Represents a dependent using declaration which was not marked with @@ -3399,8 +3493,6 @@ public: /// \endcode class UnresolvedUsingValueDecl : public ValueDecl, public Mergeable<UnresolvedUsingValueDecl> { - void anchor() override; - /// \brief The source location of the 'using' keyword SourceLocation UsingLocation; @@ -3419,13 +3511,17 @@ class UnresolvedUsingValueDecl : public ValueDecl, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, SourceLocation EllipsisLoc) - : ValueDecl(UnresolvedUsingValue, DC, - NameInfo.getLoc(), NameInfo.getName(), Ty), - UsingLocation(UsingLoc), EllipsisLoc(EllipsisLoc), - QualifierLoc(QualifierLoc), DNLoc(NameInfo.getInfo()) - { } + : ValueDecl(UnresolvedUsingValue, DC, + NameInfo.getLoc(), NameInfo.getName(), Ty), + UsingLocation(UsingLoc), EllipsisLoc(EllipsisLoc), + QualifierLoc(QualifierLoc), DNLoc(NameInfo.getInfo()) {} + + void anchor() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// \brief Returns the source location of the 'using' keyword. SourceLocation getUsingLoc() const { return UsingLocation; } @@ -3478,9 +3574,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == UnresolvedUsingValue; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Represents a dependent using declaration which was marked with @@ -3497,7 +3590,7 @@ public: class UnresolvedUsingTypenameDecl : public TypeDecl, public Mergeable<UnresolvedUsingTypenameDecl> { - void anchor() override; + friend class ASTDeclReader; /// \brief The source location of the 'typename' keyword SourceLocation TypenameLocation; @@ -3517,9 +3610,9 @@ class UnresolvedUsingTypenameDecl : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName, UsingLoc), TypenameLocation(TypenameLoc), EllipsisLoc(EllipsisLoc), - QualifierLoc(QualifierLoc) { } + QualifierLoc(QualifierLoc) {} - friend class ASTDeclReader; + void anchor() override; public: /// \brief Returns the source location of the 'using' keyword. @@ -3574,7 +3667,6 @@ public: /// \brief Represents a C++11 static_assert declaration. class StaticAssertDecl : public Decl { - virtual void anchor(); llvm::PointerIntPair<Expr *, 1, bool> AssertExprAndFailed; StringLiteral *Message; SourceLocation RParenLoc; @@ -3582,11 +3674,15 @@ class StaticAssertDecl : public Decl { StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *Message, SourceLocation RParenLoc, bool Failed) - : Decl(StaticAssert, DC, StaticAssertLoc), - AssertExprAndFailed(AssertExpr, Failed), Message(Message), - RParenLoc(RParenLoc) { } + : Decl(StaticAssert, DC, StaticAssertLoc), + AssertExprAndFailed(AssertExpr, Failed), Message(Message), + RParenLoc(RParenLoc) {} + + virtual void anchor(); public: + friend class ASTDeclReader; + static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *Message, @@ -3609,8 +3705,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == StaticAssert; } - - friend class ASTDeclReader; }; /// A binding in a decomposition declaration. For instance, given: @@ -3622,18 +3716,20 @@ public: /// x[0], x[1], and x[2] respectively, where x is the implicit /// DecompositionDecl of type 'int (&)[3]'. class BindingDecl : public ValueDecl { - void anchor() override; - /// The binding represented by this declaration. References to this /// declaration are effectively equivalent to this expression (except /// that it is only evaluated once at the point of declaration of the /// binding). - Expr *Binding; + Expr *Binding = nullptr; BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id) - : ValueDecl(Decl::Binding, DC, IdLoc, Id, QualType()), Binding(nullptr) {} + : ValueDecl(Decl::Binding, DC, IdLoc, Id, QualType()) {} + + void anchor() override; public: + friend class ASTDeclReader; + static BindingDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id); static BindingDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -3657,8 +3753,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::Binding; } - - friend class ASTDeclReader; }; /// A decomposition declaration. For instance, given: @@ -3672,8 +3766,6 @@ public: class DecompositionDecl final : public VarDecl, private llvm::TrailingObjects<DecompositionDecl, BindingDecl *> { - void anchor() override; - /// The number of BindingDecl*s following this object. unsigned NumBindings; @@ -3688,7 +3780,12 @@ class DecompositionDecl final getTrailingObjects<BindingDecl *>()); } + void anchor() override; + public: + friend class ASTDeclReader; + friend TrailingObjects; + static DecompositionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation LSquareLoc, @@ -3706,9 +3803,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decomposition; } - - friend TrailingObjects; - friend class ASTDeclReader; }; /// An instance of this class represents the declaration of a property @@ -3748,6 +3842,8 @@ class MSPropertyDecl : public DeclaratorDecl { GetterId(Getter), SetterId(Setter) {} public: + friend class ASTDeclReader; + static MSPropertyDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, SourceLocation StartL, @@ -3760,8 +3856,6 @@ public: IdentifierInfo* getGetterId() const { return GetterId; } bool hasSetter() const { return SetterId != nullptr; } IdentifierInfo* getSetterId() const { return SetterId; } - - friend class ASTDeclReader; }; /// Insertion operator for diagnostics. This allows sending an AccessSpecifier @@ -3772,6 +3866,6 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, const PartialDiagnostic &operator<<(const PartialDiagnostic &DB, AccessSpecifier AS); -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECLCXX_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h index eb86526e8eca0..6545f70f70b55 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h @@ -1,4 +1,4 @@ -//===-- DeclContextInternals.h - DeclContext Representation -----*- C++ -*-===// +//===- DeclContextInternals.h - DeclContext Representation ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,10 +11,12 @@ // of DeclContext. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H #define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "llvm/ADT/DenseMap.h" @@ -22,6 +24,7 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include <algorithm> +#include <cassert> namespace clang { @@ -30,21 +33,20 @@ class DependentDiagnostic; /// \brief An array of decls optimized for the common case of only containing /// one entry. struct StoredDeclsList { - /// \brief When in vector form, this is what the Data pointer points to. - typedef SmallVector<NamedDecl *, 4> DeclsTy; + using DeclsTy = SmallVector<NamedDecl *, 4>; /// \brief A collection of declarations, with a flag to indicate if we have /// further external declarations. - typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy; + using DeclsAndHasExternalTy = llvm::PointerIntPair<DeclsTy *, 1, bool>; /// \brief The stored data, which will be either a pointer to a NamedDecl, /// or a pointer to a vector with a flag to indicate if there are further /// external declarations. - llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data; + llvm::PointerUnion<NamedDecl *, DeclsAndHasExternalTy> Data; public: - StoredDeclsList() {} + StoredDeclsList() = default; StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) { RHS.Data = (NamedDecl *)nullptr; @@ -186,7 +188,6 @@ public: /// AddSubsequentDecl - This is called on the second and later decl when it is /// not a redeclaration to merge it into the appropriate place in our list. - /// void AddSubsequentDecl(NamedDecl *D) { assert(!isNull() && "don't AddSubsequentDecl when we have no decls"); @@ -237,28 +238,28 @@ public: }; class StoredDeclsMap - : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> { - + : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> { public: static void DestroyAll(StoredDeclsMap *Map, bool Dependent); private: friend class ASTContext; // walks the chain deleting these friend class DeclContext; + llvm::PointerIntPair<StoredDeclsMap*, 1> Previous; }; class DependentStoredDeclsMap : public StoredDeclsMap { public: - DependentStoredDeclsMap() : FirstDiagnostic(nullptr) {} + DependentStoredDeclsMap() = default; private: - friend class DependentDiagnostic; friend class DeclContext; // iterates over diagnostics + friend class DependentDiagnostic; - DependentDiagnostic *FirstDiagnostic; + DependentDiagnostic *FirstDiagnostic = nullptr; }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h b/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h index 172c46a44ac1d..5d1c6b86fe118 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h @@ -1,4 +1,4 @@ -//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===// +//===- DeclFriend.h - Classes for C++ friend declarations -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,16 +15,30 @@ #ifndef LLVM_CLANG_AST_DECLFRIEND_H #define LLVM_CLANG_AST_DECLFRIEND_H +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <iterator> namespace clang { +class ASTContext; + /// FriendDecl - Represents the declaration of a friend entity, /// which can be a function, a type, or a templated function or type. -// For example: +/// For example: /// /// @code /// template <typename T> class A { @@ -41,10 +55,14 @@ class FriendDecl final : public Decl, private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> { virtual void anchor(); + public: - typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + using FriendUnion = llvm::PointerUnion<NamedDecl *, TypeSourceInfo *>; private: + friend class CXXRecordDecl; + friend class CXXRecordDecl::friend_iterator; + // The declaration that's a friend of this class. FriendUnion Friend; @@ -64,35 +82,33 @@ private: // template <class T> friend class A<T>::B; unsigned NumTPLists : 31; - friend class CXXRecordDecl::friend_iterator; - friend class CXXRecordDecl; - FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, SourceLocation FriendL, - ArrayRef<TemplateParameterList*> FriendTypeTPLists) - : Decl(Decl::Friend, DC, L), - Friend(Friend), - NextFriend(), - FriendLoc(FriendL), - UnsupportedFriend(false), - NumTPLists(FriendTypeTPLists.size()) { + ArrayRef<TemplateParameterList *> FriendTypeTPLists) + : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL), + UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) { for (unsigned i = 0; i < NumTPLists; ++i) getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i]; } FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists) - : Decl(Decl::Friend, Empty), NextFriend(), - UnsupportedFriend(false), - NumTPLists(NumFriendTypeTPLists) { } + : Decl(Decl::Friend, Empty), UnsupportedFriend(false), + NumTPLists(NumFriendTypeTPLists) {} FriendDecl *getNextFriend() { if (!NextFriend.isOffset()) return cast_or_null<FriendDecl>(NextFriend.get(nullptr)); return getNextFriendSlowCase(); } + FriendDecl *getNextFriendSlowCase(); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTNodeImporter; + friend TrailingObjects; + static FriendDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, SourceLocation FriendL, @@ -108,9 +124,11 @@ public: TypeSourceInfo *getFriendType() const { return Friend.dyn_cast<TypeSourceInfo*>(); } + unsigned getFriendTypeNumTemplateParameterLists() const { return NumTPLists; } + TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const { assert(N < NumTPLists); return getTrailingObjects<TemplateParameterList *>()[N]; @@ -119,7 +137,7 @@ public: /// If this friend declaration doesn't name a type, return the inner /// declaration. NamedDecl *getFriendDecl() const { - return Friend.dyn_cast<NamedDecl*>(); + return Friend.dyn_cast<NamedDecl *>(); } /// Retrieves the location of the 'friend' keyword. @@ -164,27 +182,24 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::Friend; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend class ASTNodeImporter; - friend TrailingObjects; }; /// An iterator over the friend declarations of a class. class CXXRecordDecl::friend_iterator { + friend class CXXRecordDecl; + FriendDecl *Ptr; - friend class CXXRecordDecl; explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {} + public: - friend_iterator() {} + friend_iterator() = default; - typedef FriendDecl *value_type; - typedef FriendDecl *reference; - typedef FriendDecl *pointer; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = FriendDecl *; + using reference = FriendDecl *; + using pointer = FriendDecl *; + using difference_type = int; + using iterator_category = std::forward_iterator_tag; reference operator*() const { return Ptr; } @@ -240,6 +255,6 @@ inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { data().FirstFriend = FD; } -} +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECLFRIEND_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h b/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h index 6353b26f7bf57..6d5aaadf529cc 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclGroup.h @@ -1,4 +1,4 @@ -//===--- DeclGroup.h - Classes for representing groups of Decls -*- C++ -*-===// +//===- DeclGroup.h - Classes for representing groups of Decls ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,26 +14,26 @@ #ifndef LLVM_CLANG_AST_DECLGROUP_H #define LLVM_CLANG_AST_DECLGROUP_H -#include "llvm/Support/DataTypes.h" #include "llvm/Support/TrailingObjects.h" #include <cassert> +#include <cstdint> namespace clang { class ASTContext; class Decl; -class DeclGroup; -class DeclGroupIterator; class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> { // FIXME: Include a TypeSpecifier object. - unsigned NumDecls; + unsigned NumDecls = 0; private: - DeclGroup() : NumDecls(0) {} + DeclGroup() = default; DeclGroup(unsigned numdecls, Decl** decls); public: + friend TrailingObjects; + static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls); unsigned size() const { return NumDecls; } @@ -47,23 +47,21 @@ public: assert (i < NumDecls && "Out-of-bounds access."); return getTrailingObjects<Decl *>()[i]; } - - friend TrailingObjects; }; class DeclGroupRef { // Note this is not a PointerIntPair because we need the address of the // non-group case to be valid as a Decl** for iteration. enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; - Decl* D; + + Decl* D = nullptr; Kind getKind() const { return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask); } public: - DeclGroupRef() : D(nullptr) {} - + DeclGroupRef() = default; explicit DeclGroupRef(Decl* d) : D(d) {} explicit DeclGroupRef(DeclGroup* dg) : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {} @@ -76,8 +74,8 @@ public: return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls)); } - typedef Decl** iterator; - typedef Decl* const * const_iterator; + using iterator = Decl **; + using const_iterator = Decl * const *; bool isNull() const { return D == nullptr; } bool isSingleDecl() const { return getKind() == SingleDeclKind; } @@ -133,22 +131,26 @@ public: } }; -} // end clang namespace +} // namespace clang namespace llvm { + // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits. template <typename T> - class PointerLikeTypeTraits; + struct PointerLikeTypeTraits; template <> - class PointerLikeTypeTraits<clang::DeclGroupRef> { - public: + struct PointerLikeTypeTraits<clang::DeclGroupRef> { static inline void *getAsVoidPointer(clang::DeclGroupRef P) { return P.getAsOpaquePtr(); } + static inline clang::DeclGroupRef getFromVoidPointer(void *P) { return clang::DeclGroupRef::getFromOpaquePtr(P); } + enum { NumLowBitsAvailable = 0 }; }; -} -#endif + +} // namespace llvm + +#endif // LLVM_CLANG_AST_DECLGROUP_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h b/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h index eba2266724fd3..2fff055825632 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h @@ -1,4 +1,4 @@ -//===-- DeclLookups.h - Low-level interface to all names in a DC-*- C++ -*-===// +//===- DeclLookups.h - Low-level interface to all names in a DC -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,6 +18,9 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" +#include <cstddef> +#include <iterator> namespace clang { @@ -25,14 +28,15 @@ namespace clang { /// of looking up every possible name. class DeclContext::all_lookups_iterator { StoredDeclsMap::iterator It, End; + public: - typedef lookup_result value_type; - typedef lookup_result reference; - typedef lookup_result pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = lookup_result; + using reference = lookup_result; + using pointer = lookup_result; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - all_lookups_iterator() {} + all_lookups_iterator() = default; all_lookups_iterator(StoredDeclsMap::iterator It, StoredDeclsMap::iterator End) : It(It), End(End) {} @@ -63,6 +67,7 @@ public: friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) { return x.It == y.It; } + friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) { return x.It != y.It; } @@ -110,6 +115,6 @@ DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const { return noload_lookups().end(); } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECLLOOKUPS_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h index 1cd6e004f751f..cef7d935370a2 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h @@ -1,4 +1,4 @@ -//===--- DeclObjC.h - Classes for representing declarations -----*- C++ -*-===// +//===- DeclObjC.h - Classes for representing declarations -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,33 +15,59 @@ #define LLVM_CLANG_AST_DECLOBJC_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Redeclarable.h" #include "clang/AST/SelectorLocationsKind.h" +#include "clang/AST/Type.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <string> +#include <utility> namespace clang { + +class ASTContext; +class CompoundStmt; +class CXXCtorInitializer; class Expr; -class Stmt; -class FunctionDecl; -class RecordDecl; -class ObjCIvarDecl; -class ObjCMethodDecl; -class ObjCProtocolDecl; class ObjCCategoryDecl; +class ObjCCategoryImplDecl; +class ObjCImplementationDecl; +class ObjCInterfaceDecl; +class ObjCIvarDecl; class ObjCPropertyDecl; class ObjCPropertyImplDecl; -class CXXCtorInitializer; +class ObjCProtocolDecl; +class Stmt; class ObjCListBase { - ObjCListBase(const ObjCListBase &) = delete; - void operator=(const ObjCListBase &) = delete; protected: /// List is an array of pointers to objects that are not owned by this object. - void **List; - unsigned NumElts; + void **List = nullptr; + unsigned NumElts = 0; public: - ObjCListBase() : List(nullptr), NumElts(0) {} + ObjCListBase() = default; + ObjCListBase(const ObjCListBase &) = delete; + ObjCListBase &operator=(const ObjCListBase &) = delete; + unsigned size() const { return NumElts; } bool empty() const { return NumElts == 0; } @@ -49,7 +75,6 @@ protected: void set(void *const* InList, unsigned Elts, ASTContext &Ctx); }; - /// ObjCList - This is a simple template class used to hold various lists of /// decls etc, which is heavily used by the ObjC front-end. This only use case /// this supports is setting the list all at once and then reading elements out @@ -61,7 +86,8 @@ public: ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx); } - typedef T* const * iterator; + using iterator = T* const *; + iterator begin() const { return (iterator)List; } iterator end() const { return (iterator)List+NumElts; } @@ -74,14 +100,15 @@ public: /// \brief A list of Objective-C protocols, along with the source /// locations at which they were referenced. class ObjCProtocolList : public ObjCList<ObjCProtocolDecl> { - SourceLocation *Locations; + SourceLocation *Locations = nullptr; using ObjCList<ObjCProtocolDecl>::set; public: - ObjCProtocolList() : ObjCList<ObjCProtocolDecl>(), Locations(nullptr) { } + ObjCProtocolList() = default; + + using loc_iterator = const SourceLocation *; - typedef const SourceLocation *loc_iterator; loc_iterator loc_begin() const { return Locations; } loc_iterator loc_end() const { return Locations + size(); } @@ -89,7 +116,6 @@ public: const SourceLocation *Locs, ASTContext &Ctx); }; - /// ObjCMethodDecl - Represents an instance or class method declaration. /// ObjC methods can be declared within 4 contexts: class interfaces, /// categories, protocols, and class implementations. While C++ member @@ -113,6 +139,7 @@ public: class ObjCMethodDecl : public NamedDecl, public DeclContext { public: enum ImplementationControl { None, Required, Optional }; + private: // The conventional meaning of this method; an ObjCMethodFamily. // This is not serialized; instead, it is computed on demand and @@ -170,8 +197,8 @@ private: /// \brief Array of ParmVarDecls for the formal parameters of this method /// and optionally followed by selector locations. - void *ParamsAndSelLocs; - unsigned NumParams; + void *ParamsAndSelLocs = nullptr; + unsigned NumParams = 0; /// List of attributes for this method declaration. SourceLocation DeclEndLoc; // the location of the ';' or '{'. @@ -181,14 +208,35 @@ private: /// SelfDecl - Decl for the implicit self parameter. This is lazily /// constructed by createImplicitParams. - ImplicitParamDecl *SelfDecl; + ImplicitParamDecl *SelfDecl = nullptr; + /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily /// constructed by createImplicitParams. - ImplicitParamDecl *CmdDecl; + ImplicitParamDecl *CmdDecl = nullptr; + + ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, + Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, + DeclContext *contextDecl, bool isInstance = true, + bool isVariadic = false, bool isPropertyAccessor = false, + bool isImplicitlyDeclared = false, bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false) + : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), + DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily), + IsInstance(isInstance), IsVariadic(isVariadic), + IsPropertyAccessor(isPropertyAccessor), IsDefined(isDefined), + IsRedeclaration(0), HasRedeclaration(0), DeclImplementation(impControl), + objcDeclQualifier(OBJC_TQ_None), + RelatedResultType(HasRelatedResultType), + SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0), + MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclEndLoc(endLoc) { + setImplicit(isImplicitlyDeclared); + } SelectorLocationsKind getSelLocsKind() const { return (SelectorLocationsKind)SelLocsKind; } + bool hasStandardSelLocs() const { return getSelLocsKind() != SelLoc_NonStandard; } @@ -223,33 +271,15 @@ private: ArrayRef<ParmVarDecl*> Params, ArrayRef<SourceLocation> SelLocs); - ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, - Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, - DeclContext *contextDecl, bool isInstance = true, - bool isVariadic = false, bool isPropertyAccessor = false, - bool isImplicitlyDeclared = false, bool isDefined = false, - ImplementationControl impControl = None, - bool HasRelatedResultType = false) - : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), - DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily), - IsInstance(isInstance), IsVariadic(isVariadic), - IsPropertyAccessor(isPropertyAccessor), IsDefined(isDefined), - IsRedeclaration(0), HasRedeclaration(0), DeclImplementation(impControl), - objcDeclQualifier(OBJC_TQ_None), - RelatedResultType(HasRelatedResultType), - SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0), - MethodDeclType(T), ReturnTInfo(ReturnTInfo), ParamsAndSelLocs(nullptr), - NumParams(0), DeclEndLoc(endLoc), Body(), SelfDecl(nullptr), - CmdDecl(nullptr) { - setImplicit(isImplicitlyDeclared); - } - /// \brief A definition will return its interface declaration. /// An interface declaration will return its definition. /// Otherwise it will return itself. ObjCMethodDecl *getNextRedeclarationImpl() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ObjCMethodDecl * Create(ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, @@ -299,6 +329,7 @@ public: return getLocStart(); return getSelectorLoc(0); } + SourceLocation getSelectorLoc(unsigned Index) const { assert(Index < getNumSelectorLocs() && "Index out of range!"); if (hasStandardSelLocs()) @@ -346,17 +377,20 @@ public: // Iterator access to formal parameters. unsigned param_size() const { return NumParams; } - typedef const ParmVarDecl *const *param_const_iterator; - typedef ParmVarDecl *const *param_iterator; - typedef llvm::iterator_range<param_iterator> param_range; - typedef llvm::iterator_range<param_const_iterator> param_const_range; + + using param_const_iterator = const ParmVarDecl *const *; + using param_iterator = ParmVarDecl *const *; + using param_range = llvm::iterator_range<param_iterator>; + using param_const_range = llvm::iterator_range<param_const_iterator>; param_const_iterator param_begin() const { return param_const_iterator(getParams()); } + param_const_iterator param_end() const { return param_const_iterator(getParams() + NumParams); } + param_iterator param_begin() { return param_iterator(getParams()); } param_iterator param_end() { return param_iterator(getParams() + NumParams); } @@ -384,12 +418,14 @@ public: struct GetTypeFn { QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); } }; - typedef llvm::mapped_iterator<param_const_iterator, GetTypeFn> - param_type_iterator; + + using param_type_iterator = + llvm::mapped_iterator<param_const_iterator, GetTypeFn>; param_type_iterator param_type_begin() const { return llvm::map_iterator(param_begin(), GetTypeFn()); } + param_type_iterator param_type_end() const { return llvm::map_iterator(param_end(), GetTypeFn()); } @@ -462,9 +498,11 @@ public: void setDeclImplementation(ImplementationControl ic) { DeclImplementation = ic; } + ImplementationControl getImplementationControl() const { return ImplementationControl(DeclImplementation); } + bool isOptional() const { return getImplementationControl() == Optional; } @@ -499,24 +537,25 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCMethod; } + static DeclContext *castToDeclContext(const ObjCMethodDecl *D) { return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D)); } + static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC)); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Describes the variance of a given generic parameter. enum class ObjCTypeParamVariance : uint8_t { /// The parameter is invariant: must match exactly. Invariant, + /// The parameter is covariant, e.g., X<T> is a subtype of X<U> when /// the type parameter is covariant and T is a subtype of U. Covariant, + /// The parameter is contravariant, e.g., X<T> is a subtype of X<U> /// when the type parameter is covariant and U is a subtype of T. Contravariant, @@ -535,8 +574,6 @@ enum class ObjCTypeParamVariance : uint8_t { /// /// Objective-C type parameters are typedef-names in the grammar, class ObjCTypeParamDecl : public TypedefNameDecl { - void anchor() override; - /// Index of this type parameter in the type parameter list. unsigned Index : 14; @@ -555,12 +592,17 @@ class ObjCTypeParamDecl : public TypedefNameDecl { unsigned index, SourceLocation nameLoc, IdentifierInfo *name, SourceLocation colonLoc, TypeSourceInfo *boundInfo) - : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name, - boundInfo), - Index(index), Variance(static_cast<unsigned>(variance)), - VarianceLoc(varianceLoc), ColonLoc(colonLoc) { } + : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name, + boundInfo), + Index(index), Variance(static_cast<unsigned>(variance)), + VarianceLoc(varianceLoc), ColonLoc(colonLoc) {} + + void anchor() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc, ObjCTypeParamVariance variance, SourceLocation varianceLoc, @@ -600,9 +642,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCTypeParam; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Stores a list of Objective-C type parameters for a parameterized class @@ -636,6 +675,8 @@ class ObjCTypeParamList final SourceLocation rAngleLoc); public: + friend TrailingObjects; + /// Create a new Objective-C type parameter list. static ObjCTypeParamList *create(ASTContext &ctx, SourceLocation lAngleLoc, @@ -643,7 +684,7 @@ public: SourceLocation rAngleLoc); /// Iterate through the type parameters in the list. - typedef ObjCTypeParamDecl **iterator; + using iterator = ObjCTypeParamDecl **; iterator begin() { return getTrailingObjects<ObjCTypeParamDecl *>(); } @@ -653,7 +694,7 @@ public: unsigned size() const { return NumParams; } // Iterate through the type parameters in the list. - typedef ObjCTypeParamDecl * const *const_iterator; + using const_iterator = ObjCTypeParamDecl * const *; const_iterator begin() const { return getTrailingObjects<ObjCTypeParamDecl *>(); @@ -676,9 +717,11 @@ public: SourceLocation getLAngleLoc() const { return SourceLocation::getFromRawEncoding(Brackets.Begin); } + SourceLocation getRAngleLoc() const { return SourceLocation::getFromRawEncoding(Brackets.End); } + SourceRange getSourceRange() const { return SourceRange(getLAngleLoc(), getRAngleLoc()); } @@ -686,7 +729,6 @@ public: /// Gather the default set of type arguments to be substituted for /// these type parameters when dealing with an unspecialized type. void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const; - friend TrailingObjects; }; enum class ObjCPropertyQueryKind : uint8_t { @@ -703,6 +745,7 @@ enum class ObjCPropertyQueryKind : uint8_t { /// \endcode class ObjCPropertyDecl : public NamedDecl { void anchor() override; + public: enum PropertyAttributeKind { OBJC_PR_noattr = 0x00, @@ -733,24 +776,42 @@ public: enum SetterKind { Assign, Retain, Copy, Weak }; enum PropertyControl { None, Required, Optional }; + private: - SourceLocation AtLoc; // location of \@property - SourceLocation LParenLoc; // location of '(' starting attribute list or null. + // location of \@property + SourceLocation AtLoc; + + // location of '(' starting attribute list or null. + SourceLocation LParenLoc; + QualType DeclType; TypeSourceInfo *DeclTypeSourceInfo; unsigned PropertyAttributes : NumPropertyAttrsBits; unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits; + // \@required/\@optional unsigned PropertyImplementation : 2; - Selector GetterName; // getter name of NULL if no getter - Selector SetterName; // setter name of NULL if no setter - SourceLocation GetterNameLoc; // location of the getter attribute's value - SourceLocation SetterNameLoc; // location of the setter attribute's value + // getter name of NULL if no getter + Selector GetterName; + + // setter name of NULL if no setter + Selector SetterName; + + // location of the getter attribute's value + SourceLocation GetterNameLoc; + + // location of the setter attribute's value + SourceLocation SetterNameLoc; + + // Declaration of getter instance method + ObjCMethodDecl *GetterMethodDecl = nullptr; + + // Declaration of setter instance method + ObjCMethodDecl *SetterMethodDecl = nullptr; - ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method - ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method - ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property + // Synthesize ivar for this property + ObjCIvarDecl *PropertyIvarDecl = nullptr; ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation AtLocation, SourceLocation LParenLocation, @@ -760,11 +821,8 @@ private: LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI), PropertyAttributes(OBJC_PR_noattr), PropertyAttributesAsWritten(OBJC_PR_noattr), - PropertyImplementation(propControl), - GetterName(Selector()), - SetterName(Selector()), - GetterMethodDecl(nullptr), SetterMethodDecl(nullptr), - PropertyIvarDecl(nullptr) {} + PropertyImplementation(propControl), GetterName(Selector()), + SetterName(Selector()) {} public: static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, @@ -799,9 +857,11 @@ public: PropertyAttributeKind getPropertyAttributes() const { return PropertyAttributeKind(PropertyAttributes); } + void setPropertyAttributes(PropertyAttributeKind PRVal) { PropertyAttributes |= PRVal; } + void overwritePropertyAttributes(unsigned PRVal) { PropertyAttributes = PRVal; } @@ -834,10 +894,12 @@ public: bool isInstanceProperty() const { return !isClassProperty(); } bool isClassProperty() const { return PropertyAttributes & OBJC_PR_class; } + ObjCPropertyQueryKind getQueryKind() const { return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class : ObjCPropertyQueryKind::OBJC_PR_query_instance; } + static ObjCPropertyQueryKind getQueryKind(bool isClassProperty) { return isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class : ObjCPropertyQueryKind::OBJC_PR_query_instance; @@ -860,6 +922,7 @@ public: Selector getGetterName() const { return GetterName; } SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) { GetterName = Sel; GetterNameLoc = Loc; @@ -867,6 +930,7 @@ public: Selector getSetterName() const { return SetterName; } SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) { SetterName = Sel; SetterNameLoc = Loc; @@ -882,9 +946,11 @@ public: void setPropertyImplementation(PropertyControl pc) { PropertyImplementation = pc; } + PropertyControl getPropertyImplementation() const { return PropertyControl(PropertyImplementation); } + bool isOptional() const { return getPropertyImplementation() == PropertyControl::Optional; } @@ -892,6 +958,7 @@ public: void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } + ObjCIvarDecl *getPropertyIvarDecl() const { return PropertyIvarDecl; } @@ -917,104 +984,116 @@ public: /// ObjCProtocolDecl, and ObjCImplDecl. /// class ObjCContainerDecl : public NamedDecl, public DeclContext { - void anchor() override; - SourceLocation AtStart; // These two locations in the range mark the end of the method container. // The first points to the '@' token, and the second to the 'end' token. SourceRange AtEnd; -public: + void anchor() override; + +public: ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id, SourceLocation nameLoc, SourceLocation atStartLoc) - : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {} + : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {} // Iterator access to instance/class properties. - typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCPropertyDecl>> - prop_range; + using prop_iterator = specific_decl_iterator<ObjCPropertyDecl>; + using prop_range = + llvm::iterator_range<specific_decl_iterator<ObjCPropertyDecl>>; prop_range properties() const { return prop_range(prop_begin(), prop_end()); } + prop_iterator prop_begin() const { return prop_iterator(decls_begin()); } + prop_iterator prop_end() const { return prop_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCPropertyDecl, - &ObjCPropertyDecl::isInstanceProperty> - instprop_iterator; - typedef llvm::iterator_range<instprop_iterator> instprop_range; + using instprop_iterator = + filtered_decl_iterator<ObjCPropertyDecl, + &ObjCPropertyDecl::isInstanceProperty>; + using instprop_range = llvm::iterator_range<instprop_iterator>; instprop_range instance_properties() const { return instprop_range(instprop_begin(), instprop_end()); } + instprop_iterator instprop_begin() const { return instprop_iterator(decls_begin()); } + instprop_iterator instprop_end() const { return instprop_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCPropertyDecl, - &ObjCPropertyDecl::isClassProperty> - classprop_iterator; - typedef llvm::iterator_range<classprop_iterator> classprop_range; + using classprop_iterator = + filtered_decl_iterator<ObjCPropertyDecl, + &ObjCPropertyDecl::isClassProperty>; + using classprop_range = llvm::iterator_range<classprop_iterator>; classprop_range class_properties() const { return classprop_range(classprop_begin(), classprop_end()); } + classprop_iterator classprop_begin() const { return classprop_iterator(decls_begin()); } + classprop_iterator classprop_end() const { return classprop_iterator(decls_end()); } // Iterator access to instance/class methods. - typedef specific_decl_iterator<ObjCMethodDecl> method_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCMethodDecl>> - method_range; + using method_iterator = specific_decl_iterator<ObjCMethodDecl>; + using method_range = + llvm::iterator_range<specific_decl_iterator<ObjCMethodDecl>>; method_range methods() const { return method_range(meth_begin(), meth_end()); } + method_iterator meth_begin() const { return method_iterator(decls_begin()); } + method_iterator meth_end() const { return method_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isInstanceMethod> - instmeth_iterator; - typedef llvm::iterator_range<instmeth_iterator> instmeth_range; + using instmeth_iterator = + filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod>; + using instmeth_range = llvm::iterator_range<instmeth_iterator>; instmeth_range instance_methods() const { return instmeth_range(instmeth_begin(), instmeth_end()); } + instmeth_iterator instmeth_begin() const { return instmeth_iterator(decls_begin()); } + instmeth_iterator instmeth_end() const { return instmeth_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isClassMethod> - classmeth_iterator; - typedef llvm::iterator_range<classmeth_iterator> classmeth_range; + using classmeth_iterator = + filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod>; + using classmeth_range = llvm::iterator_range<classmeth_iterator>; classmeth_range class_methods() const { return classmeth_range(classmeth_begin(), classmeth_end()); } + classmeth_iterator classmeth_begin() const { return classmeth_iterator(decls_begin()); } + classmeth_iterator classmeth_end() const { return classmeth_iterator(decls_end()); } @@ -1022,13 +1101,16 @@ public: // Get the local instance/class method declared in this interface. ObjCMethodDecl *getMethod(Selector Sel, bool isInstance, bool AllowHidden = false) const; + ObjCMethodDecl *getInstanceMethod(Selector Sel, bool AllowHidden = false) const { return getMethod(Sel, true/*isInstance*/, AllowHidden); } + ObjCMethodDecl *getClassMethod(Selector Sel, bool AllowHidden = false) const { return getMethod(Sel, false/*isInstance*/, AllowHidden); } + bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const; ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; @@ -1036,13 +1118,11 @@ public: FindPropertyDeclaration(const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const; - typedef llvm::DenseMap<std::pair<IdentifierInfo*, - unsigned/*isClassProperty*/>, - ObjCPropertyDecl*> PropertyMap; - - typedef llvm::SmallDenseSet<const ObjCProtocolDecl *, 8> ProtocolPropertySet; - - typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder; + using PropertyMap = + llvm::DenseMap<std::pair<IdentifierInfo *, unsigned/*isClassProperty*/>, + ObjCPropertyDecl *>; + using ProtocolPropertySet = llvm::SmallDenseSet<const ObjCProtocolDecl *, 8>; + using PropertyDeclOrder = llvm::SmallVector<ObjCPropertyDecl *, 8>; /// This routine collects list of properties to be implemented in the class. /// This includes, class's and its conforming protocols' properties. @@ -1057,6 +1137,7 @@ public: SourceRange getAtEndRange() const { return AtEnd; } + void setAtEndRange(SourceRange atEnd) { AtEnd = atEnd; } @@ -1067,6 +1148,7 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstObjCContainer && K <= lastObjCContainer; @@ -1075,6 +1157,7 @@ public: static DeclContext *castToDeclContext(const ObjCContainerDecl *D) { return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D)); } + static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) { return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC)); } @@ -1107,20 +1190,19 @@ public: /// class ObjCInterfaceDecl : public ObjCContainerDecl , public Redeclarable<ObjCInterfaceDecl> { - void anchor() override; + friend class ASTContext; /// TypeForDecl - This indicates the Type object that represents this /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType - mutable const Type *TypeForDecl; - friend class ASTContext; + mutable const Type *TypeForDecl = nullptr; struct DefinitionData { /// \brief The definition of this class, for quick access from any /// declaration. - ObjCInterfaceDecl *Definition; + ObjCInterfaceDecl *Definition = nullptr; /// When non-null, this is always an ObjCObjectType. - TypeSourceInfo *SuperClassTInfo; + TypeSourceInfo *SuperClassTInfo = nullptr; /// Protocols referenced in the \@interface declaration ObjCProtocolList ReferencedProtocols; @@ -1133,11 +1215,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// Categories are stored as a linked list in the AST, since the categories /// and class extensions come long after the initial interface declaration, /// and we avoid dynamically-resized arrays in the AST wherever possible. - ObjCCategoryDecl *CategoryList; + ObjCCategoryDecl *CategoryList = nullptr; /// IvarList - List of all ivars defined by this class; including class /// extensions and implementation. This list is built lazily. - ObjCIvarDecl *IvarList; + ObjCIvarDecl *IvarList = nullptr; /// \brief Indicates that the contents of this Objective-C class will be /// completed by the external AST source when required. @@ -1155,11 +1237,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// We didn't calculate whether the designated initializers should be /// inherited or not. IDI_Unknown = 0, + /// Designated initializers are inherited for the super class. IDI_Inherited = 1, + /// The class does not inherit designated initializers. IDI_NotInherited = 2 }; + /// One of the \c InheritedDesignatedInitializersState enumeratos. mutable unsigned InheritedDesignatedInitializers : 2; @@ -1168,22 +1253,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// identifier, SourceLocation EndLoc; - DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(), - ExternallyCompleted(), - IvarListMissingImplementation(true), - HasDesignatedInitializers(), - InheritedDesignatedInitializers(IDI_Unknown) { } + DefinitionData() + : ExternallyCompleted(false), IvarListMissingImplementation(true), + HasDesignatedInitializers(false), + InheritedDesignatedInitializers(IDI_Unknown) {} }; - ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, - IdentifierInfo *Id, ObjCTypeParamList *typeParamList, - SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, - bool IsInternal); - - void LoadExternalDefinition() const; - /// The type parameters associated with this class, if any. - ObjCTypeParamList *TypeParamList; + ObjCTypeParamList *TypeParamList = nullptr; /// \brief Contains a pointer to the data associated with this class, /// which will be NULL if this class has not yet been defined. @@ -1192,6 +1269,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// declarations. It will be set unless modules are enabled. llvm::PointerIntPair<DefinitionData *, 1, bool> Data; + ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, + bool IsInternal); + + void anchor() override; + + void LoadExternalDefinition() const; + DefinitionData &data() const { assert(Data.getPointer() && "Declaration has no definition!"); return *Data.getPointer(); @@ -1200,13 +1286,16 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// \brief Allocate the definition data for this class. void allocateDefinitionData(); - typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base; + using redeclarable_base = Redeclarable<ObjCInterfaceDecl>; + ObjCInterfaceDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + ObjCInterfaceDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + ObjCInterfaceDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } @@ -1284,17 +1373,19 @@ public: // Get the local instance/class method declared in a category. ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const { return isInstance ? getCategoryInstanceMethod(Sel) : getCategoryClassMethod(Sel); } - typedef ObjCProtocolList::iterator protocol_iterator; - typedef llvm::iterator_range<protocol_iterator> protocol_range; + using protocol_iterator = ObjCProtocolList::iterator; + using protocol_range = llvm::iterator_range<protocol_iterator>; protocol_range protocols() const { return protocol_range(protocol_begin(), protocol_end()); } + protocol_iterator protocol_begin() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) @@ -1305,6 +1396,7 @@ public: return data().ReferencedProtocols.begin(); } + protocol_iterator protocol_end() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) @@ -1316,12 +1408,13 @@ public: return data().ReferencedProtocols.end(); } - typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; - typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + using protocol_loc_iterator = ObjCProtocolList::loc_iterator; + using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>; protocol_loc_range protocol_locs() const { return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); } + protocol_loc_iterator protocol_loc_begin() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) @@ -1344,13 +1437,14 @@ public: return data().ReferencedProtocols.loc_end(); } - typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator; - typedef llvm::iterator_range<all_protocol_iterator> all_protocol_range; + using all_protocol_iterator = ObjCList<ObjCProtocolDecl>::iterator; + using all_protocol_range = llvm::iterator_range<all_protocol_iterator>; all_protocol_range all_referenced_protocols() const { return all_protocol_range(all_referenced_protocol_begin(), all_referenced_protocol_end()); } + all_protocol_iterator all_referenced_protocol_begin() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) @@ -1363,6 +1457,7 @@ public: ? protocol_begin() : data().AllReferencedProtocols.begin(); } + all_protocol_iterator all_referenced_protocol_end() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) @@ -1376,10 +1471,11 @@ public: : data().AllReferencedProtocols.end(); } - typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>; + using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>; ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { if (const ObjCInterfaceDecl *Def = getDefinition()) return ivar_iterator(Def->decls_begin()); @@ -1387,6 +1483,7 @@ public: // FIXME: Should make sure no callers ever do this. return ivar_iterator(); } + ivar_iterator ivar_end() const { if (const ObjCInterfaceDecl *Def = getDefinition()) return ivar_iterator(Def->decls_end()); @@ -1518,21 +1615,20 @@ public: /// and extension iterators. template<bool (*Filter)(ObjCCategoryDecl *)> class filtered_category_iterator { - ObjCCategoryDecl *Current; + ObjCCategoryDecl *Current = nullptr; void findAcceptableCategory(); public: - typedef ObjCCategoryDecl * value_type; - typedef value_type reference; - typedef value_type pointer; - typedef std::ptrdiff_t difference_type; - typedef std::input_iterator_tag iterator_category; + using value_type = ObjCCategoryDecl *; + using reference = value_type; + using pointer = value_type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; - filtered_category_iterator() : Current(nullptr) { } + filtered_category_iterator() = default; explicit filtered_category_iterator(ObjCCategoryDecl *Current) - : Current(Current) - { + : Current(Current) { findAcceptableCategory(); } @@ -1567,11 +1663,11 @@ private: public: /// \brief Iterator that walks over the list of categories and extensions /// that are visible, i.e., not hidden in a non-imported submodule. - typedef filtered_category_iterator<isVisibleCategory> - visible_categories_iterator; + using visible_categories_iterator = + filtered_category_iterator<isVisibleCategory>; - typedef llvm::iterator_range<visible_categories_iterator> - visible_categories_range; + using visible_categories_range = + llvm::iterator_range<visible_categories_iterator>; visible_categories_range visible_categories() const { return visible_categories_range(visible_categories_begin(), @@ -1603,9 +1699,9 @@ private: public: /// \brief Iterator that walks over all of the known categories and /// extensions, including those that are hidden. - typedef filtered_category_iterator<isKnownCategory> known_categories_iterator; - typedef llvm::iterator_range<known_categories_iterator> - known_categories_range; + using known_categories_iterator = filtered_category_iterator<isKnownCategory>; + using known_categories_range = + llvm::iterator_range<known_categories_iterator>; known_categories_range known_categories() const { return known_categories_range(known_categories_begin(), @@ -1637,11 +1733,11 @@ private: public: /// \brief Iterator that walks over all of the visible extensions, skipping /// any that are known but hidden. - typedef filtered_category_iterator<isVisibleExtension> - visible_extensions_iterator; + using visible_extensions_iterator = + filtered_category_iterator<isVisibleExtension>; - typedef llvm::iterator_range<visible_extensions_iterator> - visible_extensions_range; + using visible_extensions_range = + llvm::iterator_range<visible_extensions_iterator>; visible_extensions_range visible_extensions() const { return visible_extensions_range(visible_extensions_begin(), @@ -1671,11 +1767,15 @@ private: static bool isKnownExtension(ObjCCategoryDecl *Cat); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + /// \brief Iterator that walks over all of the known extensions. - typedef filtered_category_iterator<isKnownExtension> - known_extensions_iterator; - typedef llvm::iterator_range<known_extensions_iterator> - known_extensions_range; + using known_extensions_iterator = + filtered_category_iterator<isKnownExtension>; + using known_extensions_range = + llvm::iterator_range<known_extensions_iterator>; known_extensions_range known_extensions() const { return known_extensions_range(known_extensions_begin(), @@ -1771,6 +1871,7 @@ public: ObjCMethodDecl *lookupClassMethod(Selector Sel) const { return lookupMethod(Sel, false/*isInstance*/); } + ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); /// \brief Lookup a method in the classes implementation hierarchy. @@ -1819,8 +1920,9 @@ public: bool lookupCategory, bool RHSIsQualifiedID = false); - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -1839,10 +1941,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCInterface; } - friend class ASTReader; - friend class ASTDeclReader; - friend class ASTDeclWriter; - private: const ObjCInterfaceDecl *findInterfaceWithDesignatedInitializers() const; bool inheritsDesignatedInitializers() const; @@ -1876,9 +1974,9 @@ private: SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) - : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, - /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), - NextIvar(nullptr), DeclAccess(ac), Synthesized(synthesized) {} + : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, + /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), + DeclAccess(ac), Synthesized(synthesized) {} public: static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, @@ -1918,26 +2016,27 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCIvar; } + private: /// NextIvar - Next Ivar in the list of ivars declared in class; class's /// extensions and class's implementation - ObjCIvarDecl *NextIvar; + ObjCIvarDecl *NextIvar = nullptr; // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum unsigned DeclAccess : 3; unsigned Synthesized : 1; }; - /// \brief Represents a field declaration created by an \@defs(...). class ObjCAtDefsFieldDecl : public FieldDecl { - void anchor() override; ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, Expr *BW) - : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, - /*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ? - BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {} + : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, + /*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ? + BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {} + + void anchor() override; public: static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, @@ -1981,11 +2080,8 @@ public: /// protocols are referenced using angle brackets as follows: /// /// id \<NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo; -/// class ObjCProtocolDecl : public ObjCContainerDecl, public Redeclarable<ObjCProtocolDecl> { - void anchor() override; - struct DefinitionData { // \brief The declaration that defines this protocol. ObjCProtocolDecl *Definition; @@ -2001,29 +2097,38 @@ class ObjCProtocolDecl : public ObjCContainerDecl, /// declarations. It will be set unless modules are enabled. llvm::PointerIntPair<DefinitionData *, 1, bool> Data; + ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc, + ObjCProtocolDecl *PrevDecl); + + void anchor() override; + DefinitionData &data() const { assert(Data.getPointer() && "Objective-C protocol has no definition!"); return *Data.getPointer(); } - ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, - SourceLocation nameLoc, SourceLocation atStartLoc, - ObjCProtocolDecl *PrevDecl); - void allocateDefinitionData(); - typedef Redeclarable<ObjCProtocolDecl> redeclarable_base; + using redeclarable_base = Redeclarable<ObjCProtocolDecl>; + ObjCProtocolDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + ObjCProtocolDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + ObjCProtocolDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, SourceLocation nameLoc, @@ -2036,42 +2141,49 @@ public: assert(hasDefinition() && "No definition available!"); return data().ReferencedProtocols; } - typedef ObjCProtocolList::iterator protocol_iterator; - typedef llvm::iterator_range<protocol_iterator> protocol_range; + + using protocol_iterator = ObjCProtocolList::iterator; + using protocol_range = llvm::iterator_range<protocol_iterator>; protocol_range protocols() const { return protocol_range(protocol_begin(), protocol_end()); } + protocol_iterator protocol_begin() const { if (!hasDefinition()) return protocol_iterator(); return data().ReferencedProtocols.begin(); } + protocol_iterator protocol_end() const { if (!hasDefinition()) return protocol_iterator(); return data().ReferencedProtocols.end(); } - typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; - typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + + using protocol_loc_iterator = ObjCProtocolList::loc_iterator; + using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>; protocol_loc_range protocol_locs() const { return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); } + protocol_loc_iterator protocol_loc_begin() const { if (!hasDefinition()) return protocol_loc_iterator(); return data().ReferencedProtocols.loc_begin(); } + protocol_loc_iterator protocol_loc_end() const { if (!hasDefinition()) return protocol_loc_iterator(); return data().ReferencedProtocols.loc_end(); } + unsigned protocol_size() const { if (!hasDefinition()) return 0; @@ -2092,9 +2204,11 @@ public: // Lookup a method. First, we search locally. If a method isn't // found, we search referenced protocols and class categories. ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { return lookupMethod(Sel, true/*isInstance*/); } + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { return lookupMethod(Sel, false/*isInstance*/); } @@ -2141,8 +2255,9 @@ public: return SourceRange(getAtStartLoc(), getLocation()); } - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -2163,10 +2278,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCProtocol; } - - friend class ASTReader; - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// ObjCCategoryDecl - Represents a category declaration. A category allows @@ -2185,22 +2296,19 @@ public: /// Categories were originally inspired by dynamic languages such as Common /// Lisp and Smalltalk. More traditional class-based languages (C++, Java) /// don't support this level of dynamism, which is both powerful and dangerous. -/// class ObjCCategoryDecl : public ObjCContainerDecl { - void anchor() override; - /// Interface belonging to this category ObjCInterfaceDecl *ClassInterface; /// The type parameters associated with this category, if any. - ObjCTypeParamList *TypeParamList; + ObjCTypeParamList *TypeParamList = nullptr; /// referenced protocols in this category. ObjCProtocolList ReferencedProtocols; /// Next category belonging to this class. /// FIXME: this should not be a singly-linked list. Move storage elsewhere. - ObjCCategoryDecl *NextClassCategory; + ObjCCategoryDecl *NextClassCategory = nullptr; /// \brief The location of the category name in this declaration. SourceLocation CategoryNameLoc; @@ -2213,10 +2321,14 @@ class ObjCCategoryDecl : public ObjCContainerDecl { SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc=SourceLocation(), - SourceLocation IvarRBraceLoc=SourceLocation()); + SourceLocation IvarLBraceLoc = SourceLocation(), + SourceLocation IvarRBraceLoc = SourceLocation()); + + void anchor() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, @@ -2257,26 +2369,31 @@ public: return ReferencedProtocols; } - typedef ObjCProtocolList::iterator protocol_iterator; - typedef llvm::iterator_range<protocol_iterator> protocol_range; + using protocol_iterator = ObjCProtocolList::iterator; + using protocol_range = llvm::iterator_range<protocol_iterator>; protocol_range protocols() const { return protocol_range(protocol_begin(), protocol_end()); } + protocol_iterator protocol_begin() const { return ReferencedProtocols.begin(); } + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } unsigned protocol_size() const { return ReferencedProtocols.size(); } - typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; - typedef llvm::iterator_range<protocol_loc_iterator> protocol_loc_range; + + using protocol_loc_iterator = ObjCProtocolList::loc_iterator; + using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>; protocol_loc_range protocol_locs() const { return protocol_loc_range(protocol_loc_begin(), protocol_loc_end()); } + protocol_loc_iterator protocol_loc_begin() const { return ReferencedProtocols.loc_begin(); } + protocol_loc_iterator protocol_loc_end() const { return ReferencedProtocols.loc_end(); } @@ -2291,19 +2408,23 @@ public: bool IsClassExtension() const { return getIdentifier() == nullptr; } - typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>; + using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>; ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); } + ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); } + unsigned ivar_size() const { return std::distance(ivar_begin(), ivar_end()); } + bool ivar_empty() const { return ivar_begin() == ivar_end(); } @@ -2318,24 +2439,21 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCCategory; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; class ObjCImplDecl : public ObjCContainerDecl { - void anchor() override; - /// Class interface for this class/category implementation ObjCInterfaceDecl *ClassInterface; + void anchor() override; + protected: ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface, IdentifierInfo *Id, SourceLocation nameLoc, SourceLocation atStartLoc) - : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc), - ClassInterface(classInterface) {} + : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc), + ClassInterface(classInterface) {} public: const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } @@ -2347,6 +2465,7 @@ public: method->setLexicalDeclContext(this); addDecl(method); } + void addClassMethod(ObjCMethodDecl *method) { // FIXME: Context should be set correctly before we get here. method->setLexicalDeclContext(this); @@ -2360,21 +2479,24 @@ public: ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const; // Iterator access to properties. - typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCPropertyImplDecl>> - propimpl_range; + using propimpl_iterator = specific_decl_iterator<ObjCPropertyImplDecl>; + using propimpl_range = + llvm::iterator_range<specific_decl_iterator<ObjCPropertyImplDecl>>; propimpl_range property_impls() const { return propimpl_range(propimpl_begin(), propimpl_end()); } + propimpl_iterator propimpl_begin() const { return propimpl_iterator(decls_begin()); } + propimpl_iterator propimpl_end() const { return propimpl_iterator(decls_end()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstObjCImpl && K <= lastObjCImpl; } @@ -2394,8 +2516,6 @@ public: /// /// ObjCCategoryImplDecl class ObjCCategoryImplDecl : public ObjCImplDecl { - void anchor() override; - // Category name location SourceLocation CategoryNameLoc; @@ -2403,10 +2523,16 @@ class ObjCCategoryImplDecl : public ObjCImplDecl { ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation CategoryNameLoc) - : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, - nameLoc, atStartLoc), - CategoryNameLoc(CategoryNameLoc) {} + : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, + nameLoc, atStartLoc), + CategoryNameLoc(CategoryNameLoc) {} + + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, ObjCInterfaceDecl *classInterface, @@ -2421,9 +2547,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCCategoryImpl;} - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID); @@ -2446,7 +2569,6 @@ raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID); /// we allow instance variables to be specified in the implementation. When /// specified, they need to be \em identical to the interface. class ObjCImplementationDecl : public ObjCImplDecl { - void anchor() override; /// Implementation Class's super class. ObjCInterfaceDecl *SuperClass; SourceLocation SuperLoc; @@ -2458,7 +2580,7 @@ class ObjCImplementationDecl : public ObjCImplDecl { /// Support for ivar initialization. /// \brief The arguments used to initialize the ivars LazyCXXCtorInitializersPtr IvarInitializers; - unsigned NumIvarInitializers; + unsigned NumIvarInitializers = 0; /// Do the ivars of this class require initialization other than /// zero-initialization? @@ -2474,15 +2596,20 @@ class ObjCImplementationDecl : public ObjCImplDecl { SourceLocation superLoc = SourceLocation(), SourceLocation IvarLBraceLoc=SourceLocation(), SourceLocation IvarRBraceLoc=SourceLocation()) - : ObjCImplDecl(ObjCImplementation, DC, classInterface, - classInterface ? classInterface->getIdentifier() - : nullptr, - nameLoc, atStartLoc), - SuperClass(superDecl), SuperLoc(superLoc), IvarLBraceLoc(IvarLBraceLoc), - IvarRBraceLoc(IvarRBraceLoc), - IvarInitializers(nullptr), NumIvarInitializers(0), - HasNonZeroConstructors(false), HasDestructors(false) {} + : ObjCImplDecl(ObjCImplementation, DC, classInterface, + classInterface ? classInterface->getIdentifier() + : nullptr, + nameLoc, atStartLoc), + SuperClass(superDecl), SuperLoc(superLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc), + HasNonZeroConstructors(false), HasDestructors(false) {} + + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl, @@ -2495,15 +2622,16 @@ public: static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// init_iterator - Iterates through the ivar initializer list. - typedef CXXCtorInitializer **init_iterator; + using init_iterator = CXXCtorInitializer **; /// init_const_iterator - Iterates through the ivar initializer list. - typedef CXXCtorInitializer * const * init_const_iterator; + using init_const_iterator = CXXCtorInitializer * const *; - typedef llvm::iterator_range<init_iterator> init_range; - typedef llvm::iterator_range<init_const_iterator> init_const_range; + using init_range = llvm::iterator_range<init_iterator>; + using init_const_range = llvm::iterator_range<init_const_iterator>; init_range inits() { return init_range(init_begin(), init_end()); } + init_const_range inits() const { return init_const_range(init_begin(), init_end()); } @@ -2513,6 +2641,7 @@ public: const auto *ConstThis = this; return const_cast<init_iterator>(ConstThis->init_begin()); } + /// begin() - Retrieve an iterator to the first initializer. init_const_iterator init_begin() const; @@ -2520,10 +2649,12 @@ public: init_iterator init_end() { return init_begin() + NumIvarInitializers; } + /// end() - Retrieve an iterator past the last initializer. init_const_iterator init_end() const { return init_begin() + NumIvarInitializers; } + /// getNumArgs - Number of ivars which must be initialized. unsigned getNumIvarInitializers() const { return NumIvarInitializers; @@ -2585,28 +2716,29 @@ public: void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } - typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; - typedef llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>> ivar_range; + using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>; + using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>; ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); } + ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); } + ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); } + unsigned ivar_size() const { return std::distance(ivar_begin(), ivar_end()); } + bool ivar_empty() const { return ivar_begin() == ivar_end(); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCImplementation; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID); @@ -2614,13 +2746,15 @@ raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID); /// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is /// declared as \@compatibility_alias alias class. class ObjCCompatibleAliasDecl : public NamedDecl { - void anchor() override; /// Class that this is an alias of. ObjCInterfaceDecl *AliasedClass; ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ObjCInterfaceDecl* aliasedClass) - : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} + : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} + + void anchor() override; + public: static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -2635,7 +2769,6 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; } - }; /// ObjCPropertyImplDecl - Represents implementation declaration of a property @@ -2648,6 +2781,7 @@ public: Synthesize, Dynamic }; + private: SourceLocation AtLoc; // location of \@synthesize or \@dynamic @@ -2667,24 +2801,25 @@ private: /// Null for \@dynamic. Non-null if property must be copy-constructed in /// getter. - Expr *GetterCXXConstructor; + Expr *GetterCXXConstructor = nullptr; /// Null for \@dynamic. Non-null if property has assignment operator to call /// in Setter synthesis. - Expr *SetterCXXAssignment; + Expr *SetterCXXAssignment = nullptr; ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, Kind PK, ObjCIvarDecl *ivarDecl, SourceLocation ivarLoc) - : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), - IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl), - GetterCXXConstructor(nullptr), SetterCXXAssignment(nullptr) { - assert (PK == Dynamic || PropertyIvarDecl); + : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), + IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl) { + assert(PK == Dynamic || PropertyIvarDecl); } public: + friend class ASTDeclReader; + static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, @@ -2733,6 +2868,7 @@ public: Expr *getGetterCXXConstructor() const { return GetterCXXConstructor; } + void setGetterCXXConstructor(Expr *getterCXXConstructor) { GetterCXXConstructor = getterCXXConstructor; } @@ -2740,14 +2876,13 @@ public: Expr *getSetterCXXAssignment() const { return SetterCXXAssignment; } + void setSetterCXXAssignment(Expr *setterCXXAssignment) { SetterCXXAssignment = setterCXXAssignment; } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } - - friend class ASTDeclReader; }; template<bool (*Filter)(ObjCCategoryDecl *)> @@ -2778,5 +2913,6 @@ inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) { return Cat->IsClassExtension(); } -} // end namespace clang -#endif +} // namespace clang + +#endif // LLVM_CLANG_AST_DECLOBJC_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h index 30ca79e9d0054..2a329c3732cb6 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclOpenMP.h @@ -100,12 +100,22 @@ public: /// /// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer. class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext { +public: + enum InitKind { + CallInit, // Initialized by function call. + DirectInit, // omp_priv(<expr>) + CopyInit // omp_priv = <expr> + }; + private: friend class ASTDeclReader; /// \brief Combiner for declare reduction construct. Expr *Combiner; /// \brief Initializer for declare reduction construct. Expr *Initializer; + /// Kind of initializer - function call or omp_priv<init_expr> initializtion. + InitKind InitializerKind = CallInit; + /// \brief Reference to the previous declare reduction construct in the same /// scope with the same name. Required for proper templates instantiation if /// the declare reduction construct is declared inside compound statement. @@ -117,7 +127,8 @@ private: DeclarationName Name, QualType Ty, OMPDeclareReductionDecl *PrevDeclInScope) : ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), Combiner(nullptr), - Initializer(nullptr), PrevDeclInScope(PrevDeclInScope) {} + Initializer(nullptr), InitializerKind(CallInit), + PrevDeclInScope(PrevDeclInScope) {} void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) { PrevDeclInScope = Prev; @@ -142,8 +153,13 @@ public: /// construct. Expr *getInitializer() { return Initializer; } const Expr *getInitializer() const { return Initializer; } + /// Get initializer kind. + InitKind getInitializerKind() const { return InitializerKind; } /// \brief Set initializer expression for the declare reduction construct. - void setInitializer(Expr *E) { Initializer = E; } + void setInitializer(Expr *E, InitKind IK) { + Initializer = E; + InitializerKind = IK; + } /// \brief Get reference to previous declare reduction construct in the same /// scope with the same name. diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h index 2879452f24046..7842d70971747 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h @@ -1,4 +1,4 @@ -//===-- DeclTemplate.h - Classes for representing C++ templates -*- C++ -*-===// +//===- DeclTemplate.h - Classes for representing C++ templates --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,42 +6,60 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the C++ template declaration subclasses. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLTEMPLATE_H #define LLVM_CLANG_AST_DECLTEMPLATE_H +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> #include <utility> namespace clang { enum BuiltinTemplateKind : int; -class TemplateParameterList; -class TemplateDecl; -class RedeclarableTemplateDecl; -class FunctionTemplateDecl; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; -class TemplateTypeParmDecl; +class Expr; +class FunctionTemplateDecl; +class IdentifierInfo; class NonTypeTemplateParmDecl; +class TemplateDecl; class TemplateTemplateParmDecl; -class TypeAliasTemplateDecl; +class TemplateTypeParmDecl; +class UnresolvedSetImpl; class VarTemplateDecl; class VarTemplatePartialSpecializationDecl; /// \brief Stores a template parameter of any kind. -typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, - TemplateTemplateParmDecl*> TemplateParameter; +using TemplateParameter = + llvm::PointerUnion3<TemplateTypeParmDecl *, NonTypeTemplateParmDecl *, + TemplateTemplateParmDecl *>; NamedDecl *getAsNamedDecl(TemplateParameter P); @@ -50,7 +68,6 @@ NamedDecl *getAsNamedDecl(TemplateParameter P); class TemplateParameterList final : private llvm::TrailingObjects<TemplateParameterList, NamedDecl *, Expr *> { - /// The location of the 'template' keyword. SourceLocation TemplateLoc; @@ -69,6 +86,10 @@ class TemplateParameterList final unsigned HasRequiresClause : 1; protected: + TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, + Expr *RequiresClause); + size_t numTrailingObjects(OverloadToken<NamedDecl *>) const { return NumParams; } @@ -77,11 +98,11 @@ protected: return HasRequiresClause; } - TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, - Expr *RequiresClause); - public: + template <size_t N, bool HasRequiresClause> + friend class FixedSizeTemplateParameterListStorage; + friend TrailingObjects; + static TemplateParameterList *Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -90,10 +111,10 @@ public: Expr *RequiresClause); /// \brief Iterates through the template parameters in this list. - typedef NamedDecl** iterator; + using iterator = NamedDecl **; /// \brief Iterates through the template parameters in this list. - typedef NamedDecl* const* const_iterator; + using const_iterator = NamedDecl * const *; iterator begin() { return getTrailingObjects<NamedDecl *>(); } const_iterator begin() const { return getTrailingObjects<NamedDecl *>(); } @@ -113,7 +134,6 @@ public: assert(Idx < size() && "Template parameter index out-of-range"); return begin()[Idx]; } - const NamedDecl* getParam(unsigned Idx) const { assert(Idx < size() && "Template parameter index out-of-range"); return begin()[Idx]; @@ -157,11 +177,6 @@ public: return SourceRange(TemplateLoc, RAngleLoc); } - friend TrailingObjects; - - template <size_t N, bool HasRequiresClause> - friend class FixedSizeTemplateParameterListStorage; - public: // FIXME: workaround for MSVC 2013; remove when no longer needed using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner; @@ -201,14 +216,16 @@ class TemplateArgumentList final /// argument list. unsigned NumArguments; - TemplateArgumentList(const TemplateArgumentList &Other) = delete; - void operator=(const TemplateArgumentList &Other) = delete; - // Constructs an instance with an internal Argument list, containing // a copy of the Args array. (Called by CreateCopy) TemplateArgumentList(ArrayRef<TemplateArgument> Args); public: + friend TrailingObjects; + + TemplateArgumentList(const TemplateArgumentList &) = delete; + TemplateArgumentList &operator=(const TemplateArgumentList &) = delete; + /// \brief Type used to indicate that the template argument list itself is a /// stack object. It does not own its template arguments. enum OnStackType { OnStack }; @@ -254,8 +271,6 @@ public: /// \brief Retrieve a pointer to the template argument list. const TemplateArgument *data() const { return Arguments; } - - friend TrailingObjects; }; void *allocateDefaultArgStorageChain(const ASTContext &C); @@ -297,9 +312,11 @@ public: /// Determine whether there is a default argument for this parameter. bool isSet() const { return !ValueOrInherited.isNull(); } + /// Determine whether the default argument for this parameter was inherited /// from a previous declaration of the same entity. bool isInherited() const { return ValueOrInherited.template is<ParmDecl*>(); } + /// Get the default argument's value. This does not consider whether the /// default argument is visible. ArgType get() const { @@ -310,6 +327,7 @@ public: return C->Value; return Storage->ValueOrInherited.template get<ArgType>(); } + /// Get the parameter from which we inherit the default argument, if any. /// This is the parameter on which the default argument was actually written. const ParmDecl *getInheritedFrom() const { @@ -319,11 +337,13 @@ public: return C->PrevDeclWithDefaultArg; return nullptr; } + /// Set the default argument. void set(ArgType Arg) { assert(!isSet() && "default argument already set"); ValueOrInherited = Arg; } + /// Set that the default argument was inherited from another parameter. void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) { assert(!isInherited() && "default argument already inherited"); @@ -334,6 +354,7 @@ public: ValueOrInherited = new (allocateDefaultArgStorageChain(C)) Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()}; } + /// Remove the default argument, even if it was inherited. void clear() { ValueOrInherited = ArgType(); @@ -350,7 +371,7 @@ class ConstrainedTemplateDeclInfo { friend TemplateDecl; public: - ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {} + ConstrainedTemplateDeclInfo() = default; TemplateParameterList *getTemplateParameters() const { return TemplateParams; @@ -365,8 +386,8 @@ protected: void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; } - TemplateParameterList *TemplateParams; - Expr *AssociatedConstraints; + TemplateParameterList *TemplateParams = nullptr; + Expr *AssociatedConstraints = nullptr; }; @@ -377,13 +398,14 @@ protected: /// reference to the templated scoped declaration: the underlying AST node. class TemplateDecl : public NamedDecl { void anchor() override; + protected: // Construct a template decl with the given name and parameters. // Used when there is no templated element (e.g., for tt-params). TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false), + : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), TemplateParams(CTDI) { this->setTemplateParameters(Params); } @@ -396,7 +418,7 @@ protected: TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false), + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), TemplateParams(CTDI) { this->setTemplateParameters(Params); } @@ -428,31 +450,22 @@ public: } /// Get the underlying, templated declaration. - NamedDecl *getTemplatedDecl() const { return TemplatedDecl.getPointer(); } + NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstTemplate && K <= lastTemplate; } SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(getTemplateParameters()->getTemplateLoc(), - TemplatedDecl.getPointer()->getSourceRange().getEnd()); + TemplatedDecl->getSourceRange().getEnd()); } - /// Whether this is a (C++ Concepts TS) function or variable concept. - bool isConcept() const { return TemplatedDecl.getInt(); } - void setConcept() { TemplatedDecl.setInt(true); } - protected: - /// \brief The named declaration from which this template was instantiated. - /// (or null). - /// - /// The boolean value will be true to indicate that this template - /// (function or variable) is a concept. - llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl; - + NamedDecl *TemplatedDecl; /// \brief The template parameter list and optional requires-clause /// associated with this declaration; alternatively, a /// \c ConstrainedTemplateDeclInfo if the associated constraints of the @@ -481,9 +494,9 @@ public: /// \brief Initialize the underlying templated declaration and /// template parameters. void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) { - assert(!TemplatedDecl.getPointer() && "TemplatedDecl already set!"); + assert(!TemplatedDecl && "TemplatedDecl already set!"); assert(!TemplateParams && "TemplateParams already set!"); - TemplatedDecl.setPointer(templatedDecl); + TemplatedDecl = templatedDecl; TemplateParams = templateParams; } }; @@ -498,11 +511,10 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { const TemplateArgumentList *TemplateArgs, const ASTTemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI) - : Function(FD), - Template(Template, TSK - 1), - TemplateArguments(TemplateArgs), - TemplateArgumentsAsWritten(TemplateArgsAsWritten), - PointOfInstantiation(POI) { } + : Function(FD), Template(Template, TSK - 1), + TemplateArguments(TemplateArgs), + TemplateArgumentsAsWritten(TemplateArgsAsWritten), + PointOfInstantiation(POI) {} public: static FunctionTemplateSpecializationInfo * @@ -604,7 +616,7 @@ public: explicit MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK, SourceLocation POI = SourceLocation()) - : MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) { + : MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) { assert(TSK != TSK_Undeclared && "Cannot encode undeclared template specializations for members"); } @@ -681,6 +693,8 @@ class DependentFunctionTemplateSpecializationInfo final const TemplateArgumentListInfo &TemplateArgs); public: + friend TrailingObjects; + static DependentFunctionTemplateSpecializationInfo * Create(ASTContext &Context, const UnresolvedSetImpl &Templates, const TemplateArgumentListInfo &TemplateArgs); @@ -716,32 +730,34 @@ public: SourceLocation getRAngleLoc() const { return AngleLocs.getEnd(); } - - friend TrailingObjects; }; /// Declaration of a redeclarable template. class RedeclarableTemplateDecl : public TemplateDecl, public Redeclarable<RedeclarableTemplateDecl> { - typedef Redeclarable<RedeclarableTemplateDecl> redeclarable_base; + using redeclarable_base = Redeclarable<RedeclarableTemplateDecl>; + RedeclarableTemplateDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } + RedeclarableTemplateDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } + RedeclarableTemplateDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } protected: template <typename EntryType> struct SpecEntryTraits { - typedef EntryType DeclType; + using DeclType = EntryType; static DeclType *getDecl(EntryType *D) { return D; } + static ArrayRef<TemplateArgument> getTemplateArgs(EntryType *D) { return D->getTemplateArgs().asArray(); } @@ -756,7 +772,7 @@ protected: typename std::iterator_traits<typename llvm::FoldingSetVector< EntryType>::iterator>::iterator_category, DeclType *, ptrdiff_t, DeclType *, DeclType *> { - SpecIterator() {} + SpecIterator() = default; explicit SpecIterator( typename llvm::FoldingSetVector<EntryType>::iterator SetIter) : SpecIterator::iterator_adaptor_base(std::move(SetIter)) {} @@ -764,6 +780,7 @@ protected: DeclType *operator*() const { return SETraits::getDecl(&*this->I)->getMostRecentDecl(); } + DeclType *operator->() const { return **this; } }; @@ -773,6 +790,8 @@ protected: return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); } + void loadLazySpecializationsImpl() const; + template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType* findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args, void *&InsertPos); @@ -782,7 +801,7 @@ protected: EntryType *Entry, void *InsertPos); struct CommonBase { - CommonBase() : InstantiatedFromMember(nullptr, false) { } + CommonBase() : InstantiatedFromMember(nullptr, false) {} /// \brief The template from which this was most /// directly instantiated (or null). @@ -791,11 +810,18 @@ protected: /// was explicitly specialized. llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool> InstantiatedFromMember; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known only by their external declaration IDs. + /// + /// The first value in the array is the number of specializations/partial + /// specializations that follow. + uint32_t *LazySpecializations = nullptr; }; /// \brief Pointer to the common data shared by all declarations of this /// template. - mutable CommonBase *Common; + mutable CommonBase *Common = nullptr; /// \brief Retrieves the "common" pointer shared by all (re-)declarations of /// the same template. Calling this routine may implicitly allocate memory @@ -809,8 +835,8 @@ protected: ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) - : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C), - Common() {} + : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C) + {} RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, @@ -818,6 +844,9 @@ protected: : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {} public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; template <class decl_type> friend class RedeclarableTemplate; /// \brief Retrieves the canonical declaration of this template. @@ -858,7 +887,7 @@ public: } /// \brief Retrieve the member template from which this template was - /// instantiated, or NULL if this template was not instantiated from a + /// instantiated, or nullptr if this template was not instantiated from a /// member template. /// /// A template is instantiated from a member template when the member @@ -902,8 +931,9 @@ public: getCommonPtr()->InstantiatedFromMember.setPointer(TD); } - typedef redeclarable_base::redecl_range redecl_range; - typedef redeclarable_base::redecl_iterator redecl_iterator; + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::redecls; @@ -913,22 +943,20 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate; } - - friend class ASTReader; - friend class ASTDeclReader; - friend class ASTDeclWriter; }; template <> struct RedeclarableTemplateDecl:: SpecEntryTraits<FunctionTemplateSpecializationInfo> { - typedef FunctionDecl DeclType; + using DeclType = FunctionDecl; static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) { return I->Function; } + static ArrayRef<TemplateArgument> getTemplateArgs(FunctionTemplateSpecializationInfo *I) { return I->TemplateArguments->asArray(); @@ -938,11 +966,11 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> { /// Declaration of a template function. class FunctionTemplateDecl : public RedeclarableTemplateDecl { protected: + friend class FunctionDecl; + /// \brief Data that is common to all of the declarations of a given /// function template. struct Common : CommonBase { - Common() : InjectedArgs(), LazySpecializations() { } - /// \brief The function template specializations for this function /// template, including explicit specializations and instantiations. llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> Specializations; @@ -954,14 +982,9 @@ protected: /// many template arguments as template parameaters) for the function /// template, and is allocated lazily, since most function templates do not /// require the use of this information. - TemplateArgument *InjectedArgs; + TemplateArgument *InjectedArgs = nullptr; - /// \brief If non-null, points to an array of specializations known only - /// by their external declaration IDs. - /// - /// The first value in the array is the number of of specializations - /// that follow. - uint32_t *LazySpecializations; + Common() = default; }; FunctionTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -976,8 +999,6 @@ protected: return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); } - friend class FunctionDecl; - /// \brief Retrieve the set of function template specializations of this /// function template. llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> & @@ -991,12 +1012,15 @@ protected: void *InsertPos); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// \brief Load any lazily-loaded specializations from the external source. void LoadLazySpecializations() const; /// Get the underlying function declaration of the template. FunctionDecl *getTemplatedDecl() const { - return static_cast<FunctionDecl *>(TemplatedDecl.getPointer()); + return static_cast<FunctionDecl *>(TemplatedDecl); } /// Returns whether this template declaration defines the primary @@ -1020,14 +1044,11 @@ public: } /// \brief Retrieve the previous declaration of this function template, or - /// NULL if no such declaration exists. + /// nullptr if no such declaration exists. FunctionTemplateDecl *getPreviousDecl() { return cast_or_null<FunctionTemplateDecl>( static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); } - - /// \brief Retrieve the previous declaration of this function template, or - /// NULL if no such declaration exists. const FunctionTemplateDecl *getPreviousDecl() const { return cast_or_null<FunctionTemplateDecl>( static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl()); @@ -1047,12 +1068,13 @@ public: RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); } - typedef SpecIterator<FunctionTemplateSpecializationInfo> spec_iterator; - typedef llvm::iterator_range<spec_iterator> spec_range; + using spec_iterator = SpecIterator<FunctionTemplateSpecializationInfo>; + using spec_range = llvm::iterator_range<spec_iterator>; spec_range specializations() const { return spec_range(spec_begin(), spec_end()); } + spec_iterator spec_begin() const { return makeSpecIterator(getSpecializations(), false); } @@ -1083,9 +1105,6 @@ public: // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == FunctionTemplate; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; //===----------------------------------------------------------------------===// @@ -1102,19 +1121,17 @@ public: /// This class is inheritedly privately by different kinds of template /// parameters and is not part of the Decl hierarchy. Just a facility. class TemplateParmPosition { - TemplateParmPosition() = delete; - protected: - TemplateParmPosition(unsigned D, unsigned P) - : Depth(D), Position(P) - { } - // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for // position? Maybe? unsigned Depth; unsigned Position; + TemplateParmPosition(unsigned D, unsigned P) : Depth(D), Position(P) {} + public: + TemplateParmPosition() = delete; + /// Get the nesting depth of the template parameter. unsigned getDepth() const { return Depth; } void setDepth(unsigned D) { Depth = D; } @@ -1134,6 +1151,9 @@ public: /// template<typename T> class vector; /// \endcode class TemplateTypeParmDecl : public TypeDecl { + /// Sema creates these on the stack during auto type deduction. + friend class Sema; + /// \brief Whether this template type parameter was declaration with /// the 'typename' keyword. /// @@ -1141,18 +1161,14 @@ class TemplateTypeParmDecl : public TypeDecl { bool Typename : 1; /// \brief The default template argument, if any. - typedef DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *> - DefArgStorage; + using DefArgStorage = + DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>; DefArgStorage DefaultArgument; TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, SourceLocation IdLoc, IdentifierInfo *Id, bool Typename) - : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename), - DefaultArgument() { } - - /// Sema creates these on the stack during auto type deduction. - friend class Sema; + : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename) {} public: static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, @@ -1199,6 +1215,7 @@ public: void setDefaultArgument(TypeSourceInfo *DefArg) { DefaultArgument.set(DefArg); } + /// \brief Set that this default argument was inherited from another /// parameter. void setInheritedDefaultArgument(const ASTContext &C, @@ -1241,9 +1258,12 @@ class NonTypeTemplateParmDecl final protected TemplateParmPosition, private llvm::TrailingObjects<NonTypeTemplateParmDecl, std::pair<QualType, TypeSourceInfo *>> { + friend class ASTDeclReader; + friend TrailingObjects; + /// \brief The default template argument, if any, and whether or not /// it was inherited. - typedef DefaultArgStorage<NonTypeTemplateParmDecl, Expr*> DefArgStorage; + using DefArgStorage = DefaultArgStorage<NonTypeTemplateParmDecl, Expr *>; DefArgStorage DefaultArgument; // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index @@ -1255,10 +1275,10 @@ class NonTypeTemplateParmDecl final /// \brief Whether this non-type template parameter is an "expanded" /// parameter pack, meaning that its type is a pack expansion and we /// already know the set of types that expansion expands to. - bool ExpandedParameterPack; + bool ExpandedParameterPack = false; /// \brief The number of types in an expanded parameter pack. - unsigned NumExpandedTypes; + unsigned NumExpandedTypes = 0; size_t numTrailingObjects( OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const { @@ -1269,10 +1289,8 @@ class NonTypeTemplateParmDecl final SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo) - : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), - TemplateParmPosition(D, P), ParameterPack(ParameterPack), - ExpandedParameterPack(false), NumExpandedTypes(0) - { } + : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), + TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, @@ -1281,9 +1299,6 @@ class NonTypeTemplateParmDecl final ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos); - friend class ASTDeclReader; - friend TrailingObjects; - public: static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, @@ -1428,11 +1443,9 @@ class TemplateTemplateParmDecl final protected TemplateParmPosition, private llvm::TrailingObjects<TemplateTemplateParmDecl, TemplateParameterList *> { - void anchor() override; - /// \brief The default template argument, if any. - typedef DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *> - DefArgStorage; + using DefArgStorage = + DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>; DefArgStorage DefaultArgument; /// \brief Whether this parameter is a parameter pack. @@ -1441,25 +1454,29 @@ class TemplateTemplateParmDecl final /// \brief Whether this template template parameter is an "expanded" /// parameter pack, meaning that it is a pack expansion and we /// already know the set of template parameters that expansion expands to. - bool ExpandedParameterPack; + bool ExpandedParameterPack = false; /// \brief The number of parameters in an expanded parameter pack. - unsigned NumExpandedParams; + unsigned NumExpandedParams = 0; TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, TemplateParameterList *Params) - : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), ParameterPack(ParameterPack), - ExpandedParameterPack(false), NumExpandedParams(0) - { } + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, TemplateParameterList *Params, ArrayRef<TemplateParameterList *> Expansions); + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, @@ -1579,22 +1596,18 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TemplateTemplateParm; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; - friend TrailingObjects; }; /// \brief Represents the builtin template declaration which is used to /// implement __make_integer_seq and other builtin templates. It serves /// no real purpose beyond existing as a place to hold template parameters. class BuiltinTemplateDecl : public TemplateDecl { - void anchor() override; + BuiltinTemplateKind BTK; BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC, DeclarationName Name, BuiltinTemplateKind BTK); - BuiltinTemplateKind BTK; + void anchor() override; public: // Implement isa/cast/dyncast support @@ -1629,7 +1642,6 @@ public: /// \endcode class ClassTemplateSpecializationDecl : public CXXRecordDecl, public llvm::FoldingSetNode { - /// \brief Structure that stores information about a class template /// specialization that was instantiated from a class template partial /// specialization. @@ -1650,19 +1662,20 @@ class ClassTemplateSpecializationDecl /// \brief Further info for explicit template specialization/instantiation. struct ExplicitSpecializationInfo { /// \brief The type-as-written. - TypeSourceInfo *TypeAsWritten; + TypeSourceInfo *TypeAsWritten = nullptr; + /// \brief The location of the extern keyword. SourceLocation ExternLoc; + /// \brief The location of the template keyword. SourceLocation TemplateKeywordLoc; - ExplicitSpecializationInfo() - : TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {} + ExplicitSpecializationInfo() = default; }; /// \brief Further info for explicit template specialization/instantiation. /// Does not apply to implicit specializations. - ExplicitSpecializationInfo *ExplicitInfo; + ExplicitSpecializationInfo *ExplicitInfo = nullptr; /// \brief The template arguments used to describe this specialization. const TemplateArgumentList *TemplateArgs; @@ -1685,6 +1698,9 @@ protected: explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ClassTemplateSpecializationDecl * Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -1828,6 +1844,7 @@ public: ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; ExplicitInfo->TypeAsWritten = T; } + /// \brief Gets the type of this specialization as it was written by /// the user, if it was so written. TypeSourceInfo *getTypeAsWritten() const { @@ -1838,6 +1855,7 @@ public: SourceLocation getExternLoc() const { return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); } + /// \brief Sets the location of the extern keyword. void setExternLoc(SourceLocation Loc) { if (!ExplicitInfo) @@ -1851,6 +1869,7 @@ public: ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; ExplicitInfo->TemplateKeywordLoc = Loc; } + /// \brief Gets the location of the template keyword, if present. SourceLocation getTemplateKeywordLoc() const { return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); @@ -1871,25 +1890,21 @@ public: } static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstClassTemplateSpecialization && K <= lastClassTemplateSpecialization; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; class ClassTemplatePartialSpecializationDecl : public ClassTemplateSpecializationDecl { - void anchor() override; - /// \brief The list of template parameters - TemplateParameterList* TemplateParams; + TemplateParameterList* TemplateParams = nullptr; /// \brief The source info for the template arguments as written. /// FIXME: redundant with TypeAsWritten? - const ASTTemplateArgumentListInfo *ArgsAsWritten; + const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; /// \brief The class template partial specialization from which this /// class template partial specialization was instantiated. @@ -1911,10 +1926,14 @@ class ClassTemplatePartialSpecializationDecl ClassTemplatePartialSpecializationDecl(ASTContext &C) : ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization), - TemplateParams(nullptr), ArgsAsWritten(nullptr), InstantiatedFromMember(nullptr, false) {} + void anchor() override; + public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static ClassTemplatePartialSpecializationDecl * Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -2024,12 +2043,10 @@ public: // FIXME: Add Profile support! static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ClassTemplatePartialSpecialization; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Declaration of a class template. @@ -2038,8 +2055,6 @@ protected: /// \brief Data that is common to all of the declarations of a given /// class template. struct Common : CommonBase { - Common() : LazySpecializations() { } - /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. llvm::FoldingSetVector<ClassTemplateSpecializationDecl> Specializations; @@ -2052,12 +2067,7 @@ protected: /// \brief The injected-class-name type for this class template. QualType InjectedClassNameType; - /// \brief If non-null, points to an array of specializations (including - /// partial specializations) known only by their external declaration IDs. - /// - /// The first value in the array is the number of of specializations/ - /// partial specializations that follow. - uint32_t *LazySpecializations; + Common() = default; }; /// \brief Retrieve the set of specializations of this class template. @@ -2087,12 +2097,15 @@ protected: } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// \brief Load any lazily-loaded specializations from the external source. void LoadLazySpecializations() const; /// \brief Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { - return static_cast<CXXRecordDecl *>(TemplatedDecl.getPointer()); + return static_cast<CXXRecordDecl *>(TemplatedDecl); } /// \brief Returns whether this template declaration defines the primary @@ -2132,14 +2145,11 @@ public: } /// \brief Retrieve the previous declaration of this class template, or - /// NULL if no such declaration exists. + /// nullptr if no such declaration exists. ClassTemplateDecl *getPreviousDecl() { return cast_or_null<ClassTemplateDecl>( static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); } - - /// \brief Retrieve the previous declaration of this class template, or - /// NULL if no such declaration exists. const ClassTemplateDecl *getPreviousDecl() const { return cast_or_null<ClassTemplateDecl>( static_cast<const RedeclarableTemplateDecl *>( @@ -2180,7 +2190,7 @@ public: /// template. /// /// \returns the class template partial specialization that exactly matches - /// the type \p T, or NULL if no such partial specialization exists. + /// the type \p T, or nullptr if no such partial specialization exists. ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T); /// \brief Find a class template partial specialization which was instantiated @@ -2189,8 +2199,8 @@ public: /// \param D a member class template partial specialization. /// /// \returns the class template partial specialization which was instantiated - /// from the given member partial specialization, or NULL if no such partial - /// specialization exists. + /// from the given member partial specialization, or nullptr if no such + /// partial specialization exists. ClassTemplatePartialSpecializationDecl * findPartialSpecInstantiatedFromMember( ClassTemplatePartialSpecializationDecl *D); @@ -2211,8 +2221,8 @@ public: /// \endcode QualType getInjectedClassNameSpecialization(); - typedef SpecIterator<ClassTemplateSpecializationDecl> spec_iterator; - typedef llvm::iterator_range<spec_iterator> spec_range; + using spec_iterator = SpecIterator<ClassTemplateSpecializationDecl>; + using spec_range = llvm::iterator_range<spec_iterator>; spec_range specializations() const { return spec_range(spec_begin(), spec_end()); @@ -2229,9 +2239,6 @@ public: // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ClassTemplate; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Declaration of a friend template. @@ -2249,15 +2256,16 @@ public: /// will yield a FriendDecl, not a FriendTemplateDecl. class FriendTemplateDecl : public Decl { virtual void anchor(); + public: - typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + using FriendUnion = llvm::PointerUnion<NamedDecl *,TypeSourceInfo *>; private: // The number of template parameters; always non-zero. - unsigned NumParams; + unsigned NumParams = 0; // The parameter list. - TemplateParameterList **Params; + TemplateParameterList **Params = nullptr; // The declaration that's a friend of this class. FriendUnion Friend; @@ -2271,13 +2279,11 @@ private: : Decl(Decl::FriendTemplate, DC, Loc), NumParams(Params.size()), Params(Params.data()), Friend(Friend), FriendLoc(FriendLoc) {} - FriendTemplateDecl(EmptyShell Empty) - : Decl(Decl::FriendTemplate, Empty), - NumParams(0), - Params(nullptr) - {} + FriendTemplateDecl(EmptyShell Empty) : Decl(Decl::FriendTemplate, Empty) {} public: + friend class ASTDeclReader; + static FriendTemplateDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc, MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend, @@ -2316,8 +2322,6 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::FriendTemplate; } - - friend class ASTDeclReader; }; /// \brief Declaration of an alias template. @@ -2328,7 +2332,7 @@ public: /// \endcode class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { protected: - typedef CommonBase Common; + using Common = CommonBase; TypeAliasTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, @@ -2343,9 +2347,12 @@ protected: } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// Get the underlying function declaration of the template. TypeAliasDecl *getTemplatedDecl() const { - return static_cast<TypeAliasDecl *>(TemplatedDecl.getPointer()); + return static_cast<TypeAliasDecl *>(TemplatedDecl); } @@ -2359,14 +2366,11 @@ public: } /// \brief Retrieve the previous declaration of this function template, or - /// NULL if no such declaration exists. + /// nullptr if no such declaration exists. TypeAliasTemplateDecl *getPreviousDecl() { return cast_or_null<TypeAliasTemplateDecl>( static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); } - - /// \brief Retrieve the previous declaration of this function template, or - /// NULL if no such declaration exists. const TypeAliasTemplateDecl *getPreviousDecl() const { return cast_or_null<TypeAliasTemplateDecl>( static_cast<const RedeclarableTemplateDecl *>( @@ -2378,7 +2382,6 @@ public: RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); } - /// \brief Create a function template node. static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -2392,9 +2395,6 @@ public: // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TypeAliasTemplate; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Declaration of a function specialization at template class scope. @@ -2414,7 +2414,9 @@ public: /// CXXMethodDecl. Then during an instantiation of class A, it will be /// transformed into an actual function specialization. class ClassScopeFunctionSpecializationDecl : public Decl { - virtual void anchor(); + CXXMethodDecl *Specialization; + bool HasExplicitTemplateArgs; + TemplateArgumentListInfo TemplateArgs; ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, bool Args, @@ -2424,13 +2426,14 @@ class ClassScopeFunctionSpecializationDecl : public Decl { TemplateArgs(std::move(TemplArgs)) {} ClassScopeFunctionSpecializationDecl(EmptyShell Empty) - : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} + : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} - CXXMethodDecl *Specialization; - bool HasExplicitTemplateArgs; - TemplateArgumentListInfo TemplateArgs; + virtual void anchor(); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + CXXMethodDecl *getSpecialization() const { return Specialization; } bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } const TemplateArgumentListInfo& templateArgs() const { return TemplateArgs; } @@ -2450,17 +2453,15 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::ClassScopeFunctionSpecialization; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Implementation of inline functions that require the template declarations inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) - : Function(FTD) { } + : Function(FTD) {} /// \brief Represents a variable template specialization, which refers to /// a variable template with a given set of template arguments. @@ -2498,19 +2499,20 @@ class VarTemplateSpecializationDecl : public VarDecl, /// \brief Further info for explicit template specialization/instantiation. struct ExplicitSpecializationInfo { /// \brief The type-as-written. - TypeSourceInfo *TypeAsWritten; + TypeSourceInfo *TypeAsWritten = nullptr; + /// \brief The location of the extern keyword. SourceLocation ExternLoc; + /// \brief The location of the template keyword. SourceLocation TemplateKeywordLoc; - ExplicitSpecializationInfo() - : TypeAsWritten(nullptr), ExternLoc(), TemplateKeywordLoc() {} + ExplicitSpecializationInfo() = default; }; /// \brief Further info for explicit template specialization/instantiation. /// Does not apply to implicit specializations. - ExplicitSpecializationInfo *ExplicitInfo; + ExplicitSpecializationInfo *ExplicitInfo = nullptr; /// \brief The template arguments used to describe this specialization. const TemplateArgumentList *TemplateArgs; @@ -2523,6 +2525,12 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Really a value of type TemplateSpecializationKind. unsigned SpecializationKind : 3; + /// \brief Whether this declaration is a complete definition of the + /// variable template specialization. We can't otherwise tell apart + /// an instantiated declaration from an instantiated definition with + /// no initializer. + unsigned IsCompleteDefinition : 1; + protected: VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -2534,6 +2542,10 @@ protected: explicit VarTemplateSpecializationDecl(Kind DK, ASTContext &Context); public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class VarDecl; + static VarTemplateSpecializationDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, @@ -2596,6 +2608,8 @@ public: PointOfInstantiation = Loc; } + void setCompleteDefinition() { IsCompleteDefinition = true; } + /// \brief If this variable template specialization is an instantiation of /// a template (rather than an explicit specialization), return the /// variable template or variable template partial specialization from which @@ -2668,6 +2682,7 @@ public: ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; ExplicitInfo->TypeAsWritten = T; } + /// \brief Gets the type of this specialization as it was written by /// the user, if it was so written. TypeSourceInfo *getTypeAsWritten() const { @@ -2678,6 +2693,7 @@ public: SourceLocation getExternLoc() const { return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); } + /// \brief Sets the location of the extern keyword. void setExternLoc(SourceLocation Loc) { if (!ExplicitInfo) @@ -2691,6 +2707,7 @@ public: ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; ExplicitInfo->TemplateKeywordLoc = Loc; } + /// \brief Gets the location of the template keyword, if present. SourceLocation getTemplateKeywordLoc() const { return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); @@ -2709,25 +2726,21 @@ public: } static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstVarTemplateSpecialization && K <= lastVarTemplateSpecialization; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; class VarTemplatePartialSpecializationDecl : public VarTemplateSpecializationDecl { - void anchor() override; - /// \brief The list of template parameters - TemplateParameterList *TemplateParams; + TemplateParameterList *TemplateParams = nullptr; /// \brief The source info for the template arguments as written. /// FIXME: redundant with TypeAsWritten? - const ASTTemplateArgumentListInfo *ArgsAsWritten; + const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; /// \brief The variable template partial specialization from which this /// variable template partial specialization was instantiated. @@ -2745,11 +2758,16 @@ class VarTemplatePartialSpecializationDecl const ASTTemplateArgumentListInfo *ArgInfos); VarTemplatePartialSpecializationDecl(ASTContext &Context) - : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context), - TemplateParams(nullptr), ArgsAsWritten(nullptr), - InstantiatedFromMember(nullptr, false) {} + : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, + Context), + InstantiatedFromMember(nullptr, false) {} + + void anchor() override; public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + static VarTemplatePartialSpecializationDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, @@ -2841,12 +2859,10 @@ public: } static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == VarTemplatePartialSpecialization; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// Declaration of a variable template. @@ -2855,8 +2871,6 @@ protected: /// \brief Data that is common to all of the declarations of a given /// variable template. struct Common : CommonBase { - Common() : LazySpecializations() {} - /// \brief The variable template specializations for this variable /// template, including explicit specializations and instantiations. llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations; @@ -2866,12 +2880,7 @@ protected: llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> PartialSpecializations; - /// \brief If non-null, points to an array of specializations (including - /// partial specializations) known ownly by their external declaration IDs. - /// - /// The first value in the array is the number of of specializations/ - /// partial specializations that follow. - uint32_t *LazySpecializations; + Common() = default; }; /// \brief Retrieve the set of specializations of this variable template. @@ -2895,12 +2904,15 @@ protected: } public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// \brief Load any lazily-loaded specializations from the external source. void LoadLazySpecializations() const; /// \brief Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { - return static_cast<VarDecl *>(TemplatedDecl.getPointer()); + return static_cast<VarDecl *>(TemplatedDecl); } /// \brief Returns whether this template declaration defines the primary @@ -2937,14 +2949,11 @@ public: } /// \brief Retrieve the previous declaration of this variable template, or - /// NULL if no such declaration exists. + /// nullptr if no such declaration exists. VarTemplateDecl *getPreviousDecl() { return cast_or_null<VarTemplateDecl>( static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl()); } - - /// \brief Retrieve the previous declaration of this variable template, or - /// NULL if no such declaration exists. const VarTemplateDecl *getPreviousDecl() const { return cast_or_null<VarTemplateDecl>( static_cast<const RedeclarableTemplateDecl *>( @@ -2986,13 +2995,13 @@ public: /// /// \returns the variable template partial specialization which was /// instantiated - /// from the given member partial specialization, or NULL if no such partial - /// specialization exists. + /// from the given member partial specialization, or nullptr if no such + /// partial specialization exists. VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember( VarTemplatePartialSpecializationDecl *D); - typedef SpecIterator<VarTemplateSpecializationDecl> spec_iterator; - typedef llvm::iterator_range<spec_iterator> spec_range; + using spec_iterator = SpecIterator<VarTemplateSpecializationDecl>; + using spec_range = llvm::iterator_range<spec_iterator>; spec_range specializations() const { return spec_range(spec_begin(), spec_end()); @@ -3009,9 +3018,6 @@ public: // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == VarTemplate; } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; inline NamedDecl *getAsNamedDecl(TemplateParameter P) { @@ -3032,6 +3038,6 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) { : nullptr; } -} /* end of namespace clang */ +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DECLTEMPLATE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h index 4eaae35778b93..3ff274bd6a7a1 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h @@ -1,4 +1,4 @@ -//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===// +//===- DeclVisitor.h - Visitor for Decl subclasses --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,27 +10,30 @@ // This file defines the DeclVisitor interface. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_AST_DECLVISITOR_H #define LLVM_CLANG_AST_DECLVISITOR_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" +#include "llvm/Support/ErrorHandling.h" namespace clang { + namespace declvisitor { -template <typename T> struct make_ptr { typedef T *type; }; -template <typename T> struct make_const_ptr { typedef const T *type; }; +template <typename T> struct make_ptr { using type = T *; }; +template <typename T> struct make_const_ptr { using type = const T *; }; /// \brief A simple visitor class that helps create declaration visitors. template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> class Base { public: - #define PTR(CLASS) typename Ptr<CLASS>::type #define DISPATCH(NAME, CLASS) \ return static_cast<ImplClass*>(this)->Visit##NAME(static_cast<PTR(CLASS)>(D)) @@ -57,23 +60,23 @@ public: #undef DISPATCH }; -} // end namespace declvisitor +} // namespace declvisitor /// \brief A simple visitor class that helps create declaration visitors. /// /// 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> {}; /// \brief 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> {}; -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_AST_DECLVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h index 5e773c9683847..467b02c52b0c9 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h @@ -1,4 +1,4 @@ -//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===// +//===- DeclarationName.h - Representation of declaration names --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,36 +10,42 @@ // This file declares the DeclarationName and DeclarationNameTable classes. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_AST_DECLARATIONNAME_H #define LLVM_CLANG_AST_DECLARATIONNAME_H +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/Compiler.h" - -namespace llvm { - template <typename T> struct DenseMapInfo; -} +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstdint> +#include <cstring> +#include <string> namespace clang { - class ASTContext; - class CXXDeductionGuideNameExtra; - class CXXLiteralOperatorIdName; - class CXXOperatorIdName; - class CXXSpecialName; - class DeclarationNameExtra; - class IdentifierInfo; - class MultiKeywordSelector; - enum OverloadedOperatorKind : int; - struct PrintingPolicy; - class QualType; - class TemplateDecl; - class Type; - class TypeSourceInfo; - class UsingDirectiveDecl; - template <typename> class CanQual; - typedef CanQual<Type> CanQualType; +class ASTContext; +template <typename> class CanQual; +class CXXDeductionGuideNameExtra; +class CXXLiteralOperatorIdName; +class CXXOperatorIdName; +class CXXSpecialName; +class DeclarationNameExtra; +class IdentifierInfo; +class MultiKeywordSelector; +enum OverloadedOperatorKind : int; +struct PrintingPolicy; +class QualType; +class TemplateDecl; +class Type; +class TypeSourceInfo; +class UsingDirectiveDecl; + +using CanQualType = CanQual<Type>; /// DeclarationName - The name of a declaration. In the common case, /// this just stores an IdentifierInfo pointer to a normal @@ -63,9 +69,13 @@ public: CXXLiteralOperatorName, CXXUsingDirective }; + static const unsigned NumNameKinds = CXXUsingDirective + 1; private: + friend class DeclarationNameTable; + friend class NamedDecl; + /// StoredNameKind - The kind of name that is actually stored in the /// upper bits of the Ptr field. This is only used internally. /// @@ -99,7 +109,18 @@ private: /// DeclarationNameExtra structure, whose first value will tell us /// whether this is an Objective-C selector, C++ operator-id name, /// or special C++ name. - uintptr_t Ptr; + uintptr_t Ptr = 0; + + // Construct a declaration name from the name of a C++ constructor, + // destructor, or conversion function. + DeclarationName(DeclarationNameExtra *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra"); + Ptr |= StoredDeclarationNameExtra; + } + + /// Construct a declaration name from a raw pointer. + DeclarationName(uintptr_t Ptr) : Ptr(Ptr) {} /// getStoredNameKind - Return the kind of object that is stored in /// Ptr. @@ -146,36 +167,22 @@ private: return nullptr; } - // Construct a declaration name from the name of a C++ constructor, - // destructor, or conversion function. - DeclarationName(DeclarationNameExtra *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra"); - Ptr |= StoredDeclarationNameExtra; - } - - /// Construct a declaration name from a raw pointer. - DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } - - friend class DeclarationNameTable; - friend class NamedDecl; - /// getFETokenInfoAsVoidSlow - Retrieves the front end-specified pointer /// for this name as a void pointer if it's not an identifier. void *getFETokenInfoAsVoidSlow() const; public: /// DeclarationName - Used to create an empty selector. - DeclarationName() : Ptr(0) { } + DeclarationName() = default; // Construct a declaration name from an IdentifierInfo *. DeclarationName(const IdentifierInfo *II) - : Ptr(reinterpret_cast<uintptr_t>(II)) { + : Ptr(reinterpret_cast<uintptr_t>(II)) { assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); } // Construct a declaration name from an Objective-C selector. - DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) { } + DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) {} /// getUsingDirectiveName - Return name for all using-directives. static DeclarationName getUsingDirectiveName(); @@ -344,16 +351,24 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { /// getCXXConstructorName). class DeclarationNameTable { const ASTContext &Ctx; - void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * - CXXOperatorIdName *CXXOperatorNames; // Operator names - void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* - void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> * - DeclarationNameTable(const DeclarationNameTable&) = delete; - void operator=(const DeclarationNameTable&) = delete; + // Actually a FoldingSet<CXXSpecialName> * + void *CXXSpecialNamesImpl; + + // Operator names + CXXOperatorIdName *CXXOperatorNames; + + // Actually a CXXOperatorIdName* + void *CXXLiteralOperatorNames; + + // FoldingSet<CXXDeductionGuideNameExtra> * + void *CXXDeductionGuideNames; public: DeclarationNameTable(const ASTContext &C); + DeclarationNameTable(const DeclarationNameTable &) = delete; + DeclarationNameTable &operator=(const DeclarationNameTable &) = delete; + ~DeclarationNameTable(); /// getIdentifier - Create a declaration name that is a simple @@ -428,10 +443,10 @@ struct DeclarationNameLoc { }; DeclarationNameLoc(DeclarationName Name); + // FIXME: this should go away once all DNLocs are properly initialized. DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); } -}; // struct DeclarationNameLoc - +}; /// DeclarationNameInfo - A collector data type for bundling together /// a DeclarationName and the correspnding source/type location info. @@ -439,29 +454,33 @@ struct DeclarationNameInfo { private: /// Name - The declaration name, also encoding name kind. DeclarationName Name; + /// Loc - The main source location for the declaration name. SourceLocation NameLoc; + /// Info - Further source/type location info for special kinds of names. DeclarationNameLoc LocInfo; public: // FIXME: remove it. - DeclarationNameInfo() {} + DeclarationNameInfo() = default; DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc) - : Name(Name), NameLoc(NameLoc), LocInfo(Name) {} + : Name(Name), NameLoc(NameLoc), LocInfo(Name) {} DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc, DeclarationNameLoc LocInfo) - : Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {} + : Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {} /// getName - Returns the embedded declaration name. DeclarationName getName() const { return Name; } + /// setName - Sets the embedded declaration name. void setName(DeclarationName N) { Name = N; } /// getLoc - Returns the main location of the declaration name. SourceLocation getLoc() const { return NameLoc; } + /// setLoc - Sets the main location of the declaration name. void setLoc(SourceLocation L) { NameLoc = L; } @@ -477,6 +496,7 @@ public: Name.getNameKind() == DeclarationName::CXXConversionFunctionName); return LocInfo.NamedType.TInfo; } + /// setNamedTypeInfo - Sets the source type info associated to /// the name. Assumes it is a constructor, destructor or conversion. void setNamedTypeInfo(TypeSourceInfo *TInfo) { @@ -495,6 +515,7 @@ public: SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc) ); } + /// setCXXOperatorNameRange - Sets the range of the operator name /// (without the operator keyword). Assumes it is a C++ operator. void setCXXOperatorNameRange(SourceRange R) { @@ -511,6 +532,7 @@ public: return SourceLocation:: getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc); } + /// setCXXLiteralOperatorNameLoc - Sets the location of the literal /// operator name (not the operator keyword). /// Assumes it is a literal operator. @@ -534,15 +556,19 @@ public: /// getBeginLoc - Retrieve the location of the first token. SourceLocation getBeginLoc() const { return NameLoc; } + /// getEndLoc - Retrieve the location of the last token. SourceLocation getEndLoc() const; + /// getSourceRange - The range of the declaration name. SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocStart(), getLocEnd()); } + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { SourceLocation EndLoc = getEndLoc(); return EndLoc.isValid() ? EndLoc : getLocStart(); @@ -573,9 +599,10 @@ inline raw_ostream &operator<<(raw_ostream &OS, return OS; } -} // end namespace clang +} // namespace clang namespace llvm { + /// Define DenseMapInfo so that DeclarationNames can be used as keys /// in DenseMap and DenseSets. template<> @@ -601,6 +628,6 @@ struct DenseMapInfo<clang::DeclarationName> { template <> struct isPodLike<clang::DeclarationName> { static const bool value = true; }; -} // end namespace llvm +} // namespace llvm -#endif +#endif // LLVM_CLANG_AST_DECLARATIONNAME_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h index 8e038c83c9890..a514326c6cb10 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h @@ -1,4 +1,4 @@ -//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=// +//==- DependentDiagnostic.h - Dependently-generated diagnostics --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -23,6 +23,9 @@ #include "clang/AST/Type.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include <cassert> +#include <iterator> namespace clang { @@ -94,6 +97,9 @@ public: } private: + friend class DeclContext::ddiag_iterator; + friend class DependentStoredDeclsMap; + DependentDiagnostic(const PartialDiagnostic &PDiag, PartialDiagnostic::Storage *Storage) : Diag(PDiag, Storage) {} @@ -102,8 +108,6 @@ private: DeclContext *Parent, const PartialDiagnostic &PDiag); - friend class DependentStoredDeclsMap; - friend class DeclContext::ddiag_iterator; DependentDiagnostic *NextDiagnostic; PartialDiagnostic Diag; @@ -118,19 +122,17 @@ private: } AccessData; }; -/// - /// An iterator over the dependent diagnostics in a dependent context. class DeclContext::ddiag_iterator { public: - ddiag_iterator() : Ptr(nullptr) {} + ddiag_iterator() = default; explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {} - typedef DependentDiagnostic *value_type; - typedef DependentDiagnostic *reference; - typedef DependentDiagnostic *pointer; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = DependentDiagnostic *; + using reference = DependentDiagnostic *; + using pointer = DependentDiagnostic *; + using difference_type = int; + using iterator_category = std::forward_iterator_tag; reference operator*() const { return Ptr; } @@ -168,7 +170,7 @@ public: } private: - DependentDiagnostic *Ptr; + DependentDiagnostic *Ptr = nullptr; }; inline DeclContext::ddiag_range DeclContext::ddiags() const { @@ -184,6 +186,6 @@ inline DeclContext::ddiag_range DeclContext::ddiags() const { return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator()); } -} +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Expr.h b/contrib/llvm/tools/clang/include/clang/AST/Expr.h index 0cdbd2a97ee4f..f2770940372fd 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Expr.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Expr.h @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SyncScope.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" @@ -274,6 +275,7 @@ public: MLV_LValueCast, // Specialized form of MLV_InvalidExpression. MLV_IncompleteType, MLV_ConstQualified, + MLV_ConstQualifiedField, MLV_ConstAddrSpace, MLV_ArrayType, MLV_NoSetterProperty, @@ -323,6 +325,7 @@ public: CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext CM_NoSetterProperty,// Implicit assignment to ObjC property without setter CM_ConstQualified, + CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, CM_IncompleteType @@ -2345,6 +2348,12 @@ public: SourceLocation getLocStart() const LLVM_READONLY; SourceLocation getLocEnd() const LLVM_READONLY; + bool isCallToStdMove() const { + const FunctionDecl* FD = getDirectCallee(); + return getNumArgs() == 1 && FD && FD->isInStdNamespace() && + FD->getIdentifier() && FD->getIdentifier()->isStr("move"); + } + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && T->getStmtClass() <= lastCallExprConstant; @@ -2733,7 +2742,6 @@ protected: ty->containsUnexpandedParameterPack()) || (op && op->containsUnexpandedParameterPack()))), Op(op) { - assert(kind != CK_Invalid && "creating cast with invalid cast kind"); CastExprBits.Kind = kind; setBasePathSize(BasePathSize); assert(CastConsistency()); @@ -2771,6 +2779,16 @@ public: path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_end() const { return path_buffer() + path_size(); } + const FieldDecl *getTargetUnionField() const { + assert(getCastKind() == CK_ToUnion); + return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType()); + } + + static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, + QualType opType); + static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, + QualType opType); + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCastExprConstant && T->getStmtClass() <= lastCastExprConstant; @@ -3054,7 +3072,7 @@ public: static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; } bool isEqualityOp() const { return isEqualityOp(getOpcode()); } - static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; } + static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; } bool isComparisonOp() const { return isComparisonOp(getOpcode()); } static Opcode negateComparisonOp(Opcode Opc) { @@ -3113,6 +3131,12 @@ public: return isShiftAssignOp(getOpcode()); } + // Return true if a binary operator using the specified opcode and operands + // would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized + // integer to a pointer. + static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, + Expr *LHS, Expr *RHS); + static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && S->getStmtClass() <= lastBinaryOperatorConstant; @@ -3986,6 +4010,10 @@ public: /// initializer)? bool isTransparent() const; + /// Is this the zero initializer {0} in a language which considers it + /// idiomatic? + bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const; + SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } @@ -3995,6 +4023,9 @@ public: InitListExpr *getSemanticForm() const { return isSemanticForm() ? nullptr : AltForm.getPointer(); } + bool isSyntacticForm() const { + return !AltForm.getInt() || !AltForm.getPointer(); + } InitListExpr *getSyntacticForm() const { return isSemanticForm() ? AltForm.getPointer() : nullptr; } @@ -5064,9 +5095,11 @@ public: /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the -/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>. -/// All of these instructions take one primary pointer and at least one memory -/// order. +/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>, +/// and corresponding __opencl_atomic_* for OpenCL 2.0. +/// All of these instructions take one primary pointer, at least one memory +/// order. The instructions for which getScopeModel returns non-null value +/// take one synch scope. class AtomicExpr : public Expr { public: enum AtomicOp { @@ -5078,14 +5111,16 @@ public: }; private: + /// \brief Location of sub-expressions. + /// The location of Scope sub-expression is NumSubExprs - 1, which is + /// not fixed, therefore is not defined in enum. enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; - Stmt* SubExprs[END_EXPR]; + Stmt *SubExprs[END_EXPR + 1]; unsigned NumSubExprs; SourceLocation BuiltinLoc, RParenLoc; AtomicOp Op; friend class ASTStmtReader; - public: AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t, AtomicOp op, SourceLocation RP); @@ -5103,8 +5138,12 @@ public: Expr *getOrder() const { return cast<Expr>(SubExprs[ORDER]); } + Expr *getScope() const { + assert(getScopeModel() && "No scope"); + return cast<Expr>(SubExprs[NumSubExprs - 1]); + } Expr *getVal1() const { - if (Op == AO__c11_atomic_init) + if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init) return cast<Expr>(SubExprs[ORDER]); assert(NumSubExprs > VAL1); return cast<Expr>(SubExprs[VAL1]); @@ -5123,6 +5162,7 @@ public: assert(NumSubExprs > WEAK); return cast<Expr>(SubExprs[WEAK]); } + QualType getValueType() const; AtomicOp getOp() const { return Op; } unsigned getNumSubExprs() const { return NumSubExprs; } @@ -5139,10 +5179,17 @@ public: bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__opencl_atomic_compare_exchange_strong || + getOp() == AO__opencl_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || getOp() == AO__atomic_compare_exchange_n; } + bool isOpenCL() const { + return getOp() >= AO__opencl_atomic_init && + getOp() <= AO__opencl_atomic_fetch_max; + } + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -5160,6 +5207,24 @@ public: const_child_range children() const { return const_child_range(SubExprs, SubExprs + NumSubExprs); } + + /// \brief Get atomic scope model for the atomic op code. + /// \return empty atomic scope model if the atomic op code does not have + /// scope operand. + static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) { + auto Kind = + (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) + ? AtomicScopeModelKind::OpenCL + : AtomicScopeModelKind::None; + return AtomicScopeModel::create(Kind); + } + + /// \brief Get atomic scope model. + /// \return empty atomic scope model if this atomic expression does not have + /// scope operand. + std::unique_ptr<AtomicScopeModel> getScopeModel() const { + return getScopeModel(getOp()); + } }; /// TypoExpr - Internal placeholder for expressions where typo correction diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h index 79d2c58099c4c..58054dda31aa8 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h @@ -1,4 +1,4 @@ -//===--- ExprCXX.h - Classes for representing expressions -------*- C++ -*-===// +//===- ExprCXX.h - Classes for representing expressions ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,31 +6,57 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::Expr interface and subclasses for C++ expressions. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_EXPRCXX_H #define LLVM_CLANG_AST_EXPRCXX_H #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" -#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TypeTraits.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> namespace clang { -class CXXTemporary; -class MSPropertyDecl; -class TemplateArgumentListInfo; -class UuidAttr; +class ASTContext; +class DeclAccessPair; +class IdentifierInfo; +class LambdaCapture; +class NonTypeTemplateParmDecl; +class TemplateParameterList; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -52,23 +78,28 @@ class UuidAttr; class CXXOperatorCallExpr : public CallExpr { /// \brief The overloaded operator. OverloadedOperatorKind Operator; + SourceRange Range; // Only meaningful for floating point types. FPOptions FPFeatures; SourceRange getSourceRangeImpl() const LLVM_READONLY; + 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), - Operator(Op), FPFeatures(FPFeatures) { + : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc), + Operator(Op), FPFeatures(FPFeatures) { Range = getSourceRangeImpl(); } - explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : - CallExpr(C, CXXOperatorCallExprClass, Empty) { } + explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) + : CallExpr(C, CXXOperatorCallExprClass, Empty) {} /// \brief Returns the kind of overloaded operator that this /// expression refers to. @@ -120,9 +151,6 @@ public: bool isFPContractableWithinStatement() const { return FPFeatures.allowFPContractWithinStatement(); } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// Represents a call to a member function that @@ -137,10 +165,10 @@ 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) {} + : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {} CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CXXMemberCallExprClass, Empty) { } + : CallExpr(C, CXXMemberCallExprClass, Empty) {} /// \brief Retrieves the implicit object argument for the member call. /// @@ -183,7 +211,7 @@ public: : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {} CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { } + : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) {} const CallExpr *getConfig() const { return cast_or_null<CallExpr>(getPreArg(CONFIG)); @@ -217,23 +245,28 @@ public: /// reinterpret_cast, and CXXConstCastExpr for \c const_cast. class CXXNamedCastExpr : public ExplicitCastExpr { private: - SourceLocation Loc; // the location of the casting op - SourceLocation RParenLoc; // the location of the right parenthesis - SourceRange AngleBrackets; // range for '<' '>' + // the location of the casting op + SourceLocation Loc; + + // the location of the right parenthesis + SourceLocation RParenLoc; + + // range for '<' '>' + SourceRange AngleBrackets; protected: + friend class ASTStmtReader; + CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK, CastKind kind, Expr *op, unsigned PathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) - : ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l), - RParenLoc(RParenLoc), AngleBrackets(AngleBrackets) {} + : ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l), + RParenLoc(RParenLoc), AngleBrackets(AngleBrackets) {} explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) - : ExplicitCastExpr(SC, Shell, PathSize) { } - - friend class ASTStmtReader; + : ExplicitCastExpr(SC, Shell, PathSize) {} public: const char *getCastName() const; @@ -273,13 +306,16 @@ class CXXStaticCastExpr final unsigned pathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) - : CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize, - writtenTy, l, RParenLoc, AngleBrackets) {} + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize, + writtenTy, l, RParenLoc, AngleBrackets) {} explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize) - : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { } + : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) {} public: + friend class CastExpr; + friend TrailingObjects; + static CXXStaticCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *Path, @@ -292,9 +328,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXStaticCastExprClass; } - - friend TrailingObjects; - friend class CastExpr; }; /// \brief A C++ @c dynamic_cast expression (C++ [expr.dynamic.cast]). @@ -309,13 +342,16 @@ class CXXDynamicCastExpr final Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) - : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize, - writtenTy, l, RParenLoc, AngleBrackets) {} + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize, + writtenTy, l, RParenLoc, AngleBrackets) {} explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize) - : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { } + : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) {} public: + friend class CastExpr; + friend TrailingObjects; + static CXXDynamicCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind Kind, Expr *Op, const CXXCastPath *Path, @@ -331,9 +367,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDynamicCastExprClass; } - - friend TrailingObjects; - friend class CastExpr; }; /// \brief A C++ @c reinterpret_cast expression (C++ [expr.reinterpret.cast]). @@ -353,13 +386,16 @@ class CXXReinterpretCastExpr final TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) - : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op, - pathSize, writtenTy, l, RParenLoc, AngleBrackets) {} + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op, + pathSize, writtenTy, l, RParenLoc, AngleBrackets) {} CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize) - : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { } + : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) {} public: + friend class CastExpr; + friend TrailingObjects; + static CXXReinterpretCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind Kind, Expr *Op, const CXXCastPath *Path, @@ -372,9 +408,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXReinterpretCastExprClass; } - - friend TrailingObjects; - friend class CastExpr; }; /// \brief A C++ \c const_cast expression (C++ [expr.const.cast]). @@ -390,13 +423,16 @@ class CXXConstCastExpr final CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) - : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, - 0, writtenTy, l, RParenLoc, AngleBrackets) {} + : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, + 0, writtenTy, l, RParenLoc, AngleBrackets) {} explicit CXXConstCastExpr(EmptyShell Empty) - : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { } + : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) {} public: + friend class CastExpr; + friend TrailingObjects; + static CXXConstCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, Expr *Op, TypeSourceInfo *WrittenTy, SourceLocation L, @@ -407,9 +443,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstCastExprClass; } - - friend TrailingObjects; - friend class CastExpr; }; /// \brief A call to a literal operator (C++11 [over.literal]) @@ -426,22 +459,37 @@ class UserDefinedLiteral : public CallExpr { SourceLocation UDSuffixLoc; public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args, QualType T, ExprValueKind VK, SourceLocation LitEndLoc, SourceLocation SuffixLoc) - : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc), - UDSuffixLoc(SuffixLoc) {} + : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc), + UDSuffixLoc(SuffixLoc) {} + explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty) - : CallExpr(C, UserDefinedLiteralClass, Empty) {} + : CallExpr(C, UserDefinedLiteralClass, Empty) {} /// The kind of literal operator which is invoked. enum LiteralOperatorKind { - LOK_Raw, ///< Raw form: operator "" X (const char *) - LOK_Template, ///< Raw form: operator "" X<cs...> () - LOK_Integer, ///< operator "" X (unsigned long long) - LOK_Floating, ///< operator "" X (long double) - LOK_String, ///< operator "" X (const CharT *, size_t) - LOK_Character ///< operator "" X (CharT) + /// Raw form: operator "" X (const char *) + LOK_Raw, + + /// Raw form: operator "" X<cs...> () + LOK_Template, + + /// operator "" X (unsigned long long) + LOK_Integer, + + /// operator "" X (long double) + LOK_Floating, + + /// operator "" X (const CharT *, size_t) + LOK_String, + + /// operator "" X (CharT) + LOK_Character }; /// \brief Returns the kind of literal operator invocation @@ -461,8 +509,8 @@ public: return getRParenLoc(); return getArg(0)->getLocStart(); } - SourceLocation getLocEnd() const { return getRParenLoc(); } + SourceLocation getLocEnd() const { return getRParenLoc(); } /// \brief Returns the location of a ud-suffix in the expression. /// @@ -476,24 +524,21 @@ public: static bool classof(const Stmt *S) { return S->getStmtClass() == UserDefinedLiteralClass; } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// \brief 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) : - Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false, false), - Value(val), Loc(l) {} + CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) + : Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(val), Loc(l) {} explicit CXXBoolLiteralExpr(EmptyShell Empty) - : Expr(CXXBoolLiteralExprClass, Empty) { } + : Expr(CXXBoolLiteralExprClass, Empty) {} bool getValue() const { return Value; } void setValue(bool V) { Value = V; } @@ -519,14 +564,15 @@ 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) : - Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false, false), - Loc(l) {} + CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) + : Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, + false, false, false), + Loc(l) {} explicit CXXNullPtrLiteralExpr(EmptyShell Empty) - : Expr(CXXNullPtrLiteralExprClass, Empty) { } + : Expr(CXXNullPtrLiteralExprClass, Empty) {} SourceLocation getLocStart() const LLVM_READONLY { return Loc; } SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } @@ -546,18 +592,21 @@ public: /// \brief Implicit construction of a std::initializer_list<T> object from an /// array temporary within list-initialization (C++11 [dcl.init.list]p5). class CXXStdInitializerListExpr : public Expr { - Stmt *SubExpr; + Stmt *SubExpr = nullptr; CXXStdInitializerListExpr(EmptyShell Empty) - : Expr(CXXStdInitializerListExprClass, Empty), SubExpr(nullptr) {} + : Expr(CXXStdInitializerListExprClass, Empty) {} public: + friend class ASTReader; + friend class ASTStmtReader; + CXXStdInitializerListExpr(QualType Ty, Expr *SubExpr) - : Expr(CXXStdInitializerListExprClass, Ty, VK_RValue, OK_Ordinary, - Ty->isDependentType(), SubExpr->isValueDependent(), - SubExpr->isInstantiationDependent(), - SubExpr->containsUnexpandedParameterPack()), - SubExpr(SubExpr) {} + : Expr(CXXStdInitializerListExprClass, Ty, VK_RValue, OK_Ordinary, + Ty->isDependentType(), SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), + SubExpr->containsUnexpandedParameterPack()), + SubExpr(SubExpr) {} Expr *getSubExpr() { return static_cast<Expr*>(SubExpr); } const Expr *getSubExpr() const { return static_cast<const Expr*>(SubExpr); } @@ -565,9 +614,11 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return SubExpr->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return SubExpr->getSourceRange(); } @@ -577,9 +628,6 @@ public: } child_range children() { return child_range(&SubExpr, &SubExpr + 1); } - - friend class ASTReader; - friend class ASTStmtReader; }; /// A C++ \c typeid expression (C++ [expr.typeid]), which gets @@ -594,27 +642,29 @@ private: public: CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) - : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, - // typeid is never type-dependent (C++ [temp.dep.expr]p4) - false, - // typeid is value-dependent if the type or expression are dependent - Operand->getType()->isDependentType(), - Operand->getType()->isInstantiationDependentType(), - Operand->getType()->containsUnexpandedParameterPack()), - Operand(Operand), Range(R) { } + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are + // dependent + Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) {} CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R) - : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, - // typeid is never type-dependent (C++ [temp.dep.expr]p4) - false, - // typeid is value-dependent if the type or expression are dependent - Operand->isTypeDependent() || Operand->isValueDependent(), - Operand->isInstantiationDependent(), - Operand->containsUnexpandedParameterPack()), - Operand(Operand), Range(R) { } + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are + // dependent + Operand->isTypeDependent() || Operand->isValueDependent(), + Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) {} CXXTypeidExpr(EmptyShell Empty, bool isExpr) - : Expr(CXXTypeidExprClass, Empty) { + : Expr(CXXTypeidExprClass, Empty) { if (isExpr) Operand = (Expr*)nullptr; else @@ -683,26 +733,30 @@ class MSPropertyRefExpr : public Expr { NestedNameSpecifierLoc QualifierLoc; public: + friend class ASTStmtReader; + MSPropertyRefExpr(Expr *baseExpr, MSPropertyDecl *decl, bool isArrow, QualType ty, ExprValueKind VK, NestedNameSpecifierLoc qualifierLoc, SourceLocation nameLoc) - : Expr(MSPropertyRefExprClass, ty, VK, OK_Ordinary, - /*type-dependent*/ false, baseExpr->isValueDependent(), - baseExpr->isInstantiationDependent(), - baseExpr->containsUnexpandedParameterPack()), - BaseExpr(baseExpr), TheDecl(decl), - MemberLoc(nameLoc), IsArrow(isArrow), - QualifierLoc(qualifierLoc) {} + : Expr(MSPropertyRefExprClass, ty, VK, OK_Ordinary, + /*type-dependent*/ false, baseExpr->isValueDependent(), + baseExpr->isInstantiationDependent(), + baseExpr->containsUnexpandedParameterPack()), + BaseExpr(baseExpr), TheDecl(decl), + MemberLoc(nameLoc), IsArrow(isArrow), + QualifierLoc(qualifierLoc) {} MSPropertyRefExpr(EmptyShell Empty) : Expr(MSPropertyRefExprClass, Empty) {} SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocStart(), getLocEnd()); } + bool isImplicitAccess() const { return getBaseExpr() && getBaseExpr()->isImplicitCXXThis(); } + SourceLocation getLocStart() const { if (!isImplicitAccess()) return BaseExpr->getLocStart(); @@ -711,11 +765,13 @@ public: else return MemberLoc; } + SourceLocation getLocEnd() const { return getMemberLoc(); } child_range children() { return child_range((Stmt**)&BaseExpr, (Stmt**)&BaseExpr + 1); } + static bool classof(const Stmt *T) { return T->getStmtClass() == MSPropertyRefExprClass; } @@ -725,8 +781,6 @@ public: bool isArrow() const { return IsArrow; } SourceLocation getMemberLoc() const { return MemberLoc; } NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } - - friend class ASTStmtReader; }; /// MS property subscript expression. @@ -742,7 +796,9 @@ public: /// This is a syntactic pseudo-object expression. class MSPropertySubscriptExpr : public Expr { friend class ASTStmtReader; + enum { BASE_EXPR, IDX_EXPR, NUM_SUBEXPRS = 2 }; + Stmt *SubExprs[NUM_SUBEXPRS]; SourceLocation RBracketLoc; @@ -773,6 +829,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return getBase()->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } SourceLocation getRBracketLoc() const { return RBracketLoc; } @@ -891,13 +948,13 @@ class CXXThisExpr : public Expr { public: CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit) - : Expr(CXXThisExprClass, Type, 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) { } + : Expr(CXXThisExprClass, Type, 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) {} CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} @@ -926,23 +983,25 @@ public: /// 'throw' assignment-expression. When assignment-expression isn't /// present, Op will be null. class CXXThrowExpr : public Expr { + friend class ASTStmtReader; + Stmt *Op; SourceLocation ThrowLoc; + /// \brief Whether the thrown variable (if any) is in scope. unsigned IsThrownVariableInScope : 1; - friend class ASTStmtReader; - 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, - bool IsThrownVariableInScope) : - Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - expr && expr->isInstantiationDependent(), - expr && expr->containsUnexpandedParameterPack()), - Op(expr), ThrowLoc(l), IsThrownVariableInScope(IsThrownVariableInScope) {} + bool IsThrownVariableInScope) + : Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + expr && expr->isInstantiationDependent(), + expr && expr->containsUnexpandedParameterPack()), + Op(expr), ThrowLoc(l), + IsThrownVariableInScope(IsThrownVariableInScope) {} CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } @@ -958,6 +1017,7 @@ public: bool isThrownVariableInScope() const { return IsThrownVariableInScope; } SourceLocation getLocStart() const LLVM_READONLY { return ThrowLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { if (!getSubExpr()) return ThrowLoc; @@ -987,15 +1047,19 @@ class CXXDefaultArgExpr final : public Expr { SourceLocation Loc; 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, false), - Param(param), Loc(Loc) { } + : Expr(SC, + param->hasUnparsedDefaultArg() + ? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType(), + param->getDefaultArg()->getValueKind(), + param->getDefaultArg()->getObjectKind(), false, false, false, + false), + Param(param), 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 @@ -1036,9 +1100,6 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// \brief A use of a default initializer in a constructor or in aggregate @@ -1062,6 +1123,9 @@ class CXXDefaultInitExpr : public Expr { 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, @@ -1094,9 +1158,6 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTReader; - friend class ASTStmtReader; }; /// \brief Represents a C++ temporary. @@ -1105,13 +1166,14 @@ class CXXTemporary { const CXXDestructorDecl *Destructor; explicit CXXTemporary(const CXXDestructorDecl *destructor) - : Destructor(destructor) { } + : Destructor(destructor) {} public: static CXXTemporary *Create(const ASTContext &C, const CXXDestructorDecl *Destructor); const CXXDestructorDecl *getDestructor() const { return Destructor; } + void setDestructor(const CXXDestructorDecl *Dtor) { Destructor = Dtor; } @@ -1132,21 +1194,20 @@ public: /// } /// \endcode class CXXBindTemporaryExpr : public Expr { - CXXTemporary *Temp; - - Stmt *SubExpr; + CXXTemporary *Temp = nullptr; + Stmt *SubExpr = nullptr; CXXBindTemporaryExpr(CXXTemporary *temp, Expr* SubExpr) - : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), - VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), - SubExpr->isValueDependent(), - SubExpr->isInstantiationDependent(), - SubExpr->containsUnexpandedParameterPack()), - Temp(temp), SubExpr(SubExpr) { } + : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), + VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), + SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), + SubExpr->containsUnexpandedParameterPack()), + Temp(temp), SubExpr(SubExpr) {} public: CXXBindTemporaryExpr(EmptyShell Empty) - : Expr(CXXBindTemporaryExprClass, Empty), Temp(nullptr), SubExpr(nullptr) {} + : Expr(CXXBindTemporaryExprClass, Empty) {} static CXXBindTemporaryExpr *Create(const ASTContext &C, CXXTemporary *Temp, Expr* SubExpr); @@ -1162,6 +1223,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return SubExpr->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} // Implement isa/cast/dyncast/etc. @@ -1184,8 +1246,7 @@ public: }; private: - CXXConstructorDecl *Constructor; - + CXXConstructorDecl *Constructor = nullptr; SourceLocation Loc; SourceRange ParenOrBraceRange; unsigned NumArgs : 16; @@ -1195,7 +1256,7 @@ private: unsigned StdInitListInitialization : 1; unsigned ZeroInitialization : 1; unsigned ConstructKind : 2; - Stmt **Args; + Stmt **Args = nullptr; void setConstructor(CXXConstructorDecl *C) { Constructor = C; } @@ -1214,15 +1275,16 @@ protected: /// \brief Construct an empty C++ construction expression. CXXConstructExpr(StmtClass SC, EmptyShell Empty) - : Expr(SC, Empty), Constructor(nullptr), NumArgs(0), Elidable(false), - HadMultipleCandidates(false), ListInitialization(false), - ZeroInitialization(false), ConstructKind(0), Args(nullptr) - { } + : Expr(SC, Empty), NumArgs(0), Elidable(false), + HadMultipleCandidates(false), ListInitialization(false), + ZeroInitialization(false), ConstructKind(0) {} public: + friend class ASTStmtReader; + /// \brief Construct an empty C++ construction expression. explicit CXXConstructExpr(EmptyShell Empty) - : CXXConstructExpr(CXXConstructExprClass, Empty) {} + : CXXConstructExpr(CXXConstructExprClass, Empty) {} static CXXConstructExpr *Create(const ASTContext &C, QualType T, SourceLocation Loc, @@ -1278,10 +1340,10 @@ public: ConstructKind = CK; } - typedef ExprIterator arg_iterator; - typedef ConstExprIterator const_arg_iterator; - typedef llvm::iterator_range<arg_iterator> arg_range; - typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + using arg_iterator = ExprIterator; + using const_arg_iterator = ConstExprIterator; + using arg_range = llvm::iterator_range<arg_iterator>; + using arg_const_range = llvm::iterator_range<const_arg_iterator>; arg_range arguments() { return arg_range(arg_begin(), arg_end()); } arg_const_range arguments() const { @@ -1329,8 +1391,6 @@ public: child_range children() { return child_range(&Args[0], &Args[0]+NumArgs); } - - friend class ASTStmtReader; }; /// \brief Represents a call to an inherited base class constructor from an @@ -1339,7 +1399,7 @@ public: /// base class constructor. class CXXInheritedCtorInitExpr : public Expr { private: - CXXConstructorDecl *Constructor; + CXXConstructorDecl *Constructor = nullptr; /// The location of the using declaration. SourceLocation Loc; @@ -1352,6 +1412,8 @@ private: unsigned InheritedFromVirtualBase : 1; public: + friend class ASTStmtReader; + /// \brief Construct a C++ inheriting construction expression. CXXInheritedCtorInitExpr(SourceLocation Loc, QualType T, CXXConstructorDecl *Ctor, bool ConstructsVirtualBase, @@ -1366,7 +1428,7 @@ public: /// \brief Construct an empty C++ inheriting construction expression. explicit CXXInheritedCtorInitExpr(EmptyShell Empty) - : Expr(CXXInheritedCtorInitExprClass, Empty), Constructor(nullptr), + : Expr(CXXInheritedCtorInitExprClass, Empty), ConstructsVirtualBase(false), InheritedFromVirtualBase(false) {} /// \brief Get the constructor that this expression will call. @@ -1393,11 +1455,10 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXInheritedCtorInitExprClass; } + child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTStmtReader; }; /// \brief Represents an explicit C++ type conversion that uses "functional" @@ -1417,14 +1478,17 @@ class CXXFunctionalCastExpr final TypeSourceInfo *writtenTy, CastKind kind, Expr *castExpr, unsigned pathSize, SourceLocation lParenLoc, SourceLocation rParenLoc) - : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind, - castExpr, pathSize, writtenTy), - LParenLoc(lParenLoc), RParenLoc(rParenLoc) {} + : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind, + castExpr, pathSize, writtenTy), + LParenLoc(lParenLoc), RParenLoc(rParenLoc) {} explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize) - : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) { } + : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) {} public: + friend class CastExpr; + friend TrailingObjects; + static CXXFunctionalCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, TypeSourceInfo *Written, @@ -1446,9 +1510,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXFunctionalCastExprClass; } - - friend TrailingObjects; - friend class CastExpr; }; /// @brief Represents a C++ functional cast expression that builds a @@ -1467,9 +1528,11 @@ public: /// }; /// \endcode class CXXTemporaryObjectExpr : public CXXConstructExpr { - TypeSourceInfo *Type; + TypeSourceInfo *Type = nullptr; public: + friend class ASTStmtReader; + CXXTemporaryObjectExpr(const ASTContext &C, CXXConstructorDecl *Cons, QualType Type, @@ -1481,7 +1544,7 @@ public: bool StdInitListInitialization, bool ZeroInitialization); explicit CXXTemporaryObjectExpr(EmptyShell Empty) - : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { } + : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty) {} TypeSourceInfo *getTypeSourceInfo() const { return Type; } @@ -1491,8 +1554,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CXXTemporaryObjectExprClass; } - - friend class ASTStmtReader; }; /// \brief A C++ lambda expression, which produces a function object @@ -1558,9 +1619,9 @@ class LambdaExpr final : public Expr, /// \brief Construct an empty lambda expression. LambdaExpr(EmptyShell Empty, unsigned NumCaptures) - : Expr(LambdaExprClass, Empty), - NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false), - ExplicitResultType(false) { + : Expr(LambdaExprClass, Empty), NumCaptures(NumCaptures), + CaptureDefault(LCD_None), ExplicitParams(false), + ExplicitResultType(false) { getStoredStmts()[NumCaptures] = nullptr; } @@ -1569,6 +1630,10 @@ class LambdaExpr final : public Expr, Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); } public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// \brief Construct a new lambda expression. static LambdaExpr * Create(const ASTContext &C, CXXRecordDecl *Class, SourceRange IntroducerRange, @@ -1597,10 +1662,10 @@ public: /// \brief An iterator that walks over the captures of the lambda, /// both implicit and explicit. - typedef const LambdaCapture *capture_iterator; + using capture_iterator = const LambdaCapture *; /// \brief An iterator over a range of lambda captures. - typedef llvm::iterator_range<capture_iterator> capture_range; + using capture_range = llvm::iterator_range<capture_iterator>; /// \brief Retrieve this lambda's captures. capture_range captures() const; @@ -1639,11 +1704,11 @@ public: /// \brief Iterator that walks over the capture initialization /// arguments. - typedef Expr **capture_init_iterator; + using capture_init_iterator = Expr **; /// \brief Const iterator that walks over the capture initialization /// arguments. - typedef Expr *const *const_capture_init_iterator; + using const_capture_init_iterator = Expr *const *; /// \brief Retrieve the initialization expressions for this lambda's captures. llvm::iterator_range<capture_init_iterator> capture_inits() { @@ -1723,26 +1788,23 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return IntroducerRange.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return ClosingBrace; } child_range children() { // Includes initialization exprs plus body stmt return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1); } - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// An expression "T()" which creates a value-initialized rvalue of type /// T, which is a non-class type. See (C++98 [5.2.3p2]). class CXXScalarValueInitExpr : public Expr { + friend class ASTStmtReader; + SourceLocation RParenLoc; TypeSourceInfo *TypeInfo; - friend class ASTStmtReader; - public: /// \brief Create an explicitly-written scalar-value initialization /// expression. @@ -1754,7 +1816,7 @@ public: RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} explicit CXXScalarValueInitExpr(EmptyShell Shell) - : Expr(CXXScalarValueInitExprClass, Shell) { } + : Expr(CXXScalarValueInitExprClass, Shell) {} TypeSourceInfo *getTypeSourceInfo() const { return TypeInfo; @@ -1778,11 +1840,16 @@ public: /// \brief Represents a new-expression for memory allocation and constructor /// calls, e.g: "new CXXNewExpr(foo)". class CXXNewExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + /// Contains an optional array size expression, an optional initialization /// expression, and any number of optional placement arguments, in that order. - Stmt **SubExprs; + Stmt **SubExprs = nullptr; + /// \brief Points to the allocation function used. FunctionDecl *OperatorNew; + /// \brief Points to the deallocation function used in case of error. May be /// null. FunctionDecl *OperatorDelete; @@ -1802,27 +1869,35 @@ class CXXNewExpr : public Expr { /// Was the usage ::new, i.e. is the global new to be used? unsigned GlobalNew : 1; + /// Do we allocate an array? If so, the first SubExpr is the size expression. unsigned Array : 1; + /// Should the alignment be passed to the allocation function? unsigned PassAlignment : 1; + /// If this is an array allocation, does the usual deallocation /// function for the allocated type want to know the allocated size? unsigned UsualArrayDeleteWantsSize : 1; + /// The number of placement new arguments. unsigned NumPlacementArgs : 26; + /// What kind of initializer do we have? Could be none, parens, or braces. /// In storage, we distinguish between "none, and no initializer expr", and /// "none, but an implicit initializer expr". unsigned StoredInitializationStyle : 2; - friend class ASTStmtReader; - friend class ASTStmtWriter; public: enum InitializationStyle { - NoInit, ///< New-expression has no initializer as written. - CallInit, ///< New-expression has a C++98 paren-delimited initializer. - ListInit ///< New-expression has a C++11 list-initializer. + /// New-expression has no initializer as written. + NoInit, + + /// New-expression has a C++98 paren-delimited initializer. + CallInit, + + /// New-expression has a C++11 list-initializer. + ListInit }; CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew, @@ -1833,7 +1908,7 @@ public: QualType ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, SourceRange directInitRange); explicit CXXNewExpr(EmptyShell Shell) - : Expr(CXXNewExprClass, Shell), SubExprs(nullptr) { } + : Expr(CXXNewExprClass, Shell) {} void AllocateArgsArray(const ASTContext &C, bool isArray, unsigned numPlaceArgs, bool hasInitializer); @@ -1870,6 +1945,7 @@ public: void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } bool isArray() const { return Array; } + Expr *getArraySize() { return Array ? cast<Expr>(SubExprs[0]) : nullptr; } @@ -1878,6 +1954,7 @@ public: } unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + Expr **getPlacementArgs() { return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer()); } @@ -1932,8 +2009,8 @@ public: return UsualArrayDeleteWantsSize; } - typedef ExprIterator arg_iterator; - typedef ConstExprIterator const_arg_iterator; + using arg_iterator = ExprIterator; + using const_arg_iterator = ConstExprIterator; llvm::iterator_range<arg_iterator> placement_arguments() { return llvm::make_range(placement_arg_begin(), placement_arg_end()); @@ -1956,7 +2033,8 @@ public: return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); } - typedef Stmt **raw_arg_iterator; + using raw_arg_iterator = Stmt **; + raw_arg_iterator raw_arg_begin() { return SubExprs; } raw_arg_iterator raw_arg_end() { return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); @@ -1974,6 +2052,7 @@ public: SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return getStartLoc(); } SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } @@ -1991,36 +2070,43 @@ public: /// destructor calls, e.g. "delete[] pArray". class CXXDeleteExpr : public Expr { /// Points to the operator delete overload that is used. Could be a member. - FunctionDecl *OperatorDelete; + FunctionDecl *OperatorDelete = nullptr; + /// The pointer expression to be deleted. - Stmt *Argument; + 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), Loc(loc), - GlobalDelete(globalDelete), - ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), - UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { } - explicit CXXDeleteExpr(EmptyShell Shell) - : Expr(CXXDeleteExprClass, Shell), OperatorDelete(nullptr), - Argument(nullptr) {} + : 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; } @@ -2054,8 +2140,6 @@ public: // Iterators child_range children() { return child_range(&Argument, &Argument+1); } - - friend class ASTStmtReader; }; /// \brief Stores the type being destroyed by a pseudo-destructor expression. @@ -2068,10 +2152,10 @@ class PseudoDestructorTypeStorage { SourceLocation Location; public: - PseudoDestructorTypeStorage() { } + PseudoDestructorTypeStorage() = default; PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) - : Type(II), Location(Loc) { } + : Type(II), Location(Loc) {} PseudoDestructorTypeStorage(TypeSourceInfo *Info); @@ -2111,8 +2195,10 @@ public: /// for scalar types. A pseudo-destructor expression has no run-time semantics /// beyond evaluating the base expression. class CXXPseudoDestructorExpr : public Expr { + friend class ASTStmtReader; + /// \brief The base expression (that is being destroyed). - Stmt *Base; + Stmt *Base = nullptr; /// \brief Whether the operator was an arrow ('->'); otherwise, it was a /// period ('.'). @@ -2126,7 +2212,7 @@ class CXXPseudoDestructorExpr : public Expr { /// \brief The type that precedes the '::' in a qualified pseudo-destructor /// expression. - TypeSourceInfo *ScopeType; + TypeSourceInfo *ScopeType = nullptr; /// \brief The location of the '::' in a qualified pseudo-destructor /// expression. @@ -2139,8 +2225,6 @@ class CXXPseudoDestructorExpr : public Expr { /// resolve the name. PseudoDestructorTypeStorage DestroyedType; - friend class ASTStmtReader; - public: CXXPseudoDestructorExpr(const ASTContext &Context, Expr *Base, bool isArrow, SourceLocation OperatorLoc, @@ -2151,8 +2235,7 @@ public: PseudoDestructorTypeStorage DestroyedType); explicit CXXPseudoDestructorExpr(EmptyShell Shell) - : Expr(CXXPseudoDestructorExprClass, Shell), - Base(nullptr), IsArrow(false), QualifierLoc(), ScopeType(nullptr) { } + : Expr(CXXPseudoDestructorExprClass, Shell), IsArrow(false) {} Expr *getBase() const { return cast<Expr>(Base); } @@ -2270,13 +2353,17 @@ class TypeTraitExpr final SourceLocation RParenLoc, bool Value); - TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { } + TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) {} size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const { return getNumArgs(); } public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// \brief Create a new type trait expression. static TypeTraitExpr *Create(const ASTContext &C, QualType T, SourceLocation Loc, TypeTrait Kind, @@ -2323,10 +2410,6 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// \brief An Embarcadero array type trait, as used in the implementation of @@ -2338,13 +2421,11 @@ public: /// __array_extent(int, 1) == 20 /// \endcode class ArrayTypeTraitExpr : public Expr { - virtual void anchor(); - /// \brief The trait. An ArrayTypeTrait enum in MSVC compat unsigned. unsigned ATT : 2; /// \brief The value of the type trait. Unspecified if dependent. - uint64_t Value; + uint64_t Value = 0; /// \brief The array dimension being queried, or -1 if not used. Expr *Dimension; @@ -2356,26 +2437,28 @@ class ArrayTypeTraitExpr : public Expr { SourceLocation RParen; /// \brief The type being queried. - TypeSourceInfo *QueriedType; + TypeSourceInfo *QueriedType = nullptr; + + virtual void anchor(); public: + friend class ASTStmtReader; + ArrayTypeTraitExpr(SourceLocation loc, ArrayTypeTrait att, TypeSourceInfo *queried, uint64_t value, Expr *dimension, SourceLocation rparen, QualType ty) - : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, - false, queried->getType()->isDependentType(), - (queried->getType()->isInstantiationDependentType() || - (dimension && dimension->isInstantiationDependent())), - queried->getType()->containsUnexpandedParameterPack()), - ATT(att), Value(value), Dimension(dimension), - Loc(loc), RParen(rparen), QueriedType(queried) { } - + : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, + false, queried->getType()->isDependentType(), + (queried->getType()->isInstantiationDependentType() || + (dimension && dimension->isInstantiationDependent())), + queried->getType()->containsUnexpandedParameterPack()), + ATT(att), Value(value), Dimension(dimension), + Loc(loc), RParen(rparen), QueriedType(queried) {} explicit ArrayTypeTraitExpr(EmptyShell Empty) - : Expr(ArrayTypeTraitExprClass, Empty), ATT(0), Value(false), - QueriedType() { } + : Expr(ArrayTypeTraitExprClass, Empty), ATT(0) {} - virtual ~ArrayTypeTraitExpr() { } + virtual ~ArrayTypeTraitExpr() = default; SourceLocation getLocStart() const LLVM_READONLY { return Loc; } SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } @@ -2398,8 +2481,6 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTStmtReader; }; /// \brief An expression trait intrinsic. @@ -2412,6 +2493,7 @@ public: class ExpressionTraitExpr : public Expr { /// \brief The trait. A ExpressionTrait enum in MSVC compatible unsigned. unsigned ET : 31; + /// \brief The value of the type trait. Unspecified if dependent. unsigned Value : 1; @@ -2422,23 +2504,25 @@ class ExpressionTraitExpr : public Expr { SourceLocation RParen; /// \brief The expression being queried. - Expr* QueriedExpression; + Expr* QueriedExpression = nullptr; + public: + friend class ASTStmtReader; + ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et, Expr *queried, bool value, SourceLocation rparen, QualType resultType) - : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary, - false, // Not type-dependent - // Value-dependent if the argument is type-dependent. - queried->isTypeDependent(), - queried->isInstantiationDependent(), - queried->containsUnexpandedParameterPack()), - ET(et), Value(value), Loc(loc), RParen(rparen), - QueriedExpression(queried) { } + : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Not type-dependent + // Value-dependent if the argument is type-dependent. + queried->isTypeDependent(), + queried->isInstantiationDependent(), + queried->containsUnexpandedParameterPack()), + ET(et), Value(value), Loc(loc), RParen(rparen), + QueriedExpression(queried) {} explicit ExpressionTraitExpr(EmptyShell Empty) - : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false), - QueriedExpression() { } + : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false) {} SourceLocation getLocStart() const LLVM_READONLY { return Loc; } SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } @@ -2457,11 +2541,8 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTStmtReader; }; - /// \brief A reference to an overloaded function set, either an /// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr. class OverloadExpr : public Expr { @@ -2475,13 +2556,26 @@ class OverloadExpr : public Expr { /// include UsingShadowDecls. Access is relative to the naming /// class. // FIXME: Allocate this data after the OverloadExpr subclass. - DeclAccessPair *Results; - unsigned NumResults; + DeclAccessPair *Results = nullptr; + + unsigned NumResults = 0; protected: /// \brief Whether the name includes info for explicit template /// keyword and arguments. - bool HasTemplateKWAndArgsInfo; + bool HasTemplateKWAndArgsInfo = false; + + OverloadExpr(StmtClass K, const ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End, + bool KnownDependent, + bool KnownInstantiationDependent, + bool KnownContainsUnexpandedParameterPack); + + OverloadExpr(StmtClass K, EmptyShell Empty) : Expr(K, Empty) {} /// \brief Return the optional template keyword and arguments info. ASTTemplateKWAndArgsInfo * @@ -2496,25 +2590,14 @@ protected: /// Return the optional template arguments. TemplateArgumentLoc *getTrailingTemplateArgumentLoc(); // defined far below - OverloadExpr(StmtClass K, const ASTContext &C, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs, - UnresolvedSetIterator Begin, UnresolvedSetIterator End, - bool KnownDependent, - bool KnownInstantiationDependent, - bool KnownContainsUnexpandedParameterPack); - - OverloadExpr(StmtClass K, EmptyShell Empty) - : Expr(K, Empty), QualifierLoc(), Results(nullptr), NumResults(0), - HasTemplateKWAndArgsInfo(false) { } - void initializeResults(const ASTContext &C, UnresolvedSetIterator Begin, UnresolvedSetIterator End); public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + struct FindResult { OverloadExpr *Expression; bool IsAddressOfOperand; @@ -2552,7 +2635,8 @@ public: /// \brief Gets the naming class of this lookup, if any. CXXRecordDecl *getNamingClass() const; - typedef UnresolvedSetImpl::iterator decls_iterator; + using decls_iterator = UnresolvedSetImpl::iterator; + decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); } decls_iterator decls_end() const { return UnresolvedSetIterator(Results + NumResults); @@ -2636,9 +2720,6 @@ public: return T->getStmtClass() == UnresolvedLookupExprClass || T->getStmtClass() == UnresolvedMemberExprClass; } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// \brief A reference to a name which we were able to look up during @@ -2656,25 +2737,25 @@ class UnresolvedLookupExpr final : public OverloadExpr, private llvm::TrailingObjects< UnresolvedLookupExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + friend class ASTStmtReader; + friend class OverloadExpr; + friend TrailingObjects; + /// True if these lookup results should be extended by /// argument-dependent lookup if this is the operand of a function /// call. - bool RequiresADL; + bool RequiresADL = false; /// True if these lookup results are overloaded. This is pretty /// trivially rederivable if we urgently need to kill this field. - bool Overloaded; + bool Overloaded = false; /// The naming class (C++ [class.access.base]p5) of the lookup, if /// any. This can generally be recalculated from the context chain, /// but that can be fairly expensive for unqualified lookups. If we /// want to improve memory use here, this could go in a union /// against the qualified-lookup bits. - CXXRecordDecl *NamingClass; - - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; - } + CXXRecordDecl *NamingClass = nullptr; UnresolvedLookupExpr(const ASTContext &C, CXXRecordDecl *NamingClass, @@ -2684,20 +2765,17 @@ class UnresolvedLookupExpr final bool RequiresADL, bool Overloaded, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc, - NameInfo, TemplateArgs, Begin, End, false, false, false), - RequiresADL(RequiresADL), - Overloaded(Overloaded), NamingClass(NamingClass) - {} + : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc, + NameInfo, TemplateArgs, Begin, End, false, false, false), + RequiresADL(RequiresADL), + Overloaded(Overloaded), NamingClass(NamingClass) {} UnresolvedLookupExpr(EmptyShell Empty) - : OverloadExpr(UnresolvedLookupExprClass, Empty), - RequiresADL(false), Overloaded(false), NamingClass(nullptr) - {} + : OverloadExpr(UnresolvedLookupExprClass, Empty) {} - friend TrailingObjects; - friend class OverloadExpr; - friend class ASTStmtReader; + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } public: static UnresolvedLookupExpr *Create(const ASTContext &C, @@ -2743,6 +2821,7 @@ public: return l.getBeginLoc(); return getNameInfo().getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); @@ -2788,17 +2867,21 @@ class DependentScopeDeclRefExpr final /// keyword and arguments. bool HasTemplateKWAndArgsInfo; - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; - } - DependentScopeDeclRefExpr(QualType T, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args); + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } + public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + static DependentScopeDeclRefExpr *Create(const ASTContext &C, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, @@ -2888,6 +2971,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return QualifierLoc.getBeginLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); @@ -2901,10 +2985,6 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// Represents an expression -- generally a full-expression -- that @@ -2925,18 +3005,18 @@ public: /// It's useful to remember the set of blocks; we could also /// remember the set of temporaries, but there's currently /// no need. - typedef BlockDecl *CleanupObject; + using CleanupObject = BlockDecl *; private: + friend class ASTStmtReader; + friend TrailingObjects; + Stmt *SubExpr; ExprWithCleanups(EmptyShell, unsigned NumObjects); ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects, ArrayRef<CleanupObject> Objects); - friend TrailingObjects; - friend class ASTStmtReader; - public: static ExprWithCleanups *Create(const ASTContext &C, EmptyShell empty, unsigned numObjects); @@ -2959,6 +3039,7 @@ public: Expr *getSubExpr() { return cast<Expr>(SubExpr); } const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + bool cleanupsHaveSideEffects() const { return ExprWithCleanupsBits.CleanupsHaveSideEffects; } @@ -2970,6 +3051,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return SubExpr->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} // Implement isa/cast/dyncast/etc. @@ -3005,8 +3087,11 @@ public: class CXXUnresolvedConstructExpr final : public Expr, private llvm::TrailingObjects<CXXUnresolvedConstructExpr, Expr *> { + friend class ASTStmtReader; + friend TrailingObjects; + /// \brief The type being constructed. - TypeSourceInfo *Type; + TypeSourceInfo *Type = nullptr; /// \brief The location of the left parentheses ('('). SourceLocation LParenLoc; @@ -3023,10 +3108,7 @@ class CXXUnresolvedConstructExpr final SourceLocation RParenLoc); CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) - : Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { } - - friend TrailingObjects; - friend class ASTStmtReader; + : Expr(CXXUnresolvedConstructExprClass, Empty), NumArgs(NumArgs) {} public: static CXXUnresolvedConstructExpr *Create(const ASTContext &C, @@ -3056,14 +3138,21 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + /// Determine whether this expression models list-initialization. + /// If so, there will be exactly one subexpression, which will be + /// an InitListExpr. + bool isListInitialization() const { return LParenLoc.isInvalid(); } + /// \brief Retrieve the number of arguments. unsigned arg_size() const { return NumArgs; } - typedef Expr** arg_iterator; + using arg_iterator = Expr **; + arg_iterator arg_begin() { return getTrailingObjects<Expr *>(); } arg_iterator arg_end() { return arg_begin() + NumArgs; } - typedef const Expr* const * const_arg_iterator; + using const_arg_iterator = const Expr* const *; + const_arg_iterator arg_begin() const { return getTrailingObjects<Expr *>(); } const_arg_iterator arg_end() const { return arg_begin() + NumArgs; @@ -3085,6 +3174,7 @@ public: } SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY { if (!RParenLoc.isValid() && NumArgs > 0) return getArg(NumArgs - 1)->getLocEnd(); @@ -3165,6 +3255,10 @@ class CXXDependentScopeMemberExpr final const TemplateArgumentListInfo *TemplateArgs); public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -3214,7 +3308,6 @@ public: /// name, with source location information. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } - /// \brief Retrieve the first part of the nested-name-specifier that was /// found in the scope of the member access expression when the member access /// was initially parsed. @@ -3326,10 +3419,6 @@ public: return child_range(child_iterator(), child_iterator()); return child_range(&Base, &Base + 1); } - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// \brief Represents a C++ member access expression for which lookup @@ -3351,6 +3440,10 @@ class UnresolvedMemberExpr final : public OverloadExpr, private llvm::TrailingObjects< UnresolvedMemberExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + friend class ASTStmtReader; + friend class OverloadExpr; + friend TrailingObjects; + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; @@ -3363,7 +3456,7 @@ class UnresolvedMemberExpr final /// e.g., the \c x in x.f. /// /// This can be null if this is an 'unbased' member expression. - Stmt *Base; + Stmt *Base = nullptr; /// \brief The type of the base expression; never null. QualType BaseType; @@ -3371,10 +3464,6 @@ class UnresolvedMemberExpr final /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; - } - UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -3385,12 +3474,12 @@ class UnresolvedMemberExpr final UnresolvedSetIterator Begin, UnresolvedSetIterator End); UnresolvedMemberExpr(EmptyShell Empty) - : OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false), - HasUnresolvedUsing(false), Base(nullptr) { } + : OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false), + HasUnresolvedUsing(false) {} - friend TrailingObjects; - friend class OverloadExpr; - friend class ASTStmtReader; + size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return HasTemplateKWAndArgsInfo ? 1 : 0; + } public: static UnresolvedMemberExpr * @@ -3463,6 +3552,7 @@ public: return l.getBeginLoc(); return getMemberNameInfo().getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); @@ -3508,26 +3598,23 @@ inline TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() { /// The noexcept expression tests whether a given expression might throw. Its /// result is a boolean constant. class CXXNoexceptExpr : public Expr { + friend class ASTStmtReader; + bool Value : 1; Stmt *Operand; SourceRange Range; - friend class ASTStmtReader; - public: CXXNoexceptExpr(QualType Ty, Expr *Operand, CanThrowResult Val, SourceLocation Keyword, SourceLocation RParen) - : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, - /*TypeDependent*/false, - /*ValueDependent*/Val == CT_Dependent, - Val == CT_Dependent || Operand->isInstantiationDependent(), - Operand->containsUnexpandedParameterPack()), - Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) - { } + : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, + /*TypeDependent*/false, + /*ValueDependent*/Val == CT_Dependent, + Val == CT_Dependent || Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) {} - CXXNoexceptExpr(EmptyShell Empty) - : Expr(CXXNoexceptExprClass, Empty) - { } + CXXNoexceptExpr(EmptyShell Empty) : Expr(CXXNoexceptExprClass, Empty) {} Expr *getOperand() const { return static_cast<Expr*>(Operand); } @@ -3563,6 +3650,9 @@ public: /// template is instantiated, the pack expansion will instantiate to zero or /// or more function arguments to the function object \c f. class PackExpansionExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + SourceLocation EllipsisLoc; /// \brief The number of expansions that will be produced by this pack @@ -3574,21 +3664,18 @@ class PackExpansionExpr : public Expr { Stmt *Pattern; - friend class ASTStmtReader; - friend class ASTStmtWriter; - public: PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions) - : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), - Pattern->getObjectKind(), /*TypeDependent=*/true, - /*ValueDependent=*/true, /*InstantiationDependent=*/true, - /*ContainsUnexpandedParameterPack=*/false), - EllipsisLoc(EllipsisLoc), - NumExpansions(NumExpansions? *NumExpansions + 1 : 0), - Pattern(Pattern) { } + : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), + Pattern->getObjectKind(), /*TypeDependent=*/true, + /*ValueDependent=*/true, /*InstantiationDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), + EllipsisLoc(EllipsisLoc), + NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), + Pattern(Pattern) {} - PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { } + PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) {} /// \brief Retrieve the pattern of the pack expansion. Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); } @@ -3612,6 +3699,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return Pattern->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return EllipsisLoc; } static bool classof(const Stmt *T) { @@ -3624,7 +3712,6 @@ public: } }; - /// \brief Represents an expression that computes the length of a parameter /// pack. /// @@ -3637,6 +3724,10 @@ public: class SizeOfPackExpr final : public Expr, private llvm::TrailingObjects<SizeOfPackExpr, TemplateArgument> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// \brief The location of the \c sizeof keyword. SourceLocation OperatorLoc; @@ -3659,11 +3750,7 @@ class SizeOfPackExpr final unsigned Length; /// \brief The parameter pack. - NamedDecl *Pack; - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; + NamedDecl *Pack = nullptr; /// \brief Create an expression that computes the length of /// the given parameter pack. @@ -3684,7 +3771,7 @@ class SizeOfPackExpr final /// \brief Create an empty expression. SizeOfPackExpr(EmptyShell Empty, unsigned NumPartialArgs) - : Expr(SizeOfPackExprClass, Empty), Length(NumPartialArgs), Pack() {} + : Expr(SizeOfPackExprClass, Empty), Length(NumPartialArgs) {} public: static SizeOfPackExpr *Create(ASTContext &Context, SourceLocation OperatorLoc, @@ -3749,6 +3836,9 @@ public: /// \brief Represents a reference to a non-type template parameter /// that has been substituted with a template argument. class SubstNonTypeTemplateParmExpr : public Expr { + friend class ASTReader; + friend class ASTStmtReader; + /// \brief The replaced parameter. NonTypeTemplateParmDecl *Param; @@ -3758,10 +3848,8 @@ class SubstNonTypeTemplateParmExpr : public Expr { /// \brief The location of the non-type template parameter reference. SourceLocation NameLoc; - friend class ASTReader; - friend class ASTStmtReader; explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty) - : Expr(SubstNonTypeTemplateParmExprClass, Empty) { } + : Expr(SubstNonTypeTemplateParmExprClass, Empty) {} public: SubstNonTypeTemplateParmExpr(QualType type, @@ -3769,11 +3857,11 @@ public: SourceLocation loc, NonTypeTemplateParmDecl *param, Expr *replacement) - : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, - replacement->isTypeDependent(), replacement->isValueDependent(), - replacement->isInstantiationDependent(), - replacement->containsUnexpandedParameterPack()), - Param(param), Replacement(replacement), NameLoc(loc) {} + : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, + replacement->isTypeDependent(), replacement->isValueDependent(), + replacement->isInstantiationDependent(), + replacement->containsUnexpandedParameterPack()), + Param(param), Replacement(replacement), NameLoc(loc) {} SourceLocation getNameLoc() const { return NameLoc; } SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } @@ -3804,6 +3892,9 @@ public: /// arguments), this type will be replaced with the appropriate underlying /// expression at the current pack substitution index. class SubstNonTypeTemplateParmPackExpr : public Expr { + friend class ASTReader; + friend class ASTStmtReader; + /// \brief The non-type template parameter pack itself. NonTypeTemplateParmDecl *Param; @@ -3817,10 +3908,8 @@ class SubstNonTypeTemplateParmPackExpr : public Expr { /// \brief The location of the non-type template parameter pack reference. SourceLocation NameLoc; - friend class ASTReader; - friend class ASTStmtReader; explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) - : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) {} public: SubstNonTypeTemplateParmPackExpr(QualType T, @@ -3868,6 +3957,10 @@ public: class FunctionParmPackExpr final : public Expr, private llvm::TrailingObjects<FunctionParmPackExpr, ParmVarDecl *> { + friend class ASTReader; + friend class ASTStmtReader; + friend TrailingObjects; + /// \brief The function parameter pack which was referenced. ParmVarDecl *ParamPack; @@ -3881,10 +3974,6 @@ class FunctionParmPackExpr final SourceLocation NameLoc, unsigned NumParams, ParmVarDecl *const *Params); - friend TrailingObjects; - friend class ASTReader; - friend class ASTStmtReader; - public: static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T, ParmVarDecl *ParamPack, @@ -3901,7 +3990,7 @@ public: /// \brief Iterators over the parameters which the parameter pack expanded /// into. - typedef ParmVarDecl * const *iterator; + using iterator = ParmVarDecl * const *; iterator begin() const { return getTrailingObjects<ParmVarDecl *>(); } iterator end() const { return begin() + NumParameters; } @@ -3945,6 +4034,9 @@ public: /// declaration which is responsible for the lifetime extension. class MaterializeTemporaryExpr : public Expr { private: + friend class ASTStmtReader; + friend class ASTStmtWriter; + struct ExtraState { /// \brief The temporary-generating expression whose value will be /// materialized. @@ -3958,24 +4050,21 @@ private: }; llvm::PointerUnion<Stmt *, ExtraState *> State; - friend class ASTStmtReader; - friend class ASTStmtWriter; - void initializeExtraState(const ValueDecl *ExtendedBy, unsigned ManglingNumber); public: MaterializeTemporaryExpr(QualType T, Expr *Temporary, bool BoundToLvalueReference) - : Expr(MaterializeTemporaryExprClass, T, - BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, - Temporary->isTypeDependent(), Temporary->isValueDependent(), - Temporary->isInstantiationDependent(), - Temporary->containsUnexpandedParameterPack()), + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()), State(Temporary) {} MaterializeTemporaryExpr(EmptyShell Empty) - : Expr(MaterializeTemporaryExprClass, Empty) { } + : Expr(MaterializeTemporaryExprClass, Empty) {} Stmt *getTemporary() const { return State.is<Stmt *>() ? State.get<Stmt *>() @@ -4026,6 +4115,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return getTemporary()->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getTemporary()->getLocEnd(); } @@ -4053,14 +4143,15 @@ public: /// ( ... op expr ) /// ( expr op ... op expr ) class CXXFoldExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + SourceLocation LParenLoc; SourceLocation EllipsisLoc; SourceLocation RParenLoc; Stmt *SubExprs[2]; BinaryOperatorKind Opcode; - friend class ASTStmtReader; - friend class ASTStmtWriter; public: CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS, @@ -4073,6 +4164,7 @@ public: SubExprs[0] = LHS; SubExprs[1] = RHS; } + CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {} Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); } @@ -4082,10 +4174,13 @@ public: bool isRightFold() const { return getLHS() && getLHS()->containsUnexpandedParameterPack(); } + /// Does this produce a left-associated sequence of operators? bool isLeftFold() const { return !isRightFold(); } + /// Get the pattern, that is, the operand that contains an unexpanded pack. Expr *getPattern() const { return isLeftFold() ? getRHS() : getLHS(); } + /// Get the operand that doesn't contain a pack, for a binary fold. Expr *getInit() const { return isLeftFold() ? getLHS() : getRHS(); } @@ -4095,6 +4190,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } @@ -4121,13 +4217,15 @@ public: /// expression is evaluated, and its result is the result of the overall /// expression. class CoroutineSuspendExpr : public Expr { + friend class ASTStmtReader; + SourceLocation KeywordLoc; enum SubExpr { Common, Ready, Suspend, Resume, Count }; + Stmt *SubExprs[SubExpr::Count]; OpaqueValueExpr *OpaqueValue = nullptr; - friend class ASTStmtReader; public: CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common, Expr *Ready, Expr *Suspend, Expr *Resume, @@ -4142,6 +4240,7 @@ public: SubExprs[SubExpr::Suspend] = Suspend; SubExprs[SubExpr::Resume] = Resume; } + CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, QualType Ty, Expr *Common) : Expr(SC, Ty, VK_RValue, OK_Ordinary, true, true, true, @@ -4154,6 +4253,7 @@ public: SubExprs[SubExpr::Suspend] = nullptr; SubExprs[SubExpr::Resume] = nullptr; } + CoroutineSuspendExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { SubExprs[SubExpr::Common] = nullptr; SubExprs[SubExpr::Ready] = nullptr; @@ -4162,18 +4262,22 @@ public: } SourceLocation getKeywordLoc() const { return KeywordLoc; } + Expr *getCommonExpr() const { return static_cast<Expr*>(SubExprs[SubExpr::Common]); } + /// \brief getOpaqueValue - Return the opaque value placeholder. OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } Expr *getReadyExpr() const { return static_cast<Expr*>(SubExprs[SubExpr::Ready]); } + Expr *getSuspendExpr() const { return static_cast<Expr*>(SubExprs[SubExpr::Suspend]); } + Expr *getResumeExpr() const { return static_cast<Expr*>(SubExprs[SubExpr::Resume]); } @@ -4181,6 +4285,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return getCommonExpr()->getLocEnd(); } @@ -4198,6 +4303,7 @@ public: /// \brief Represents a 'co_await' expression. class CoawaitExpr : public CoroutineSuspendExpr { friend class ASTStmtReader; + public: CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready, Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue, @@ -4206,11 +4312,13 @@ public: Suspend, Resume, OpaqueValue) { CoawaitBits.IsImplicit = IsImplicit; } + CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand, bool IsImplicit = false) : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) { CoawaitBits.IsImplicit = IsImplicit; } + CoawaitExpr(EmptyShell Empty) : CoroutineSuspendExpr(CoawaitExprClass, Empty) {} @@ -4230,11 +4338,11 @@ public: /// \brief Represents a 'co_await' expression while the type of the promise /// is dependent. class DependentCoawaitExpr : public Expr { + friend class ASTStmtReader; + SourceLocation KeywordLoc; Stmt *SubExprs[2]; - friend class ASTStmtReader; - public: DependentCoawaitExpr(SourceLocation KeywordLoc, QualType Ty, Expr *Op, UnresolvedLookupExpr *OpCoawait) @@ -4255,12 +4363,15 @@ public: : Expr(DependentCoawaitExprClass, Empty) {} Expr *getOperand() const { return cast<Expr>(SubExprs[0]); } + UnresolvedLookupExpr *getOperatorCoawaitLookup() const { return cast<UnresolvedLookupExpr>(SubExprs[1]); } + SourceLocation getKeywordLoc() const { return KeywordLoc; } SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return getOperand()->getLocEnd(); } @@ -4275,6 +4386,7 @@ public: /// \brief Represents a 'co_yield' expression. class CoyieldExpr : public CoroutineSuspendExpr { friend class ASTStmtReader; + public: CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready, Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue) @@ -4295,6 +4407,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h b/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h index cd9381758618a..ab2df8a34819e 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h @@ -1,4 +1,4 @@ -//===--- ExprObjC.h - Classes for representing ObjC expressions -*- C++ -*-===// +//===- ExprObjC.h - Classes for representing ObjC expressions ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,28 +14,51 @@ #ifndef LLVM_CLANG_AST_EXPROBJC_H #define LLVM_CLANG_AST_EXPROBJC_H +#include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/SelectorLocationsKind.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstddef> +#include <cstdint> namespace clang { - class IdentifierInfo; - class ASTContext; + +class ASTContext; +class CXXBaseSpecifier; /// ObjCStringLiteral, used for Objective-C string literals /// i.e. @"foo". class ObjCStringLiteral : public Expr { Stmt *String; SourceLocation AtLoc; + public: ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) - : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, - false, false), - String(SL), AtLoc(L) {} + : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + String(SL), AtLoc(L) {} explicit ObjCStringLiteral(EmptyShell Empty) - : Expr(ObjCStringLiteralClass, Empty) {} + : Expr(ObjCStringLiteralClass, Empty) {} StringLiteral *getString() { return cast<StringLiteral>(String); } const StringLiteral *getString() const { return cast<StringLiteral>(String); } @@ -47,26 +70,26 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } SourceLocation getLocEnd() const LLVM_READONLY { return String->getLocEnd(); } + // Iterators + child_range children() { return child_range(&String, &String+1); } + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCStringLiteralClass; } - - // Iterators - child_range children() { return child_range(&String, &String+1); } }; /// ObjCBoolLiteralExpr - Objective-C Boolean Literal. -/// class ObjCBoolLiteralExpr : public Expr { bool Value; SourceLocation Loc; + public: - ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : - Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false, false), Value(val), Loc(l) {} - + ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) + : Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(val), Loc(l) {} explicit ObjCBoolLiteralExpr(EmptyShell Empty) - : Expr(ObjCBoolLiteralExprClass, Empty) { } + : Expr(ObjCBoolLiteralExprClass, Empty) {} bool getValue() const { return Value; } void setValue(bool V) { Value = V; } @@ -77,14 +100,14 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCBoolLiteralExprClass; - } - // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBoolLiteralExprClass; + } }; /// ObjCBoxedExpr - used for generalized expression boxing. @@ -95,15 +118,19 @@ class ObjCBoxedExpr : public Expr { Stmt *SubExpr; ObjCMethodDecl *BoxingMethod; SourceRange Range; + public: + friend class ASTStmtReader; + ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method, SourceRange R) - : Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary, - E->isTypeDependent(), E->isValueDependent(), - E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), - SubExpr(E), BoxingMethod(method), Range(R) {} + : Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary, + E->isTypeDependent(), E->isValueDependent(), + E->isInstantiationDependent(), + E->containsUnexpandedParameterPack()), + SubExpr(E), BoxingMethod(method), Range(R) {} explicit ObjCBoxedExpr(EmptyShell Empty) - : Expr(ObjCBoxedExprClass, Empty) {} + : Expr(ObjCBoxedExprClass, Empty) {} Expr *getSubExpr() { return cast<Expr>(SubExpr); } const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } @@ -116,27 +143,27 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return Range; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCBoxedExprClass; - } - // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } - typedef ConstExprIterator const_arg_iterator; + using const_arg_iterator = ConstExprIterator; const_arg_iterator arg_begin() const { return reinterpret_cast<Stmt const * const*>(&SubExpr); } + const_arg_iterator arg_end() const { return reinterpret_cast<Stmt const * const*>(&SubExpr + 1); } - - friend class ASTStmtReader; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBoxedExprClass; + } }; /// ObjCArrayLiteral - used for objective-c array containers; as in: @@ -153,9 +180,12 @@ class ObjCArrayLiteral final SourceRange SR); explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements) - : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} + : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} public: + friend class ASTStmtReader; + friend TrailingObjects; + static ObjCArrayLiteral *Create(const ASTContext &C, ArrayRef<Expr *> Elements, QualType T, ObjCMethodDecl * Method, @@ -168,10 +198,6 @@ public: SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCArrayLiteralClass; - } - /// \brief Retrieve elements of array of literals. Expr **getElements() { return getTrailingObjects<Expr *>(); } @@ -183,7 +209,7 @@ public: /// getNumElements - Return number of elements of objective-c array literal. unsigned getNumElements() const { return NumElements; } - /// getExpr - Return the Expr at the specified index. + /// getElement - Return the Element at the specified index. Expr *getElement(unsigned Index) { assert((Index < NumElements) && "Arg access out of range!"); return cast<Expr>(getElements()[Index]); @@ -203,8 +229,9 @@ public: reinterpret_cast<Stmt **>(getElements()) + NumElements); } - friend TrailingObjects; - friend class ASTStmtReader; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCArrayLiteralClass; + } }; /// \brief An element in an Objective-C dictionary literal. @@ -226,13 +253,17 @@ struct ObjCDictionaryElement { /// \brief Determines whether this dictionary element is a pack expansion. bool isPackExpansion() const { return EllipsisLoc.isValid(); } }; -} // end namespace clang + +} // namespace clang namespace llvm { + template <> struct isPodLike<clang::ObjCDictionaryElement> : std::true_type {}; -} + +} // namespace llvm namespace clang { + /// \brief Internal struct for storing Key/value pair. struct ObjCDictionaryLiteral_KeyValuePair { Expr *Key; @@ -274,12 +305,8 @@ class ObjCDictionaryLiteral final SourceRange Range; ObjCMethodDecl *DictWithObjectsMethod; - typedef ObjCDictionaryLiteral_KeyValuePair KeyValuePair; - typedef ObjCDictionaryLiteral_ExpansionData ExpansionData; - - size_t numTrailingObjects(OverloadToken<KeyValuePair>) const { - return NumElements; - } + using KeyValuePair = ObjCDictionaryLiteral_KeyValuePair; + using ExpansionData = ObjCDictionaryLiteral_ExpansionData; ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK, bool HasPackExpansions, @@ -288,10 +315,18 @@ class ObjCDictionaryLiteral final explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements, bool HasPackExpansions) - : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements), - HasPackExpansions(HasPackExpansions) {} + : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements), + HasPackExpansions(HasPackExpansions) {} + + size_t numTrailingObjects(OverloadToken<KeyValuePair>) const { + return NumElements; + } public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + static ObjCDictionaryLiteral *Create(const ASTContext &C, ArrayRef<ObjCDictionaryElement> VK, bool HasPackExpansions, @@ -320,17 +355,14 @@ public: return Result; } - ObjCMethodDecl *getDictWithObjectsMethod() const - { return DictWithObjectsMethod; } + ObjCMethodDecl *getDictWithObjectsMethod() const { + return DictWithObjectsMethod; + } SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCDictionaryLiteralClass; - } - + // Iterators child_range children() { // Note: we're taking advantage of the layout of the KeyValuePair struct @@ -342,12 +374,11 @@ public: reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()) + NumElements * 2); } - - friend class ASTStmtReader; - friend class ASTStmtWriter; - friend TrailingObjects; -}; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCDictionaryLiteralClass; + } +}; /// ObjCEncodeExpr, used for \@encode in Objective-C. \@encode has the same /// type and behavior as StringLiteral except that the string initializer is @@ -355,19 +386,19 @@ public: class ObjCEncodeExpr : public Expr { TypeSourceInfo *EncodedType; SourceLocation AtLoc, RParenLoc; + public: ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, SourceLocation at, SourceLocation rp) - : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, - EncodedType->getType()->isDependentType(), - EncodedType->getType()->isDependentType(), - EncodedType->getType()->isInstantiationDependentType(), - EncodedType->getType()->containsUnexpandedParameterPack()), - EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} + : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isInstantiationDependentType(), + EncodedType->getType()->containsUnexpandedParameterPack()), + EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} - SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -376,6 +407,7 @@ public: QualType getEncodedType() const { return EncodedType->getType(); } TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; } + void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) { EncodedType = EncType; } @@ -383,28 +415,29 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCEncodeExprClass; - } - // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCEncodeExprClass; + } }; /// ObjCSelectorExpr used for \@selector in Objective-C. class ObjCSelectorExpr : public Expr { Selector SelName; SourceLocation AtLoc, RParenLoc; + public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, SourceLocation rp) - : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, - false, false), - SelName(selInfo), AtLoc(at), RParenLoc(rp){} + : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + SelName(selInfo), AtLoc(at), RParenLoc(rp) {} explicit ObjCSelectorExpr(EmptyShell Empty) - : Expr(ObjCSelectorExprClass, Empty) {} + : Expr(ObjCSelectorExprClass, Empty) {} Selector getSelector() const { return SelName; } void setSelector(Selector S) { SelName = S; } @@ -420,14 +453,14 @@ public: /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return SelName.getNumArgs(); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCSelectorExprClass; - } - // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSelectorExprClass; + } }; /// ObjCProtocolExpr used for protocol expression in Objective-C. @@ -441,14 +474,18 @@ public: class ObjCProtocolExpr : public Expr { ObjCProtocolDecl *TheProtocol; SourceLocation AtLoc, ProtoLoc, RParenLoc; + public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, SourceLocation at, SourceLocation protoLoc, SourceLocation rp) - : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, - false, false), - TheProtocol(protocol), AtLoc(at), ProtoLoc(protoLoc), RParenLoc(rp) {} + : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + TheProtocol(protocol), AtLoc(at), ProtoLoc(protoLoc), RParenLoc(rp) {} explicit ObjCProtocolExpr(EmptyShell Empty) - : Expr(ObjCProtocolExprClass, Empty) {} + : Expr(ObjCProtocolExprClass, Empty) {} ObjCProtocolDecl *getProtocol() const { return TheProtocol; } void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; } @@ -462,17 +499,14 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCProtocolExprClass; - } - // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } - friend class ASTStmtReader; - friend class ASTStmtWriter; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCProtocolExprClass; + } }; /// ObjCIvarRefExpr - A reference to an ObjC instance variable. @@ -480,27 +514,31 @@ class ObjCIvarRefExpr : public Expr { ObjCIvarDecl *D; Stmt *Base; SourceLocation Loc; + /// OpLoc - This is the location of '.' or '->' SourceLocation OpLoc; - - bool IsArrow:1; // True if this is "X->F", false if this is "X.F". - bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). + + // True if this is "X->F", false if this is "X.F". + bool IsArrow : 1; + + // True if ivar reference has no base (self assumed). + bool IsFreeIvar : 1; public: ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, SourceLocation l, SourceLocation oploc, Expr *base, - bool arrow = false, bool freeIvar = false) : - Expr(ObjCIvarRefExprClass, t, VK_LValue, - d->isBitField() ? OK_BitField : OK_Ordinary, - /*TypeDependent=*/false, base->isValueDependent(), - base->isInstantiationDependent(), - base->containsUnexpandedParameterPack()), - D(d), Base(base), Loc(l), OpLoc(oploc), - IsArrow(arrow), IsFreeIvar(freeIvar) {} + bool arrow = false, bool freeIvar = false) + : Expr(ObjCIvarRefExprClass, t, VK_LValue, + d->isBitField() ? OK_BitField : OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + D(d), Base(base), Loc(l), OpLoc(oploc), IsArrow(arrow), + IsFreeIvar(freeIvar) {} explicit ObjCIvarRefExpr(EmptyShell Empty) - : Expr(ObjCIvarRefExprClass, Empty) {} + : Expr(ObjCIvarRefExprClass, Empty) {} ObjCIvarDecl *getDecl() { return D; } const ObjCIvarDecl *getDecl() const { return D; } @@ -526,12 +564,12 @@ public: SourceLocation getOpLoc() const { return OpLoc; } void setOpLoc(SourceLocation L) { OpLoc = L; } + // Iterators + child_range children() { return child_range(&Base, &Base+1); } + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCIvarRefExprClass; } - - // Iterators - child_range children() { return child_range(&Base, &Base+1); } }; /// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC @@ -542,7 +580,7 @@ private: /// pointer is an (optional) ObjCMethodDecl and Setter may be set. /// if the bool is false, this is an explicit property reference; /// the pointer is an ObjCPropertyDecl and Setter is always null. - llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; + llvm::PointerIntPair<NamedDecl *, 1, bool> PropertyOrGetter; /// \brief Indicates whether the property reference will result in a message /// to the getter, the setter, or both. @@ -567,40 +605,39 @@ private: /// the location of the 'super' keyword. When it's an interface, /// this is that interface. SourceLocation ReceiverLoc; - llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver; + llvm::PointerUnion3<Stmt *, const Type *, ObjCInterfaceDecl *> Receiver; public: ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, Expr *base) - : Expr(ObjCPropertyRefExprClass, t, VK, OK, - /*TypeDependent=*/false, base->isValueDependent(), - base->isInstantiationDependent(), - base->containsUnexpandedParameterPack()), - PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), - IdLoc(l), ReceiverLoc(), Receiver(base) { + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), IdLoc(l), Receiver(base) { assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, SourceLocation sl, QualType st) - : Expr(ObjCPropertyRefExprClass, t, VK, OK, - /*TypeDependent=*/false, false, st->isInstantiationDependentType(), - st->containsUnexpandedParameterPack()), - PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), - IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, false, st->isInstantiationDependentType(), + st->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), IdLoc(l), ReceiverLoc(sl), + Receiver(st.getTypePtr()) { assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, Expr *Base) - : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, - Base->isValueDependent(), Base->isInstantiationDependent(), - Base->containsUnexpandedParameterPack()), - PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), - IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, + Base->isValueDependent(), Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), Receiver(Base) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -608,9 +645,9 @@ public: QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, SourceLocation SuperLoc, QualType SuperTy) - : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), - PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), - IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } @@ -618,14 +655,14 @@ public: QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation IdLoc, SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) - : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), - PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), - IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } explicit ObjCPropertyRefExpr(EmptyShell Empty) - : Expr(ObjCPropertyRefExprClass, Empty) {} + : Expr(ObjCPropertyRefExprClass, Empty) {} bool isImplicitProperty() const { return PropertyOrGetter.getInt(); } bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); } @@ -689,6 +726,7 @@ public: SourceLocation getLocation() const { return IdLoc; } SourceLocation getReceiverLocation() const { return ReceiverLoc; } + QualType getSuperReceiverType() const { return QualType(Receiver.get<const Type*>(), 0); } @@ -696,6 +734,7 @@ public: ObjCInterfaceDecl *getClassReceiver() const { return Receiver.get<ObjCInterfaceDecl*>(); } + bool isObjectReceiver() const { return Receiver.is<Stmt*>(); } bool isSuperReceiver() const { return Receiver.is<const Type*>(); } bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } @@ -706,11 +745,8 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCPropertyRefExprClass; - } + SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; } // Iterators child_range children() { @@ -721,15 +757,21 @@ public: return child_range(child_iterator(), child_iterator()); } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCPropertyRefExprClass; + } + private: friend class ASTStmtReader; friend class ASTStmtWriter; + void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) { PropertyOrGetter.setPointer(D); PropertyOrGetter.setInt(false); SetterAndMethodRefFlags.setPointer(nullptr); SetterAndMethodRefFlags.setInt(methRefFlags); } + void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, unsigned methRefFlags) { PropertyOrGetter.setPointer(Getter); @@ -737,6 +779,7 @@ private: SetterAndMethodRefFlags.setPointer(Setter); SetterAndMethodRefFlags.setInt(methRefFlags); } + void setBase(Expr *Base) { Receiver = Base; } void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; } @@ -756,10 +799,10 @@ private: /// ObjCSubscriptRefExpr - used for array and dictionary subscripting. /// array[4] = array[3]; dictionary[key] = dictionary[alt_key]; -/// class ObjCSubscriptRefExpr : public Expr { // Location of ']' in an indexing expression. SourceLocation RBracket; + // array/dictionary base expression. // for arrays, this is a numeric expression. For dictionaries, this is // an objective-c object pointer expression. @@ -773,24 +816,24 @@ class ObjCSubscriptRefExpr : public Expr { ObjCMethodDecl *SetAtIndexMethodDecl; public: - ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T, ExprValueKind VK, ExprObjectKind OK, ObjCMethodDecl *getMethod, ObjCMethodDecl *setMethod, SourceLocation RB) - : Expr(ObjCSubscriptRefExprClass, T, VK, OK, - base->isTypeDependent() || key->isTypeDependent(), - base->isValueDependent() || key->isValueDependent(), - base->isInstantiationDependent() || key->isInstantiationDependent(), - (base->containsUnexpandedParameterPack() || - key->containsUnexpandedParameterPack())), - RBracket(RB), - GetAtIndexMethodDecl(getMethod), - SetAtIndexMethodDecl(setMethod) - {SubExprs[BASE] = base; SubExprs[KEY] = key;} + : Expr(ObjCSubscriptRefExprClass, T, VK, OK, + base->isTypeDependent() || key->isTypeDependent(), + base->isValueDependent() || key->isValueDependent(), + (base->isInstantiationDependent() || + key->isInstantiationDependent()), + (base->containsUnexpandedParameterPack() || + key->containsUnexpandedParameterPack())), + RBracket(RB), GetAtIndexMethodDecl(getMethod), + SetAtIndexMethodDecl(setMethod) { + SubExprs[BASE] = base; SubExprs[KEY] = key; + } explicit ObjCSubscriptRefExpr(EmptyShell Empty) - : Expr(ObjCSubscriptRefExprClass, Empty) {} + : Expr(ObjCSubscriptRefExprClass, Empty) {} SourceLocation getRBracket() const { return RBracket; } void setRBracket(SourceLocation RB) { RBracket = RB; } @@ -798,11 +841,8 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return SubExprs[BASE]->getLocStart(); } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCSubscriptRefExprClass; - } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; } Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); } void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; } @@ -825,10 +865,14 @@ public: child_range children() { return child_range(SubExprs, SubExprs+END_EXPR); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSubscriptRefExprClass; + } + private: friend class ASTStmtReader; }; - /// \brief An expression that sends a message to the given Objective-C /// object or class. @@ -856,14 +900,13 @@ private: /// The "void *" trailing objects are actually ONE void * (the /// receiver pointer), and NumArgs Expr *. But due to the /// implementation of children(), these must be together contiguously. - class ObjCMessageExpr final : public Expr, private llvm::TrailingObjects<ObjCMessageExpr, void *, SourceLocation> { /// \brief Stores either the selector that this message is sending /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer /// referring to the method that we type-checked against. - uintptr_t SelectorOrMethod; + uintptr_t SelectorOrMethod = 0; enum { NumArgsBitWidth = 16 }; @@ -904,16 +947,9 @@ class ObjCMessageExpr final /// brackets ('[' and ']', respectively). SourceLocation LBracLoc, RBracLoc; - size_t numTrailingObjects(OverloadToken<void *>) const { return NumArgs + 1; } - - void setNumArgs(unsigned Num) { - assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!"); - NumArgs = Num; - } - ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) - : Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0), - HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) { + : Expr(ObjCMessageExprClass, Empty), Kind(0), HasMethod(false), + IsDelegateInitCall(false), IsImplicit(false), SelLocsKind(0) { setNumArgs(NumArgs); } @@ -950,6 +986,13 @@ class ObjCMessageExpr final SourceLocation RBracLoc, bool isImplicit); + size_t numTrailingObjects(OverloadToken<void *>) const { return NumArgs + 1; } + + void setNumArgs(unsigned Num) { + assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!"); + NumArgs = Num; + } + void initArgsAndSelLocs(ArrayRef<Expr *> Args, ArrayRef<SourceLocation> SelLocs, SelectorLocationsKind SelLocsK); @@ -965,6 +1008,7 @@ class ObjCMessageExpr final SelectorLocationsKind getSelLocsKind() const { return (SelectorLocationsKind)SelLocsKind; } + bool hasStandardSelLocs() const { return getSelLocsKind() != SelLoc_NonStandard; } @@ -997,14 +1041,21 @@ class ObjCMessageExpr final unsigned NumStoredSelLocs); public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// \brief The kind of receiver this message is sending to. enum ReceiverKind { /// \brief The receiver is a class. Class = 0, + /// \brief The receiver is an object instance. Instance, + /// \brief The receiver is a superclass. SuperClass, + /// \brief The receiver is the instance of the superclass object. SuperInstance }; @@ -1029,7 +1080,7 @@ public: /// \param Sel The selector used to determine which method gets called. /// /// \param Method The Objective-C method against which this message - /// send was type-checked. May be NULL. + /// send was type-checked. May be nullptr. /// /// \param Args The message send arguments. /// @@ -1065,7 +1116,7 @@ public: /// \param Sel The selector used to determine which method gets called. /// /// \param Method The Objective-C method against which this message - /// send was type-checked. May be NULL. + /// send was type-checked. May be nullptr. /// /// \param Args The message send arguments. /// @@ -1099,7 +1150,7 @@ public: /// \param Sel The selector used to determine which method gets called. /// /// \param Method The Objective-C method against which this message - /// send was type-checked. May be NULL. + /// send was type-checked. May be nullptr. /// /// \param Args The message send arguments. /// @@ -1175,11 +1226,11 @@ public: if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo()) return TSInfo->getType(); - return QualType(); + return {}; } /// \brief Returns a type-source information of a class message - /// send, or NULL if the message is not a class message. + /// send, or nullptr if the message is not a class message. TypeSourceInfo *getClassReceiverTypeInfo() const { if (getReceiverKind() == Class) return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer()); @@ -1220,7 +1271,7 @@ public: /// whether the message is a class or an instance method, whether it /// is a send to super or not, etc. /// - /// \returns The Objective-C interface if known, otherwise NULL. + /// \returns The Objective-C interface if known, otherwise nullptr. ObjCInterfaceDecl *getReceiverInterface() const; /// \brief Retrieve the type referred to by 'super'. @@ -1295,6 +1346,7 @@ public: assert(Arg < NumArgs && "Arg access out of range!"); return getArgs()[Arg]; } + /// setArg - Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { assert(Arg < NumArgs && "Arg access out of range!"); @@ -1315,6 +1367,7 @@ public: return getLocStart(); return getSelectorLoc(0); } + SourceLocation getSelectorLoc(unsigned Index) const { assert(Index < getNumSelectorLocs() && "Index out of range!"); if (hasStandardSelLocs()) @@ -1341,18 +1394,15 @@ public: LBracLoc = R.getBegin(); RBracLoc = R.getEnd(); } + SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; } SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCMessageExprClass; - } - // Iterators child_range children(); - typedef ExprIterator arg_iterator; - typedef ConstExprIterator const_arg_iterator; + using arg_iterator = ExprIterator; + using const_arg_iterator = ConstExprIterator; llvm::iterator_range<arg_iterator> arguments() { return llvm::make_range(arg_begin(), arg_end()); @@ -1363,19 +1413,22 @@ public: } arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); } + arg_iterator arg_end() { return reinterpret_cast<Stmt **>(getArgs() + NumArgs); } + const_arg_iterator arg_begin() const { return reinterpret_cast<Stmt const * const*>(getArgs()); } + const_arg_iterator arg_end() const { return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs); } - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCMessageExprClass; + } }; /// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. @@ -1392,17 +1445,18 @@ class ObjCIsaExpr : public Expr { /// IsArrow - True if this is "X->F", false if this is "X.F". bool IsArrow; + public: ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, SourceLocation oploc, QualType ty) - : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, - /*TypeDependent=*/false, base->isValueDependent(), - base->isInstantiationDependent(), - /*ContainsUnexpandedParameterPack=*/false), - Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {} + : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + /*ContainsUnexpandedParameterPack=*/false), + Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {} /// \brief Build an empty expression. - explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { } + explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) {} void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast<Expr>(Base); } @@ -1430,15 +1484,14 @@ public: SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; } + // Iterators + child_range children() { return child_range(&Base, &Base+1); } + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCIsaExprClass; } - - // Iterators - child_range children() { return child_range(&Base, &Base+1); } }; - /// ObjCIndirectCopyRestoreExpr - Represents the passing of a function /// argument by indirect copy-restore in ARC. This is used to support /// passing indirect arguments with the wrong lifetime, e.g. when @@ -1462,27 +1515,27 @@ public: /// __autoreleasing; this qualifier is ignored when initializing /// the value. class ObjCIndirectCopyRestoreExpr : public Expr { + friend class ASTReader; + friend class ASTStmtReader; + Stmt *Operand; // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1; - friend class ASTReader; - friend class ASTStmtReader; + explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) + : Expr(ObjCIndirectCopyRestoreExprClass, Empty) {} void setShouldCopy(bool shouldCopy) { ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy; } - explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) - : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { } - public: ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy) - : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, - operand->isTypeDependent(), operand->isValueDependent(), - operand->isInstantiationDependent(), - operand->containsUnexpandedParameterPack()), - Operand(operand) { + : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, + operand->isTypeDependent(), operand->isValueDependent(), + operand->isInstantiationDependent(), + operand->containsUnexpandedParameterPack()), + Operand(operand) { setShouldCopy(shouldCopy); } @@ -1519,26 +1572,26 @@ public: class ObjCBridgedCastExpr final : public ExplicitCastExpr, private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class CastExpr; + friend TrailingObjects; + SourceLocation LParenLoc; SourceLocation BridgeKeywordLoc; unsigned Kind : 2; - friend TrailingObjects; - friend class CastExpr; - friend class ASTStmtReader; - friend class ASTStmtWriter; - public: ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, CastKind CK, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *Operand) - : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, - CK, Operand, 0, TSInfo), - LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } + : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, + CK, Operand, 0, TSInfo), + LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) {} /// \brief Construct an empty Objective-C bridged cast. explicit ObjCBridgedCastExpr(EmptyShell Shell) - : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { } + : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) {} SourceLocation getLParenLoc() const { return LParenLoc; } @@ -1554,6 +1607,7 @@ public: SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return getSubExpr()->getLocEnd(); } @@ -1577,10 +1631,11 @@ public: /// expressions. /// class ObjCAvailabilityCheckExpr : public Expr { + friend class ASTStmtReader; + VersionTuple VersionToCheck; SourceLocation AtLoc, RParen; - friend class ASTStmtReader; public: ObjCAvailabilityCheckExpr(VersionTuple VersionToCheck, SourceLocation AtLoc, SourceLocation RParen, QualType Ty) @@ -1608,6 +1663,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_EXPROBJC_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h index 51d0c30ad23bf..81492aec6e13e 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h @@ -16,34 +16,159 @@ #include "clang/AST/ASTImporter.h" #include "clang/AST/ExternalASTSource.h" +#include "llvm/Support/raw_ostream.h" namespace clang { +/// ExternalASTSource implementation that merges information from several +/// ASTContexts. +/// +/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import +/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts +/// in response to ExternalASTSource API calls. +/// +/// When lookup occurs in the resulting imported DeclContexts, the original +/// DeclContexts need to be queried. Roughly, there are three cases here: +/// +/// - The DeclContext of origin can be found by simple name lookup. In this +/// case, no additional state is required. +/// +/// - The DeclContext of origin is different from what would be found by name +/// lookup. In this case, Origins contains an entry overriding lookup and +/// specifying the correct pair of DeclContext/ASTContext. +/// +/// - The DeclContext of origin was determined by another ExterenalASTMerger. +/// (This is possible when the source ASTContext for one of the Importers has +/// its own ExternalASTMerger). The origin must be properly forwarded in this +/// case. +/// +/// ExternalASTMerger's job is to maintain the data structures necessary to +/// allow this. The data structures themselves can be extracted (read-only) and +/// copied for re-use. class ExternalASTMerger : public ExternalASTSource { public: - struct ImporterPair { - std::unique_ptr<ASTImporter> Forward; - std::unique_ptr<ASTImporter> Reverse; + /// A single origin for a DeclContext. Unlike Decls, DeclContexts do + /// not allow their containing ASTContext to be determined in all cases. + struct DCOrigin { + DeclContext *DC; + ASTContext *AST; }; + typedef std::map<const DeclContext *, DCOrigin> OriginMap; + typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector; private: - std::vector<ImporterPair> Importers; + /// One importer exists for each source. + ImporterVector Importers; + /// Overrides in case name lookup would return nothing or would return + /// the wrong thing. + OriginMap Origins; + /// The installed log stream. + llvm::raw_ostream *LogStream; public: - struct ImporterEndpoint { + /// The target for an ExternalASTMerger. + /// + /// ASTImporters require both ASTContext and FileManager to be able to + /// import SourceLocations properly. + struct ImporterTarget { ASTContext &AST; FileManager &FM; }; - ExternalASTMerger(const ImporterEndpoint &Target, - llvm::ArrayRef<ImporterEndpoint> Sources); + /// A source for an ExternalASTMerger. + /// + /// ASTImporters require both ASTContext and FileManager to be able to + /// import SourceLocations properly. Additionally, when import occurs for + /// a DeclContext whose origin has been overridden, then this + /// ExternalASTMerger must be able to determine that. + struct ImporterSource { + ASTContext &AST; + FileManager &FM; + const OriginMap &OM; + }; +private: + /// The target for this ExtenralASTMerger. + ImporterTarget Target; + +public: + ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef<ImporterSource> Sources); + + /// Add a set of ASTContexts as possible origins. + /// + /// Usually the set will be initialized in the constructor, but long-lived + /// ExternalASTMergers may neeed to import from new sources (for example, + /// newly-parsed source files). + /// + /// Ensures that Importers does not gain duplicate entries as a result. + void AddSources(llvm::ArrayRef<ImporterSource> Sources); + + /// Remove a set of ASTContexts as possible origins. + /// + /// Sometimes an origin goes away (for example, if a source file gets + /// superseded by a newer version). + /// + /// The caller is responsible for ensuring that this doesn't leave + /// DeclContexts that can't be completed. + void RemoveSources(llvm::ArrayRef<ImporterSource> Sources); + + /// Implementation of the ExternalASTSource API. bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; + /// Implementation of the ExternalASTSource API. void FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Result) override; + + /// Implementation of the ExternalASTSource API. + void CompleteType(TagDecl *Tag) override; + + /// Implementation of the ExternalASTSource API. + void CompleteType(ObjCInterfaceDecl *Interface) override; + + /// Returns true if DC can be found in any source AST context. + bool CanComplete(DeclContext *DC); + + /// Records an origin in Origins only if name lookup would find + /// something different or nothing at all. + void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + + /// Regardless of any checks, override the Origin for a DeclContext. + void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + + /// Get a read-only view of the Origins map, for use in constructing + /// an ImporterSource for another ExternalASTMerger. + const OriginMap &GetOrigins() { return Origins; } + + /// Returns true if Importers contains an ASTImporter whose source is + /// OriginContext. + bool HasImporterForOrigin(ASTContext &OriginContext); + + /// Returns a reference to the ASTRImporter from Importers whose origin + /// is OriginContext. This allows manual import of ASTs while preserving the + /// OriginMap correctly. + ASTImporter &ImporterForOrigin(ASTContext &OriginContext); + + /// Sets the current log stream. + void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } +private: + /// Records and origin in Origins. + void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, + ASTImporter &importer); + + /// Performs an action for every DeclContext that is identified as + /// corresponding (either by forced origin or by name lookup) to DC. + template <typename CallbackType> + void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); + +public: + /// Log something if there is a logging callback installed. + llvm::raw_ostream &logs() { return *LogStream; } + + /// True if the log stream is not llvm::nulls(); + bool LoggingEnabled() { return LogStream != &llvm::nulls(); } }; } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h index d8dd18ecb8d3b..be013c5d6b6a1 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h +++ b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h @@ -1,4 +1,4 @@ -//===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===// +//===- ExternalASTSource.h - Abstract External AST Interface ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,24 +11,44 @@ // construction of AST nodes from some external source. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H #define LLVM_CLANG_AST_EXTERNALASTSOURCE_H #include "clang/AST/CharUnits.h" #include "clang/AST/DeclBase.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <string> +#include <utility> namespace clang { class ASTConsumer; +class ASTContext; class CXXBaseSpecifier; class CXXCtorInitializer; +class CXXRecordDecl; class DeclarationName; -class ExternalSemaSource; // layering violation required for downcasting class FieldDecl; -class Module; +class IdentifierInfo; class NamedDecl; +class ObjCInterfaceDecl; class RecordDecl; class Selector; class Stmt; @@ -42,30 +62,31 @@ class TagDecl; /// actual type and declaration nodes, and read parts of declaration /// contexts. class ExternalASTSource : public RefCountedBase<ExternalASTSource> { + friend class ExternalSemaSource; + /// Generation number for this external AST source. Must be increased /// whenever we might have added new redeclarations for existing decls. - uint32_t CurrentGeneration; + uint32_t CurrentGeneration = 0; /// \brief Whether this AST source also provides information for /// semantic analysis. - bool SemaSource; - - friend class ExternalSemaSource; + bool SemaSource = false; public: - ExternalASTSource() : CurrentGeneration(0), SemaSource(false) { } - + ExternalASTSource() = default; virtual ~ExternalASTSource(); /// \brief RAII class for safely pairing a StartedDeserializing call /// with FinishedDeserializing. class Deserializing { ExternalASTSource *Source; + public: explicit Deserializing(ExternalASTSource *source) : Source(source) { assert(Source); Source->StartedDeserializing(); } + ~Deserializing() { Source->FinishedDeserializing(); } @@ -122,7 +143,7 @@ public: virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); /// \brief Update an out-of-date identifier. - virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { } + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {} /// \brief Find all declarations with the given name in the given context, /// and add them to the context by calling SetExternalVisibleDeclsForName @@ -154,12 +175,13 @@ public: const Module *ClangModule = nullptr; public: - ASTSourceDescriptor(){}; + ASTSourceDescriptor() = default; ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, ASTFileSignature Signature) : PCHModuleName(std::move(Name)), Path(std::move(Path)), - ASTFile(std::move(ASTFile)), Signature(Signature){}; + ASTFile(std::move(ASTFile)), Signature(Signature) {} ASTSourceDescriptor(const Module &M); + std::string getModuleName() const; StringRef getPath() const { return Path; } StringRef getASTFile() const { return ASTFile; } @@ -246,7 +268,6 @@ public: /// The default implementation of this method is a no-op. virtual void PrintStats(); - /// \brief Perform layout on the given record. /// /// This routine allows the external AST source to provide an specific @@ -289,7 +310,7 @@ public: size_t mmap_bytes; MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) - : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} + : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} }; /// Return the amount of memory used by memory buffers, breaking down @@ -329,12 +350,12 @@ struct LazyOffsetPtr { /// /// If the low bit is clear, a pointer to the AST node. If the low /// bit is set, the upper 63 bits are the offset. - mutable uint64_t Ptr; + mutable uint64_t Ptr = 0; public: - LazyOffsetPtr() : Ptr(0) { } + LazyOffsetPtr() = default; + explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {} - explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { } explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); if (Offset == 0) @@ -392,15 +413,16 @@ struct LazyGenerationalUpdatePtr { /// A cache of the value of this pointer, in the most recent generation in /// which we queried it. struct LazyData { - LazyData(ExternalASTSource *Source, T Value) - : ExternalSource(Source), LastGeneration(0), LastValue(Value) {} ExternalASTSource *ExternalSource; - uint32_t LastGeneration; + uint32_t LastGeneration = 0; T LastValue; + + LazyData(ExternalASTSource *Source, T Value) + : ExternalSource(Source), LastValue(Value) {} }; // Our value is represented as simply T if there is no external AST source. - typedef llvm::PointerUnion<T, LazyData*> ValueType; + using ValueType = llvm::PointerUnion<T, LazyData*>; ValueType Value; LazyGenerationalUpdatePtr(ValueType V) : Value(V) {} @@ -459,25 +481,31 @@ public: return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr)); } }; -} // end namespace clang + +} // namespace clang /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be /// placed into a PointerUnion. namespace llvm { + template<typename Owner, typename T, void (clang::ExternalASTSource::*Update)(Owner)> struct PointerLikeTypeTraits< clang::LazyGenerationalUpdatePtr<Owner, T, Update>> { - typedef clang::LazyGenerationalUpdatePtr<Owner, T, Update> Ptr; + using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>; + static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); } static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); } + enum { NumLowBitsAvailable = PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1 }; }; -} + +} // namespace llvm namespace clang { + /// \brief Represents a lazily-loaded vector of data. /// /// The lazily-loaded vector of data contains data that is partially loaded @@ -511,13 +539,14 @@ public: class iterator : public llvm::iterator_adaptor_base< iterator, int, std::random_access_iterator_tag, T, int, T *, T &> { + friend class LazyVector; + LazyVector *Self; iterator(LazyVector *Self, int Position) : iterator::iterator_adaptor_base(Position), Self(Self) {} bool isLoaded() const { return this->I < 0; } - friend class LazyVector; public: iterator() : iterator(nullptr, 0) {} @@ -562,23 +591,23 @@ public: }; /// \brief A lazy pointer to a statement. -typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> - LazyDeclStmtPtr; +using LazyDeclStmtPtr = + LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>; /// \brief A lazy pointer to a declaration. -typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> - LazyDeclPtr; +using LazyDeclPtr = + LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>; /// \brief A lazy pointer to a set of CXXCtorInitializers. -typedef LazyOffsetPtr<CXXCtorInitializer *, uint64_t, - &ExternalASTSource::GetExternalCXXCtorInitializers> - LazyCXXCtorInitializersPtr; +using LazyCXXCtorInitializersPtr = + LazyOffsetPtr<CXXCtorInitializer *, uint64_t, + &ExternalASTSource::GetExternalCXXCtorInitializers>; /// \brief A lazy pointer to a set of CXXBaseSpecifiers. -typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, - &ExternalASTSource::GetExternalCXXBaseSpecifiers> - LazyCXXBaseSpecifiersPtr; +using LazyCXXBaseSpecifiersPtr = + LazyOffsetPtr<CXXBaseSpecifier, uint64_t, + &ExternalASTSource::GetExternalCXXBaseSpecifiers>; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h b/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h index adf63a3aea69c..3b3e4367d56c3 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h +++ b/contrib/llvm/tools/clang/include/clang/AST/GlobalDecl.h @@ -1,4 +1,4 @@ -//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===// +//===- GlobalDecl.h - Global declaration holder -----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,6 +19,12 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/Basic/ABI.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/type_traits.h" +#include <cassert> namespace clang { @@ -27,7 +33,7 @@ namespace clang { /// a CXXDestructorDecl and the destructor type (Base, Complete) or /// a VarDecl, a FunctionDecl or a BlockDecl. class GlobalDecl { - llvm::PointerIntPair<const Decl*, 2> Value; + llvm::PointerIntPair<const Decl *, 2> Value; void Init(const Decl *D) { assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); @@ -37,19 +43,15 @@ class GlobalDecl { } public: - GlobalDecl() {} - + GlobalDecl() = default; GlobalDecl(const VarDecl *D) { Init(D);} GlobalDecl(const FunctionDecl *D) { Init(D); } GlobalDecl(const BlockDecl *D) { Init(D); } GlobalDecl(const CapturedDecl *D) { Init(D); } GlobalDecl(const ObjCMethodDecl *D) { Init(D); } GlobalDecl(const OMPDeclareReductionDecl *D) { Init(D); } - - GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) - : Value(D, Type) {} - GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) - : Value(D, Type) {} + GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {} + GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {} GlobalDecl getCanonicalDecl() const { GlobalDecl CanonGD; @@ -90,10 +92,9 @@ public: } }; -} // end namespace clang +} // namespace clang namespace llvm { - template<class> struct DenseMapInfo; template<> struct DenseMapInfo<clang::GlobalDecl> { static inline clang::GlobalDecl getEmptyKey() { @@ -113,7 +114,6 @@ namespace llvm { clang::GlobalDecl RHS) { return LHS == RHS; } - }; // GlobalDecl isn't *technically* a POD type. However, its copy constructor, @@ -122,6 +122,7 @@ namespace llvm { struct isPodLike<clang::GlobalDecl> { static const bool value = true; }; -} // end namespace llvm -#endif +} // namespace llvm + +#endif // LLVM_CLANG_AST_GLOBALDECL_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h new file mode 100644 index 0000000000000..264f20f19ad5b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h @@ -0,0 +1,164 @@ +//===--- LexicallyOrderedRecursiveASTVisitor.h - ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LexicallyOrderedRecursiveASTVisitor interface, which +// recursively traverses the entire AST in a lexical order. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H + +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/SaveAndRestore.h" + +namespace clang { + +/// A RecursiveASTVisitor subclass that guarantees that AST traversal is +/// performed in a lexical order (i.e. the order in which declarations are +/// written in the source). +/// +/// RecursiveASTVisitor doesn't guarantee lexical ordering because there are +/// some declarations, like Objective-C @implementation declarations +/// that might be represented in the AST differently to how they were written +/// in the source. +/// In particular, Objective-C @implementation declarations may contain +/// non-Objective-C declarations, like functions: +/// +/// @implementation MyClass +/// +/// - (void) method { } +/// void normalFunction() { } +/// +/// @end +/// +/// Clang's AST stores these declarations outside of the @implementation +/// declaration, so the example above would be represented using the following +/// AST: +/// |-ObjCImplementationDecl ... MyClass +/// | `-ObjCMethodDecl ... method +/// | ... +/// `-FunctionDecl ... normalFunction +/// ... +/// +/// This class ensures that these declarations are traversed before the +/// corresponding TraverseDecl for the @implementation returns. This ensures +/// that the lexical parent relationship between these declarations and the +/// @implementation is preserved while traversing the AST. Note that the +/// current implementation doesn't mix these declarations with the declarations +/// contained in the @implementation, so the traversal of all of the +/// declarations in the @implementation still doesn't follow the lexical order. +template <typename Derived> +class LexicallyOrderedRecursiveASTVisitor + : public RecursiveASTVisitor<Derived> { + using BaseType = RecursiveASTVisitor<Derived>; + +public: + LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {} + + bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { + // Objective-C @implementation declarations should not trigger early exit + // until the additional decls are traversed as their children are not + // lexically ordered. + bool Result = BaseType::TraverseObjCImplementationDecl(D); + return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; + } + + bool TraverseObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + bool Result = BaseType::TraverseObjCCategoryImplDecl(D); + return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; + } + + bool TraverseDeclContextHelper(DeclContext *DC) { + if (!DC) + return true; + + for (auto I = DC->decls_begin(), E = DC->decls_end(); I != E;) { + Decl *Child = *I; + if (BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Child)) { + ++I; + continue; + } + if (!isa<ObjCImplementationDecl>(Child) && + !isa<ObjCCategoryImplDecl>(Child)) { + if (!BaseType::getDerived().TraverseDecl(Child)) + return false; + ++I; + continue; + } + // Gather declarations that follow the Objective-C implementation + // declarations but are lexically contained in the implementation. + LexicallyNestedDeclarations.clear(); + for (++I; I != E; ++I) { + Decl *Sibling = *I; + if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(), + Child->getLocEnd())) + break; + if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling)) + LexicallyNestedDeclarations.push_back(Sibling); + } + if (!BaseType::getDerived().TraverseDecl(Child)) + return false; + } + return true; + } + + Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } + + SmallVector<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) { + SmallVector<Stmt *, 8> Children(CE->children()); + bool Swap; + // Switch the operator and the first operand for all infix and postfix + // operations. + switch (CE->getOperator()) { + case OO_Arrow: + case OO_Call: + case OO_Subscript: + Swap = true; + break; + case OO_PlusPlus: + case OO_MinusMinus: + // These are postfix unless there is exactly one argument. + Swap = Children.size() != 2; + break; + default: + Swap = CE->isInfixBinaryOp(); + break; + } + if (Swap && Children.size() > 1) + std::swap(Children[0], Children[1]); + return Children; + } + +private: + bool TraverseAdditionalLexicallyNestedDeclarations() { + // FIXME: Ideally the gathered declarations and the declarations in the + // @implementation should be mixed and sorted to get a true lexical order, + // but right now we only care about getting the correct lexical parent, so + // we can traverse the gathered nested declarations after the declarations + // in the decl context. + assert(!BaseType::getDerived().shouldTraversePostOrder() && + "post-order traversal is not supported for lexically ordered " + "recursive ast visitor"); + for (Decl *D : LexicallyNestedDeclarations) { + if (!BaseType::getDerived().TraverseDecl(D)) + return false; + } + return true; + } + + const SourceManager &SM; + llvm::SmallVector<Decl *, 8> LexicallyNestedDeclarations; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h b/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h index b1ff9bdff5891..e2cb45c36de6b 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h +++ b/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h @@ -1,4 +1,4 @@ -//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===// +//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,38 +11,42 @@ // a C++ nested-name-specifier. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Compiler.h" +#include <cstdint> +#include <cstdlib> +#include <utility> namespace clang { class ASTContext; class CXXRecordDecl; +class IdentifierInfo; +class LangOptions; class NamespaceAliasDecl; class NamespaceDecl; -class IdentifierInfo; struct PrintingPolicy; class Type; class TypeLoc; -class LangOptions; /// \brief Represents a C++ nested name specifier, such as /// "\::std::vector<int>::". /// /// C++ nested name specifiers are the prefixes to qualified -/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// names. For example, "foo::" in "foo::x" is a nested name /// specifier. Nested name specifiers are made up of a sequence of /// specifiers, each of which can be a namespace, type, identifier /// (for dependent names), decltype specifier, or the global specifier ('::'). /// The last two specifiers can only appear at the start of a /// nested-namespace-specifier. class NestedNameSpecifier : public llvm::FoldingSetNode { - /// \brief Enumeration describing enum StoredSpecifierKind { StoredIdentifier = 0, @@ -66,7 +70,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode { /// specifier '::'. Otherwise, the pointer is one of /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of /// specifier as encoded within the prefix. - void* Specifier; + void* Specifier = nullptr; public: /// \brief The kind of specifier that completes this nested name @@ -74,17 +78,23 @@ public: enum SpecifierKind { /// \brief An identifier, stored as an IdentifierInfo*. Identifier, + /// \brief A namespace, stored as a NamespaceDecl*. Namespace, + /// \brief A namespace alias, stored as a NamespaceAliasDecl*. NamespaceAlias, + /// \brief A type, stored as a Type*. TypeSpec, + /// \brief A type that was preceded by the 'template' keyword, /// stored as a Type*. TypeSpecWithTemplate, + /// \brief The global specifier '::'. There is no stored value. Global, + /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of /// the class it appeared in. Super @@ -92,17 +102,11 @@ public: private: /// \brief Builds the global specifier. - NestedNameSpecifier() - : Prefix(nullptr, StoredIdentifier), Specifier(nullptr) {} + NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {} /// \brief Copy constructor used internally to clone nested name /// specifiers. - NestedNameSpecifier(const NestedNameSpecifier &Other) - : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), - Specifier(Other.Specifier) { - } - - void operator=(const NestedNameSpecifier &) = delete; + NestedNameSpecifier(const NestedNameSpecifier &Other) = default; /// \brief Either find or insert the given nested name specifier /// mockup in the given context. @@ -110,6 +114,8 @@ private: const NestedNameSpecifier &Mockup); public: + NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete; + /// \brief Builds a specifier combining a prefix and an identifier. /// /// The prefix must be dependent, since nested name specifiers @@ -224,8 +230,8 @@ public: /// \brief A C++ nested-name-specifier augmented with source location /// information. class NestedNameSpecifierLoc { - NestedNameSpecifier *Qualifier; - void *Data; + NestedNameSpecifier *Qualifier = nullptr; + void *Data = nullptr; /// \brief Determines the data length for the last component in the /// given nested-name-specifier. @@ -237,12 +243,12 @@ class NestedNameSpecifierLoc { public: /// \brief Construct an empty nested-name-specifier. - NestedNameSpecifierLoc() : Qualifier(nullptr), Data(nullptr) { } + NestedNameSpecifierLoc() = default; /// \brief Construct a nested-name-specifier with source location information /// from NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) - : Qualifier(Qualifier), Data(Data) { } + : Qualifier(Qualifier), Data(Data) {} /// \brief Evalutes true when this nested-name-specifier location is /// non-empty. @@ -339,7 +345,7 @@ public: class NestedNameSpecifierLocBuilder { /// \brief The current representation of the nested-name-specifier we're /// building. - NestedNameSpecifier *Representation; + NestedNameSpecifier *Representation = nullptr; /// \brief Buffer used to store source-location information for the /// nested-name-specifier. @@ -347,21 +353,18 @@ class NestedNameSpecifierLocBuilder { /// Note that we explicitly manage the buffer (rather than using a /// SmallVector) because \c Declarator expects it to be possible to memcpy() /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. - char *Buffer; + char *Buffer = nullptr; /// \brief The size of the buffer used to store source-location information /// for the nested-name-specifier. - unsigned BufferSize; + unsigned BufferSize = 0; /// \brief The capacity of the buffer used to store source-location /// information for the nested-name-specifier. - unsigned BufferCapacity; + unsigned BufferCapacity = 0; public: - NestedNameSpecifierLocBuilder() - : Representation(nullptr), Buffer(nullptr), BufferSize(0), - BufferCapacity(0) {} - + NestedNameSpecifierLocBuilder() = default; NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); NestedNameSpecifierLocBuilder & @@ -451,6 +454,7 @@ public: /// \param ColonColonLoc The location of the trailing '::'. void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc, SourceLocation ColonColonLoc); + /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// @@ -511,6 +515,6 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } -} +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h index a1cae8e18f84e..1f732f67517a4 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h +++ b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h @@ -6,35 +6,55 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// /// \file /// \brief This file defines OpenMP AST classes for clauses. /// There are clauses for executable directives, clauses for declarative /// directives and clauses which can be used in both kinds of directives. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_OPENMPCLAUSE_H #define LLVM_CLANG_AST_OPENMPCLAUSE_H +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" +#include "clang/AST/StmtIterator.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <utility> namespace clang { +class ASTContext; + //===----------------------------------------------------------------------===// // AST classes for clauses. //===----------------------------------------------------------------------===// /// \brief This is a basic class for representing single OpenMP clause. -/// class OMPClause { /// \brief Starting location of the clause (the clause keyword). SourceLocation StartLoc; + /// \brief Ending location of the clause. SourceLocation EndLoc; + /// \brief Kind of the clause. OpenMPClauseKind Kind; @@ -45,11 +65,13 @@ protected: public: /// \brief Returns the starting location of the clause. SourceLocation getLocStart() const { return StartLoc; } + /// \brief Returns the ending location of the clause. SourceLocation getLocEnd() const { return EndLoc; } /// \brief Sets the starting location of the clause. void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Sets the ending location of the clause. void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } @@ -58,16 +80,17 @@ public: bool isImplicit() const { return StartLoc.isInvalid(); } - typedef StmtIterator child_iterator; - typedef ConstStmtIterator const_child_iterator; - typedef llvm::iterator_range<child_iterator> child_range; - typedef llvm::iterator_range<const_child_iterator> const_child_range; + using child_iterator = StmtIterator; + using const_child_iterator = ConstStmtIterator; + using child_range = llvm::iterator_range<child_iterator>; + using const_child_range = llvm::iterator_range<const_child_iterator>; child_range children(); const_child_range children() const { auto Children = const_cast<OMPClause *>(this)->children(); return const_child_range(Children.begin(), Children.end()); } + static bool classof(const OMPClause *) { return true; } }; @@ -75,29 +98,34 @@ public: /// 'shedule', 'firstprivate' etc. class OMPClauseWithPreInit { friend class OMPClauseReader; + /// Pre-initialization statement for the clause. - Stmt *PreInit; + Stmt *PreInit = nullptr; + /// Region that captures the associated stmt. - OpenMPDirectiveKind CaptureRegion; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; protected: + OMPClauseWithPreInit(const OMPClause *This) { + assert(get(This) && "get is not tuned for pre-init."); + } + /// Set pre-initialization statement for the clause. void setPreInitStmt(Stmt *S, OpenMPDirectiveKind ThisRegion = OMPD_unknown) { PreInit = S; CaptureRegion = ThisRegion; } - OMPClauseWithPreInit(const OMPClause *This) - : PreInit(nullptr), CaptureRegion(OMPD_unknown) { - assert(get(This) && "get is not tuned for pre-init."); - } public: /// Get pre-initialization statement for the clause. const Stmt *getPreInitStmt() const { return PreInit; } + /// Get pre-initialization statement for the clause. Stmt *getPreInitStmt() { return PreInit; } + /// Get capture region for the stmt in the clause. OpenMPDirectiveKind getCaptureRegion() { return CaptureRegion; } + static OMPClauseWithPreInit *get(OMPClause *C); static const OMPClauseWithPreInit *get(const OMPClause *C); }; @@ -106,21 +134,25 @@ public: /// 'lastprivate', 'reduction' etc. class OMPClauseWithPostUpdate : public OMPClauseWithPreInit { friend class OMPClauseReader; + /// Post-update expression for the clause. - Expr *PostUpdate; + Expr *PostUpdate = nullptr; + protected: - /// Set pre-initialization statement for the clause. - void setPostUpdateExpr(Expr *S) { PostUpdate = S; } - OMPClauseWithPostUpdate(const OMPClause *This) - : OMPClauseWithPreInit(This), PostUpdate(nullptr) { + OMPClauseWithPostUpdate(const OMPClause *This) : OMPClauseWithPreInit(This) { assert(get(This) && "get is not tuned for post-update."); } + /// Set pre-initialization statement for the clause. + void setPostUpdateExpr(Expr *S) { PostUpdate = S; } + public: /// Get post-update expression for the clause. const Expr *getPostUpdateExpr() const { return PostUpdate; } + /// Get post-update expression for the clause. Expr *getPostUpdateExpr() { return PostUpdate; } + static OMPClauseWithPostUpdate *get(OMPClause *C); static const OMPClauseWithPostUpdate *get(const OMPClause *C); }; @@ -130,12 +162,25 @@ public: /// '#pragma omp ...' directives. template <class T> class OMPVarListClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Number of variables in the list. unsigned NumVars; protected: + /// \brief Build a clause with \a N variables + /// + /// \param K Kind of the clause. + /// \param StartLoc Starting location of the clause (the clause keyword). + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + OMPVarListClause(OpenMPClauseKind K, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) + : OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc), NumVars(N) {} + /// \brief Fetches list of variables associated with this clause. MutableArrayRef<Expr *> getVarRefs() { return MutableArrayRef<Expr *>( @@ -150,23 +195,11 @@ protected: static_cast<T *>(this)->template getTrailingObjects<Expr *>()); } - /// \brief Build a clause with \a N variables - /// - /// \param K Kind of the clause. - /// \param StartLoc Starting location of the clause (the clause keyword). - /// \param LParenLoc Location of '('. - /// \param EndLoc Ending location of the clause. - /// \param N Number of the variables in the clause. - /// - OMPVarListClause(OpenMPClauseKind K, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) - : OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc), NumVars(N) {} - public: - typedef MutableArrayRef<Expr *>::iterator varlist_iterator; - typedef ArrayRef<const Expr *>::iterator varlist_const_iterator; - typedef llvm::iterator_range<varlist_iterator> varlist_range; - typedef llvm::iterator_range<varlist_const_iterator> varlist_const_range; + using varlist_iterator = MutableArrayRef<Expr *>::iterator; + using varlist_const_iterator = ArrayRef<const Expr *>::iterator; + using varlist_range = llvm::iterator_range<varlist_iterator>; + using varlist_const_range = llvm::iterator_range<varlist_const_iterator>; unsigned varlist_size() const { return NumVars; } bool varlist_empty() const { return NumVars == 0; } @@ -185,6 +218,7 @@ public: /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } @@ -203,31 +237,34 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has simple 'if' clause with /// condition 'a > 5' and directive name modifier 'parallel'. -/// class OMPIfClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Condition of the 'if' clause. - Stmt *Condition; + Stmt *Condition = nullptr; + /// \brief Location of ':' (if any). SourceLocation ColonLoc; + /// \brief Directive name modifier for the clause. - OpenMPDirectiveKind NameModifier; + OpenMPDirectiveKind NameModifier = OMPD_unknown; + /// \brief Name modifier location. SourceLocation NameModifierLoc; /// \brief Set condition. - /// void setCondition(Expr *Cond) { Condition = Cond; } + /// \brief Set directive name modifier for the clause. - /// void setNameModifier(OpenMPDirectiveKind NM) { NameModifier = NM; } + /// \brief Set location of directive name modifier for the clause. - /// void setNameModifierLoc(SourceLocation Loc) { NameModifierLoc = Loc; } + /// \brief Set location of ':'. - /// void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } public: @@ -243,7 +280,6 @@ public: /// \param NameModifierLoc Location of directive name modifier. /// \param ColonLoc [OpenMP 4.1] Location of ':'. /// \param EndLoc Ending location of the clause. - /// OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond, Stmt *HelperCond, OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, @@ -255,14 +291,13 @@ public: } /// \brief Build an empty clause. - /// OMPIfClause() : OMPClause(OMPC_if, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), LParenLoc(), Condition(nullptr), ColonLoc(), - NameModifier(OMPD_unknown), NameModifierLoc() {} + OMPClauseWithPreInit(this) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } @@ -271,17 +306,18 @@ public: /// \brief Returns condition. Expr *getCondition() const { return cast_or_null<Expr>(Condition); } + /// \brief Return directive name modifier associated with the clause. OpenMPDirectiveKind getNameModifier() const { return NameModifier; } /// \brief Return the location of directive name modifier. SourceLocation getNameModifierLoc() const { return NameModifierLoc; } + child_range children() { return child_range(&Condition, &Condition + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_if; } - - child_range children() { return child_range(&Condition, &Condition + 1); } }; /// \brief This represents 'final' clause in the '#pragma omp ...' directive. @@ -291,16 +327,16 @@ public: /// \endcode /// In this example directive '#pragma omp task' has simple 'final' /// clause with condition 'a > 5'. -/// class OMPFinalClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Condition of the 'if' clause. - Stmt *Condition; + Stmt *Condition = nullptr; /// \brief Set condition. - /// void setCondition(Expr *Cond) { Condition = Cond; } public: @@ -310,31 +346,29 @@ public: /// \param LParenLoc Location of '('. /// \param Cond Condition of the clause. /// \param EndLoc Ending location of the clause. - /// OMPFinalClause(Expr *Cond, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_final, StartLoc, EndLoc), LParenLoc(LParenLoc), Condition(Cond) {} /// \brief Build an empty clause. - /// OMPFinalClause() - : OMPClause(OMPC_final, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Condition(nullptr) {} + : OMPClause(OMPC_final, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Returns condition. Expr *getCondition() const { return cast_or_null<Expr>(Condition); } + child_range children() { return child_range(&Condition, &Condition + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_final; } - - child_range children() { return child_range(&Condition, &Condition + 1); } }; /// \brief This represents 'num_threads' clause in the '#pragma omp ...' @@ -345,16 +379,16 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has simple 'num_threads' /// clause with number of threads '6'. -/// class OMPNumThreadsClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Condition of the 'num_threads' clause. - Stmt *NumThreads; + Stmt *NumThreads = nullptr; /// \brief Set condition. - /// void setNumThreads(Expr *NThreads) { NumThreads = NThreads; } public: @@ -367,7 +401,6 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPNumThreadsClause(Expr *NumThreads, Stmt *HelperNumThreads, OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -379,25 +412,24 @@ public: } /// \brief Build an empty clause. - /// OMPNumThreadsClause() : OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), LParenLoc(SourceLocation()), - NumThreads(nullptr) {} + OMPClauseWithPreInit(this) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Returns number of threads. Expr *getNumThreads() const { return cast_or_null<Expr>(NumThreads); } + child_range children() { return child_range(&NumThreads, &NumThreads + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_num_threads; } - - child_range children() { return child_range(&NumThreads, &NumThreads + 1); } }; /// \brief This represents 'safelen' clause in the '#pragma omp ...' @@ -412,13 +444,14 @@ public: /// concurrently with SIMD instructions can have a greater distance /// in the logical iteration space than its value. The parameter of /// the safelen clause must be a constant positive integer expression. -/// class OMPSafelenClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Safe iteration space distance. - Stmt *Safelen; + Stmt *Safelen = nullptr; /// \brief Set safelen. void setSafelen(Expr *Len) { Safelen = Len; } @@ -429,31 +462,29 @@ public: /// \param Len Expression associated with this clause. /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPSafelenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_safelen, StartLoc, EndLoc), LParenLoc(LParenLoc), Safelen(Len) {} /// \brief Build an empty clause. - /// explicit OMPSafelenClause() - : OMPClause(OMPC_safelen, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Safelen(nullptr) {} + : OMPClause(OMPC_safelen, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return safe iteration space distance. Expr *getSafelen() const { return cast_or_null<Expr>(Safelen); } + child_range children() { return child_range(&Safelen, &Safelen + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_safelen; } - - child_range children() { return child_range(&Safelen, &Safelen + 1); } }; /// \brief This represents 'simdlen' clause in the '#pragma omp ...' @@ -467,13 +498,14 @@ public: /// If the 'simdlen' clause is used then it specifies the preferred number of /// iterations to be executed concurrently. The parameter of the 'simdlen' /// clause must be a constant positive integer expression. -/// class OMPSimdlenClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Safe iteration space distance. - Stmt *Simdlen; + Stmt *Simdlen = nullptr; /// \brief Set simdlen. void setSimdlen(Expr *Len) { Simdlen = Len; } @@ -484,31 +516,29 @@ public: /// \param Len Expression associated with this clause. /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPSimdlenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_simdlen, StartLoc, EndLoc), LParenLoc(LParenLoc), Simdlen(Len) {} /// \brief Build an empty clause. - /// explicit OMPSimdlenClause() - : OMPClause(OMPC_simdlen, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Simdlen(nullptr) {} + : OMPClause(OMPC_simdlen, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return safe iteration space distance. Expr *getSimdlen() const { return cast_or_null<Expr>(Simdlen); } + child_range children() { return child_range(&Simdlen, &Simdlen + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_simdlen; } - - child_range children() { return child_range(&Simdlen, &Simdlen + 1); } }; /// \brief This represents 'collapse' clause in the '#pragma omp ...' @@ -522,13 +552,14 @@ public: /// The parameter must be a constant positive integer expression, it specifies /// the number of nested loops that should be collapsed into a single iteration /// space. -/// class OMPCollapseClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Number of for-loops. - Stmt *NumForLoops; + Stmt *NumForLoops = nullptr; /// \brief Set the number of associated for-loops. void setNumForLoops(Expr *Num) { NumForLoops = Num; } @@ -540,31 +571,29 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPCollapseClause(Expr *Num, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_collapse, StartLoc, EndLoc), LParenLoc(LParenLoc), NumForLoops(Num) {} /// \brief Build an empty clause. - /// explicit OMPCollapseClause() - : OMPClause(OMPC_collapse, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), NumForLoops(nullptr) {} + : OMPClause(OMPC_collapse, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return the number of associated for-loops. Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); } + child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_collapse; } - - child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } }; /// \brief This represents 'default' clause in the '#pragma omp ...' directive. @@ -574,26 +603,26 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has simple 'default' /// clause with kind 'shared'. -/// class OMPDefaultClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief A kind of the 'default' clause. - OpenMPDefaultClauseKind Kind; + OpenMPDefaultClauseKind Kind = OMPC_DEFAULT_unknown; + /// \brief Start location of the kind in source code. SourceLocation KindKwLoc; /// \brief Set kind of the clauses. /// /// \param K Argument of clause. - /// void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; } /// \brief Set argument location. /// /// \param KLoc Argument location. - /// void setDefaultKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } public: @@ -604,7 +633,6 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) @@ -612,14 +640,12 @@ public: Kind(A), KindKwLoc(ALoc) {} /// \brief Build an empty clause. - /// OMPDefaultClause() - : OMPClause(OMPC_default, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Kind(OMPC_DEFAULT_unknown), - KindKwLoc(SourceLocation()) {} + : OMPClause(OMPC_default, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } @@ -629,13 +655,13 @@ public: /// \brief Returns location of clause kind. SourceLocation getDefaultKindKwLoc() const { return KindKwLoc; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_default; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_default; + } }; /// \brief This represents 'proc_bind' clause in the '#pragma omp ...' @@ -646,26 +672,26 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has simple 'proc_bind' /// clause with kind 'master'. -/// class OMPProcBindClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief A kind of the 'proc_bind' clause. - OpenMPProcBindClauseKind Kind; + OpenMPProcBindClauseKind Kind = OMPC_PROC_BIND_unknown; + /// \brief Start location of the kind in source code. SourceLocation KindKwLoc; /// \brief Set kind of the clause. /// /// \param K Kind of clause. - /// void setProcBindKind(OpenMPProcBindClauseKind K) { Kind = K; } /// \brief Set clause kind location. /// /// \param KLoc Kind location. - /// void setProcBindKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } public: @@ -677,7 +703,6 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPProcBindClause(OpenMPProcBindClauseKind A, SourceLocation ALoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) @@ -685,14 +710,12 @@ public: Kind(A), KindKwLoc(ALoc) {} /// \brief Build an empty clause. - /// OMPProcBindClause() - : OMPClause(OMPC_proc_bind, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Kind(OMPC_PROC_BIND_unknown), - KindKwLoc(SourceLocation()) {} + : OMPClause(OMPC_proc_bind, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } @@ -702,13 +725,13 @@ public: /// \brief Returns location of clause kind. SourceLocation getProcBindKindKwLoc() const { return KindKwLoc; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_proc_bind; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_proc_bind; + } }; /// \brief This represents 'schedule' clause in the '#pragma omp ...' directive. @@ -718,58 +741,63 @@ public: /// \endcode /// In this example directive '#pragma omp for' has 'schedule' clause with /// arguments 'static' and '3'. -/// class OMPScheduleClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief A kind of the 'schedule' clause. - OpenMPScheduleClauseKind Kind; + OpenMPScheduleClauseKind Kind = OMPC_SCHEDULE_unknown; + /// \brief Modifiers for 'schedule' clause. enum {FIRST, SECOND, NUM_MODIFIERS}; OpenMPScheduleClauseModifier Modifiers[NUM_MODIFIERS]; + /// \brief Locations of modifiers. SourceLocation ModifiersLoc[NUM_MODIFIERS]; + /// \brief Start location of the schedule ind in source code. SourceLocation KindLoc; + /// \brief Location of ',' (if any). SourceLocation CommaLoc; + /// \brief Chunk size. - Expr *ChunkSize; + Expr *ChunkSize = nullptr; /// \brief Set schedule kind. /// /// \param K Schedule kind. - /// void setScheduleKind(OpenMPScheduleClauseKind K) { Kind = K; } + /// \brief Set the first schedule modifier. /// /// \param M Schedule modifier. - /// void setFirstScheduleModifier(OpenMPScheduleClauseModifier M) { Modifiers[FIRST] = M; } + /// \brief Set the second schedule modifier. /// /// \param M Schedule modifier. - /// void setSecondScheduleModifier(OpenMPScheduleClauseModifier M) { Modifiers[SECOND] = M; } + /// \brief Set location of the first schedule modifier. - /// void setFirstScheduleModifierLoc(SourceLocation Loc) { ModifiersLoc[FIRST] = Loc; } + /// \brief Set location of the second schedule modifier. - /// void setSecondScheduleModifierLoc(SourceLocation Loc) { ModifiersLoc[SECOND] = Loc; } + /// \brief Set schedule modifier location. /// /// \param M Schedule modifier location. - /// void setScheduleModifer(OpenMPScheduleClauseModifier M) { if (Modifiers[FIRST] == OMPC_SCHEDULE_MODIFIER_unknown) Modifiers[FIRST] = M; @@ -778,25 +806,25 @@ class OMPScheduleClause : public OMPClause, public OMPClauseWithPreInit { Modifiers[SECOND] = M; } } + /// \brief Sets the location of '('. /// /// \param Loc Location of '('. - /// void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Set schedule kind start location. /// /// \param KLoc Schedule kind location. - /// void setScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + /// \brief Set location of ','. /// /// \param Loc Location of ','. - /// void setCommaLoc(SourceLocation Loc) { CommaLoc = Loc; } + /// \brief Set chunk size. /// /// \param E Chunk size. - /// void setChunkSize(Expr *E) { ChunkSize = E; } public: @@ -815,7 +843,6 @@ public: /// \param M1Loc Location of the first modifier /// \param M2 The second modifier applied to 'schedule' clause. /// \param M2Loc Location of the second modifier - /// OMPScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KLoc, SourceLocation CommaLoc, SourceLocation EndLoc, OpenMPScheduleClauseKind Kind, @@ -833,62 +860,59 @@ public: } /// \brief Build an empty clause. - /// explicit OMPScheduleClause() : OMPClause(OMPC_schedule, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), Kind(OMPC_SCHEDULE_unknown), - ChunkSize(nullptr) { + OMPClauseWithPreInit(this) { Modifiers[FIRST] = OMPC_SCHEDULE_MODIFIER_unknown; Modifiers[SECOND] = OMPC_SCHEDULE_MODIFIER_unknown; } /// \brief Get kind of the clause. - /// OpenMPScheduleClauseKind getScheduleKind() const { return Kind; } + /// \brief Get the first modifier of the clause. - /// OpenMPScheduleClauseModifier getFirstScheduleModifier() const { return Modifiers[FIRST]; } + /// \brief Get the second modifier of the clause. - /// OpenMPScheduleClauseModifier getSecondScheduleModifier() const { return Modifiers[SECOND]; } + /// \brief Get location of '('. - /// SourceLocation getLParenLoc() { return LParenLoc; } + /// \brief Get kind location. - /// SourceLocation getScheduleKindLoc() { return KindLoc; } + /// \brief Get the first modifier location. - /// SourceLocation getFirstScheduleModifierLoc() const { return ModifiersLoc[FIRST]; } + /// \brief Get the second modifier location. - /// SourceLocation getSecondScheduleModifierLoc() const { return ModifiersLoc[SECOND]; } + /// \brief Get location of ','. - /// SourceLocation getCommaLoc() { return CommaLoc; } + /// \brief Get chunk size. - /// Expr *getChunkSize() { return ChunkSize; } + /// \brief Get chunk size. - /// const Expr *getChunkSize() const { return ChunkSize; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_schedule; - } - child_range children() { return child_range(reinterpret_cast<Stmt **>(&ChunkSize), reinterpret_cast<Stmt **>(&ChunkSize) + 1); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_schedule; + } }; /// \brief This represents 'ordered' clause in the '#pragma omp ...' directive. @@ -898,13 +922,14 @@ public: /// \endcode /// In this example directive '#pragma omp for' has 'ordered' clause with /// parameter 2. -/// class OMPOrderedClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Number of for-loops. - Stmt *NumForLoops; + Stmt *NumForLoops = nullptr; /// \brief Set the number of associated for-loops. void setNumForLoops(Expr *Num) { NumForLoops = Num; } @@ -916,31 +941,29 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPOrderedClause(Expr *Num, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc), NumForLoops(Num) {} /// \brief Build an empty clause. - /// explicit OMPOrderedClause() - : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), NumForLoops(nullptr) {} + : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return the number of associated for-loops. Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); } + child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_ordered; } - - child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } }; /// \brief This represents 'nowait' clause in the '#pragma omp ...' directive. @@ -949,29 +972,26 @@ public: /// #pragma omp for nowait /// \endcode /// In this example directive '#pragma omp for' has 'nowait' clause. -/// class OMPNowaitClause : public OMPClause { public: /// \brief Build 'nowait' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_nowait, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPNowaitClause() : OMPClause(OMPC_nowait, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_nowait; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_nowait; + } }; /// \brief This represents 'untied' clause in the '#pragma omp ...' directive. @@ -980,29 +1000,26 @@ public: /// #pragma omp task untied /// \endcode /// In this example directive '#pragma omp task' has 'untied' clause. -/// class OMPUntiedClause : public OMPClause { public: /// \brief Build 'untied' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_untied, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPUntiedClause() : OMPClause(OMPC_untied, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_untied; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_untied; + } }; /// \brief This represents 'mergeable' clause in the '#pragma omp ...' @@ -1012,29 +1029,26 @@ public: /// #pragma omp task mergeable /// \endcode /// In this example directive '#pragma omp task' has 'mergeable' clause. -/// class OMPMergeableClause : public OMPClause { public: /// \brief Build 'mergeable' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_mergeable, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPMergeableClause() : OMPClause(OMPC_mergeable, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_mergeable; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_mergeable; + } }; /// \brief This represents 'read' clause in the '#pragma omp atomic' directive. @@ -1043,28 +1057,25 @@ public: /// #pragma omp atomic read /// \endcode /// In this example directive '#pragma omp atomic' has 'read' clause. -/// class OMPReadClause : public OMPClause { public: /// \brief Build 'read' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_read, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPReadClause() : OMPClause(OMPC_read, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_read; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_read; + } }; /// \brief This represents 'write' clause in the '#pragma omp atomic' directive. @@ -1073,29 +1084,26 @@ public: /// #pragma omp atomic write /// \endcode /// In this example directive '#pragma omp atomic' has 'write' clause. -/// class OMPWriteClause : public OMPClause { public: /// \brief Build 'write' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_write, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPWriteClause() : OMPClause(OMPC_write, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_write; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_write; + } }; /// \brief This represents 'update' clause in the '#pragma omp atomic' @@ -1105,29 +1113,26 @@ public: /// #pragma omp atomic update /// \endcode /// In this example directive '#pragma omp atomic' has 'update' clause. -/// class OMPUpdateClause : public OMPClause { public: /// \brief Build 'update' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_update, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPUpdateClause() : OMPClause(OMPC_update, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_update; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_update; + } }; /// \brief This represents 'capture' clause in the '#pragma omp atomic' @@ -1137,29 +1142,26 @@ public: /// #pragma omp atomic capture /// \endcode /// In this example directive '#pragma omp atomic' has 'capture' clause. -/// class OMPCaptureClause : public OMPClause { public: /// \brief Build 'capture' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_capture, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPCaptureClause() : OMPClause(OMPC_capture, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_capture; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_capture; + } }; /// \brief This represents 'seq_cst' clause in the '#pragma omp atomic' @@ -1169,29 +1171,26 @@ public: /// #pragma omp atomic seq_cst /// \endcode /// In this example directive '#pragma omp atomic' has 'seq_cst' clause. -/// class OMPSeqCstClause : public OMPClause { public: /// \brief Build 'seq_cst' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_seq_cst, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPSeqCstClause() : OMPClause(OMPC_seq_cst, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_seq_cst; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_seq_cst; + } }; /// \brief This represents clause 'private' in the '#pragma omp ...' directives. @@ -1201,20 +1200,19 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has clause 'private' /// with the variables 'a' and 'b'. -/// class OMPPrivateClause final : public OMPVarListClause<OMPPrivateClause>, private llvm::TrailingObjects<OMPPrivateClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPPrivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPPrivateClause>(OMPC_private, StartLoc, LParenLoc, @@ -1223,7 +1221,6 @@ class OMPPrivateClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPPrivateClause(unsigned N) : OMPVarListClause<OMPPrivateClause>(OMPC_private, SourceLocation(), SourceLocation(), SourceLocation(), @@ -1252,28 +1249,28 @@ public: /// \param EndLoc Ending location of the clause. /// \param VL List of references to the variables. /// \param PrivateVL List of references to private copies with initializers. - /// static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL); + /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); - typedef MutableArrayRef<Expr *>::iterator private_copies_iterator; - typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator; - typedef llvm::iterator_range<private_copies_iterator> private_copies_range; - typedef llvm::iterator_range<private_copies_const_iterator> - private_copies_const_range; + using private_copies_iterator = MutableArrayRef<Expr *>::iterator; + using private_copies_const_iterator = ArrayRef<const Expr *>::iterator; + using private_copies_range = llvm::iterator_range<private_copies_iterator>; + using private_copies_const_range = + llvm::iterator_range<private_copies_const_iterator>; private_copies_range private_copies() { return private_copies_range(getPrivateCopies().begin(), getPrivateCopies().end()); } + private_copies_const_range private_copies() const { return private_copies_const_range(getPrivateCopies().begin(), getPrivateCopies().end()); @@ -1297,14 +1294,13 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has clause 'firstprivate' /// with the variables 'a' and 'b'. -/// class OMPFirstprivateClause final : public OMPVarListClause<OMPFirstprivateClause>, public OMPClauseWithPreInit, private llvm::TrailingObjects<OMPFirstprivateClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; /// \brief Build clause with number of variables \a N. /// @@ -1312,7 +1308,6 @@ class OMPFirstprivateClause final /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPFirstprivateClause>(OMPC_firstprivate, StartLoc, @@ -1322,12 +1317,12 @@ class OMPFirstprivateClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPFirstprivateClause(unsigned N) : OMPVarListClause<OMPFirstprivateClause>( OMPC_firstprivate, SourceLocation(), SourceLocation(), SourceLocation(), N), OMPClauseWithPreInit(this) {} + /// \brief Sets the list of references to private copies with initializers for /// new private variables. /// \param VL List of references. @@ -1370,23 +1365,22 @@ public: /// of array type. /// \param PreInit Statement that must be executed before entering the OpenMP /// region with this clause. - /// static OMPFirstprivateClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL, ArrayRef<Expr *> InitVL, Stmt *PreInit); + /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N); - typedef MutableArrayRef<Expr *>::iterator private_copies_iterator; - typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator; - typedef llvm::iterator_range<private_copies_iterator> private_copies_range; - typedef llvm::iterator_range<private_copies_const_iterator> - private_copies_const_range; + using private_copies_iterator = MutableArrayRef<Expr *>::iterator; + using private_copies_const_iterator = ArrayRef<const Expr *>::iterator; + using private_copies_range = llvm::iterator_range<private_copies_iterator>; + using private_copies_const_range = + llvm::iterator_range<private_copies_const_iterator>; private_copies_range private_copies() { return private_copies_range(getPrivateCopies().begin(), @@ -1397,10 +1391,10 @@ public: getPrivateCopies().end()); } - typedef MutableArrayRef<Expr *>::iterator inits_iterator; - typedef ArrayRef<const Expr *>::iterator inits_const_iterator; - typedef llvm::iterator_range<inits_iterator> inits_range; - typedef llvm::iterator_range<inits_const_iterator> inits_const_range; + using inits_iterator = MutableArrayRef<Expr *>::iterator; + using inits_const_iterator = ArrayRef<const Expr *>::iterator; + using inits_range = llvm::iterator_range<inits_iterator>; + using inits_const_range = llvm::iterator_range<inits_const_iterator>; inits_range inits() { return inits_range(getInits().begin(), getInits().end()); @@ -1447,10 +1441,9 @@ class OMPLastprivateClause final // \endcode // Required for proper codegen of final assignment performed by the // lastprivate clause. - // - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; /// \brief Build clause with number of variables \a N. /// @@ -1458,7 +1451,6 @@ class OMPLastprivateClause final /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPLastprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPLastprivateClause>(OMPC_lastprivate, StartLoc, @@ -1468,7 +1460,6 @@ class OMPLastprivateClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPLastprivateClause(unsigned N) : OMPVarListClause<OMPLastprivateClause>( OMPC_lastprivate, SourceLocation(), SourceLocation(), @@ -1550,24 +1541,23 @@ public: /// region with this clause. /// \param PostUpdate Expression that must be executed after exit from the /// OpenMP region with this clause. - /// static OMPLastprivateClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps, Stmt *PreInit, Expr *PostUpdate); + /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPLastprivateClause *CreateEmpty(const ASTContext &C, unsigned N); - typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; - typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; - typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; - typedef llvm::iterator_range<helper_expr_const_iterator> - helper_expr_const_range; + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; /// \brief Set list of helper expressions, required for generation of private /// copies of original lastprivate variables. @@ -1577,29 +1567,36 @@ public: return helper_expr_const_range(getPrivateCopies().begin(), getPrivateCopies().end()); } + helper_expr_range private_copies() { return helper_expr_range(getPrivateCopies().begin(), getPrivateCopies().end()); } + helper_expr_const_range source_exprs() const { return helper_expr_const_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_range source_exprs() { return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_const_range destination_exprs() const { return helper_expr_const_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_range destination_exprs() { return helper_expr_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_const_range assignment_ops() const { return helper_expr_const_range(getAssignmentOps().begin(), getAssignmentOps().end()); } + helper_expr_range assignment_ops() { return helper_expr_range(getAssignmentOps().begin(), getAssignmentOps().end()); @@ -1622,19 +1619,18 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has clause 'shared' /// with the variables 'a' and 'b'. -/// class OMPSharedClause final : public OMPVarListClause<OMPSharedClause>, private llvm::TrailingObjects<OMPSharedClause, Expr *> { - friend TrailingObjects; friend OMPVarListClause; + friend TrailingObjects; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPSharedClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPSharedClause>(OMPC_shared, StartLoc, LParenLoc, @@ -1643,7 +1639,6 @@ class OMPSharedClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPSharedClause(unsigned N) : OMPVarListClause<OMPSharedClause>(OMPC_shared, SourceLocation(), SourceLocation(), SourceLocation(), @@ -1657,15 +1652,14 @@ public: /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param VL List of references to the variables. - /// static OMPSharedClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPSharedClause *CreateEmpty(const ASTContext &C, unsigned N); child_range children() { @@ -1686,18 +1680,20 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has clause 'reduction' /// with operator '+' and the variables 'a' and 'b'. -/// class OMPReductionClause final : public OMPVarListClause<OMPReductionClause>, public OMPClauseWithPostUpdate, private llvm::TrailingObjects<OMPReductionClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Location of ':'. SourceLocation ColonLoc; + /// \brief Nested name specifier for C++. NestedNameSpecifierLoc QualifierLoc; + /// \brief Name of custom operator. DeclarationNameInfo NameInfo; @@ -1710,7 +1706,6 @@ class OMPReductionClause final /// \param N Number of the variables in the clause. /// \param QualifierLoc The nested-name qualifier with location information /// \param NameInfo The full name info for reduction identifier. - /// OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N, NestedNameSpecifierLoc QualifierLoc, @@ -1723,17 +1718,18 @@ class OMPReductionClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPReductionClause(unsigned N) : OMPVarListClause<OMPReductionClause>(OMPC_reduction, SourceLocation(), SourceLocation(), SourceLocation(), N), - OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {} + OMPClauseWithPostUpdate(this) {} /// \brief Sets location of ':' symbol in clause. void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + /// \brief Sets the name info for specified reduction identifier. void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + /// \brief Sets the nested name specifier. void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } @@ -1825,7 +1821,6 @@ public: /// region with this clause. /// \param PostUpdate Expression that must be executed after exit from the /// OpenMP region with this clause. - /// static OMPReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, @@ -1833,48 +1828,57 @@ public: const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, Stmt *PreInit, Expr *PostUpdate); + /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N); /// \brief Gets location of ':' symbol in clause. SourceLocation getColonLoc() const { return ColonLoc; } + /// \brief Gets the name info for specified reduction identifier. const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + /// \brief Gets the nested name specifier. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } - typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; - typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; - typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; - typedef llvm::iterator_range<helper_expr_const_iterator> - helper_expr_const_range; + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; helper_expr_const_range privates() const { return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); } + helper_expr_range privates() { return helper_expr_range(getPrivates().begin(), getPrivates().end()); } + helper_expr_const_range lhs_exprs() const { return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); } + helper_expr_range lhs_exprs() { return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); } + helper_expr_const_range rhs_exprs() const { return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); } + helper_expr_range rhs_exprs() { return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); } + helper_expr_const_range reduction_ops() const { return helper_expr_const_range(getReductionOps().begin(), getReductionOps().end()); } + helper_expr_range reduction_ops() { return helper_expr_range(getReductionOps().begin(), getReductionOps().end()); @@ -1898,18 +1902,20 @@ public: /// \endcode /// In this example directive '#pragma omp taskgroup' has clause /// 'task_reduction' with operator '+' and the variables 'a' and 'b'. -/// class OMPTaskReductionClause final : public OMPVarListClause<OMPTaskReductionClause>, public OMPClauseWithPostUpdate, private llvm::TrailingObjects<OMPTaskReductionClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// Location of ':'. SourceLocation ColonLoc; + /// Nested name specifier for C++. NestedNameSpecifierLoc QualifierLoc; + /// Name of custom operator. DeclarationNameInfo NameInfo; @@ -1922,7 +1928,6 @@ class OMPTaskReductionClause final /// \param N Number of the variables in the clause. /// \param QualifierLoc The nested-name qualifier with location information /// \param NameInfo The full name info for reduction identifier. - /// OMPTaskReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N, NestedNameSpecifierLoc QualifierLoc, @@ -1935,17 +1940,18 @@ class OMPTaskReductionClause final /// Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPTaskReductionClause(unsigned N) : OMPVarListClause<OMPTaskReductionClause>( OMPC_task_reduction, SourceLocation(), SourceLocation(), SourceLocation(), N), - OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {} + OMPClauseWithPostUpdate(this) {} /// Sets location of ':' symbol in clause. void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + /// Sets the name info for specified reduction identifier. void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + /// Sets the nested name specifier. void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } @@ -2035,7 +2041,6 @@ public: /// region with this clause. /// \param PostUpdate Expression that must be executed after exit from the /// OpenMP region with this clause. - /// static OMPTaskReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, @@ -2048,44 +2053,52 @@ public: /// /// \param C AST context. /// \param N The number of variables. - /// static OMPTaskReductionClause *CreateEmpty(const ASTContext &C, unsigned N); /// Gets location of ':' symbol in clause. SourceLocation getColonLoc() const { return ColonLoc; } + /// Gets the name info for specified reduction identifier. const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + /// Gets the nested name specifier. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } - typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; - typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; - typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; - typedef llvm::iterator_range<helper_expr_const_iterator> - helper_expr_const_range; + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; helper_expr_const_range privates() const { return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); } + helper_expr_range privates() { return helper_expr_range(getPrivates().begin(), getPrivates().end()); } + helper_expr_const_range lhs_exprs() const { return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); } + helper_expr_range lhs_exprs() { return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); } + helper_expr_const_range rhs_exprs() const { return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); } + helper_expr_range rhs_exprs() { return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); } + helper_expr_const_range reduction_ops() const { return helper_expr_const_range(getReductionOps().begin(), getReductionOps().end()); } + helper_expr_range reduction_ops() { return helper_expr_range(getReductionOps().begin(), getReductionOps().end()); @@ -2101,6 +2114,249 @@ public: } }; +/// This represents clause 'in_reduction' in the '#pragma omp task' directives. +/// +/// \code +/// #pragma omp task in_reduction(+:a,b) +/// \endcode +/// In this example directive '#pragma omp task' has clause 'in_reduction' with +/// operator '+' and the variables 'a' and 'b'. +class OMPInReductionClause final + : public OMPVarListClause<OMPInReductionClause>, + public OMPClauseWithPostUpdate, + private llvm::TrailingObjects<OMPInReductionClause, Expr *> { + friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + + /// Location of ':'. + SourceLocation ColonLoc; + + /// Nested name specifier for C++. + NestedNameSpecifierLoc QualifierLoc; + + /// Name of custom operator. + DeclarationNameInfo NameInfo; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param ColonLoc Location of ':'. + /// \param N Number of the variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + OMPInReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + unsigned N, NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : OMPVarListClause<OMPInReductionClause>(OMPC_in_reduction, StartLoc, + LParenLoc, EndLoc, N), + OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), + QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + explicit OMPInReductionClause(unsigned N) + : OMPVarListClause<OMPInReductionClause>( + OMPC_in_reduction, SourceLocation(), SourceLocation(), + SourceLocation(), N), + OMPClauseWithPostUpdate(this) {} + + /// Sets location of ':' symbol in clause. + void setColonLoc(SourceLocation CL) { ColonLoc = CL; } + + /// Sets the name info for specified reduction identifier. + void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; } + + /// Sets the nested name specifier. + void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent private copy of the reduction variable. + void setPrivates(ArrayRef<Expr *> Privates); + + /// Get the list of helper privates. + MutableArrayRef<Expr *> getPrivates() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivates() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent LHS expression in the final reduction + /// expression performed by the reduction clause. + void setLHSExprs(ArrayRef<Expr *> LHSExprs); + + /// Get the list of helper LHS expressions. + MutableArrayRef<Expr *> getLHSExprs() { + return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size()); + } + ArrayRef<const Expr *> getLHSExprs() const { + return llvm::makeArrayRef(getPrivates().end(), varlist_size()); + } + + /// Set list of helper expressions, required for proper codegen of the clause. + /// These expressions represent RHS expression in the final reduction + /// expression performed by the reduction clause. Also, variables in these + /// expressions are used for proper initialization of reduction copies. + void setRHSExprs(ArrayRef<Expr *> RHSExprs); + + /// Get the list of helper destination expressions. + MutableArrayRef<Expr *> getRHSExprs() { + return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getRHSExprs() const { + return llvm::makeArrayRef(getLHSExprs().end(), varlist_size()); + } + + /// Set list of helper reduction expressions, required for proper + /// codegen of the clause. These expressions are binary expressions or + /// operator/custom reduction call that calculates new value from source + /// helper expressions to destination helper expressions. + void setReductionOps(ArrayRef<Expr *> ReductionOps); + + /// Get the list of helper reduction expressions. + MutableArrayRef<Expr *> getReductionOps() { + return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size()); + } + ArrayRef<const Expr *> getReductionOps() const { + return llvm::makeArrayRef(getRHSExprs().end(), varlist_size()); + } + + /// Set list of helper reduction taskgroup descriptors. + void setTaskgroupDescriptors(ArrayRef<Expr *> ReductionOps); + + /// Get the list of helper reduction taskgroup descriptors. + MutableArrayRef<Expr *> getTaskgroupDescriptors() { + return MutableArrayRef<Expr *>(getReductionOps().end(), varlist_size()); + } + ArrayRef<const Expr *> getTaskgroupDescriptors() const { + return llvm::makeArrayRef(getReductionOps().end(), varlist_size()); + } + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. + /// \param VL The variables in the clause. + /// \param QualifierLoc The nested-name qualifier with location information + /// \param NameInfo The full name info for reduction identifier. + /// \param Privates List of helper expressions for proper generation of + /// private copies. + /// \param LHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// LHSs of the reduction expressions. + /// \param RHSExprs List of helper expressions for proper generation of + /// assignment operation required for copyprivate clause. This list represents + /// RHSs of the reduction expressions. + /// Also, variables in these expressions are used for proper initialization of + /// reduction copies. + /// \param ReductionOps List of helper expressions that represents reduction + /// expressions: + /// \code + /// LHSExprs binop RHSExprs; + /// operator binop(LHSExpr, RHSExpr); + /// <CutomReduction>(LHSExpr, RHSExpr); + /// \endcode + /// Required for proper codegen of final reduction operation performed by the + /// reduction clause. + /// \param TaskgroupDescriptors List of helper taskgroup descriptors for + /// corresponding items in parent taskgroup task_reduction clause. + /// \param PreInit Statement that must be executed before entering the OpenMP + /// region with this clause. + /// \param PostUpdate Expression that must be executed after exit from the + /// OpenMP region with this clause. + static OMPInReductionClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates, + ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, + ArrayRef<Expr *> ReductionOps, ArrayRef<Expr *> TaskgroupDescriptors, + Stmt *PreInit, Expr *PostUpdate); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + static OMPInReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// Gets location of ':' symbol in clause. + SourceLocation getColonLoc() const { return ColonLoc; } + + /// Gets the name info for specified reduction identifier. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + + /// Gets the nested name specifier. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; + + helper_expr_const_range privates() const { + return helper_expr_const_range(getPrivates().begin(), getPrivates().end()); + } + + helper_expr_range privates() { + return helper_expr_range(getPrivates().begin(), getPrivates().end()); + } + + helper_expr_const_range lhs_exprs() const { + return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end()); + } + + helper_expr_range lhs_exprs() { + return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end()); + } + + helper_expr_const_range rhs_exprs() const { + return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end()); + } + + helper_expr_range rhs_exprs() { + return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end()); + } + + helper_expr_const_range reduction_ops() const { + return helper_expr_const_range(getReductionOps().begin(), + getReductionOps().end()); + } + + helper_expr_range reduction_ops() { + return helper_expr_range(getReductionOps().begin(), + getReductionOps().end()); + } + + helper_expr_const_range taskgroup_descriptors() const { + return helper_expr_const_range(getTaskgroupDescriptors().begin(), + getTaskgroupDescriptors().end()); + } + + helper_expr_range taskgroup_descriptors() { + return helper_expr_range(getTaskgroupDescriptors().begin(), + getTaskgroupDescriptors().end()); + } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_in_reduction; + } +}; + /// \brief This represents clause 'linear' in the '#pragma omp ...' /// directives. /// @@ -2109,18 +2365,20 @@ public: /// \endcode /// In this example directive '#pragma omp simd' has clause 'linear' /// with variables 'a', 'b' and linear step '2'. -/// class OMPLinearClause final : public OMPVarListClause<OMPLinearClause>, public OMPClauseWithPostUpdate, private llvm::TrailingObjects<OMPLinearClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Modifier of 'linear' clause. - OpenMPLinearClauseKind Modifier; + OpenMPLinearClauseKind Modifier = OMPC_LINEAR_val; + /// \brief Location of linear modifier if any. SourceLocation ModifierLoc; + /// \brief Location of ':'. SourceLocation ColonLoc; @@ -2137,7 +2395,6 @@ class OMPLinearClause final /// \param ColonLoc Location of ':'. /// \param EndLoc Ending location of the clause. /// \param NumVars Number of variables. - /// OMPLinearClause(SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, @@ -2150,13 +2407,11 @@ class OMPLinearClause final /// \brief Build an empty clause. /// /// \param NumVars Number of variables. - /// explicit OMPLinearClause(unsigned NumVars) : OMPVarListClause<OMPLinearClause>(OMPC_linear, SourceLocation(), SourceLocation(), SourceLocation(), NumVars), - OMPClauseWithPostUpdate(this), Modifier(OMPC_LINEAR_val), ModifierLoc(), - ColonLoc() {} + OMPClauseWithPostUpdate(this) {} /// \brief Gets the list of initial values for linear variables. /// @@ -2170,7 +2425,6 @@ class OMPLinearClause final /// /// { Vars[] /* in OMPVarListClause */; Privates[]; Inits[]; Updates[]; /// Finals[]; Step; CalcStep; } - /// MutableArrayRef<Expr *> getPrivates() { return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); } @@ -2240,30 +2494,35 @@ public: /// /// \param C AST context. /// \param NumVars Number of variables. - /// static OMPLinearClause *CreateEmpty(const ASTContext &C, unsigned NumVars); /// \brief Set modifier. void setModifier(OpenMPLinearClauseKind Kind) { Modifier = Kind; } + /// \brief Return modifier. OpenMPLinearClauseKind getModifier() const { return Modifier; } /// \brief Set modifier location. void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// \brief Return modifier location. SourceLocation getModifierLoc() const { return ModifierLoc; } /// \brief Sets the location of ':'. void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// \brief Returns the location of ':'. SourceLocation getColonLoc() const { return ColonLoc; } /// \brief Returns linear step. Expr *getStep() { return *(getFinals().end()); } + /// \brief Returns linear step. const Expr *getStep() const { return *(getFinals().end()); } + /// \brief Returns expression to calculate linear step. Expr *getCalcStep() { return *(getFinals().end() + 1); } + /// \brief Returns expression to calculate linear step. const Expr *getCalcStep() const { return *(getFinals().end() + 1); } @@ -2275,50 +2534,54 @@ public: /// \param FL List of expressions. void setFinals(ArrayRef<Expr *> FL); - typedef MutableArrayRef<Expr *>::iterator privates_iterator; - typedef ArrayRef<const Expr *>::iterator privates_const_iterator; - typedef llvm::iterator_range<privates_iterator> privates_range; - typedef llvm::iterator_range<privates_const_iterator> privates_const_range; + using privates_iterator = MutableArrayRef<Expr *>::iterator; + using privates_const_iterator = ArrayRef<const Expr *>::iterator; + using privates_range = llvm::iterator_range<privates_iterator>; + using privates_const_range = llvm::iterator_range<privates_const_iterator>; privates_range privates() { return privates_range(getPrivates().begin(), getPrivates().end()); } + privates_const_range privates() const { return privates_const_range(getPrivates().begin(), getPrivates().end()); } - typedef MutableArrayRef<Expr *>::iterator inits_iterator; - typedef ArrayRef<const Expr *>::iterator inits_const_iterator; - typedef llvm::iterator_range<inits_iterator> inits_range; - typedef llvm::iterator_range<inits_const_iterator> inits_const_range; + using inits_iterator = MutableArrayRef<Expr *>::iterator; + using inits_const_iterator = ArrayRef<const Expr *>::iterator; + using inits_range = llvm::iterator_range<inits_iterator>; + using inits_const_range = llvm::iterator_range<inits_const_iterator>; inits_range inits() { return inits_range(getInits().begin(), getInits().end()); } + inits_const_range inits() const { return inits_const_range(getInits().begin(), getInits().end()); } - typedef MutableArrayRef<Expr *>::iterator updates_iterator; - typedef ArrayRef<const Expr *>::iterator updates_const_iterator; - typedef llvm::iterator_range<updates_iterator> updates_range; - typedef llvm::iterator_range<updates_const_iterator> updates_const_range; + using updates_iterator = MutableArrayRef<Expr *>::iterator; + using updates_const_iterator = ArrayRef<const Expr *>::iterator; + using updates_range = llvm::iterator_range<updates_iterator>; + using updates_const_range = llvm::iterator_range<updates_const_iterator>; updates_range updates() { return updates_range(getUpdates().begin(), getUpdates().end()); } + updates_const_range updates() const { return updates_const_range(getUpdates().begin(), getUpdates().end()); } - typedef MutableArrayRef<Expr *>::iterator finals_iterator; - typedef ArrayRef<const Expr *>::iterator finals_const_iterator; - typedef llvm::iterator_range<finals_iterator> finals_range; - typedef llvm::iterator_range<finals_const_iterator> finals_const_range; + using finals_iterator = MutableArrayRef<Expr *>::iterator; + using finals_const_iterator = ArrayRef<const Expr *>::iterator; + using finals_range = llvm::iterator_range<finals_iterator>; + using finals_const_range = llvm::iterator_range<finals_const_iterator>; finals_range finals() { return finals_range(getFinals().begin(), getFinals().end()); } + finals_const_range finals() const { return finals_const_range(getFinals().begin(), getFinals().end()); } @@ -2341,13 +2604,13 @@ public: /// \endcode /// In this example directive '#pragma omp simd' has clause 'aligned' /// with variables 'a', 'b' and alignment '8'. -/// class OMPAlignedClause final : public OMPVarListClause<OMPAlignedClause>, private llvm::TrailingObjects<OMPAlignedClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Location of ':'. SourceLocation ColonLoc; @@ -2361,7 +2624,6 @@ class OMPAlignedClause final /// \param ColonLoc Location of ':'. /// \param EndLoc Ending location of the clause. /// \param NumVars Number of variables. - /// OMPAlignedClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, unsigned NumVars) @@ -2372,12 +2634,10 @@ class OMPAlignedClause final /// \brief Build an empty clause. /// /// \param NumVars Number of variables. - /// explicit OMPAlignedClause(unsigned NumVars) : OMPVarListClause<OMPAlignedClause>(OMPC_aligned, SourceLocation(), SourceLocation(), SourceLocation(), - NumVars), - ColonLoc(SourceLocation()) {} + NumVars) {} public: /// \brief Creates clause with a list of variables \a VL and alignment \a A. @@ -2399,16 +2659,17 @@ public: /// /// \param C AST context. /// \param NumVars Number of variables. - /// static OMPAlignedClause *CreateEmpty(const ASTContext &C, unsigned NumVars); /// \brief Sets the location of ':'. void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// \brief Returns the location of ':'. SourceLocation getColonLoc() const { return ColonLoc; } /// \brief Returns alignment. Expr *getAlignment() { return *varlist_end(); } + /// \brief Returns alignment. const Expr *getAlignment() const { return *varlist_end(); } @@ -2429,7 +2690,6 @@ public: /// \endcode /// In this example directive '#pragma omp parallel' has clause 'copyin' /// with the variables 'a' and 'b'. -/// class OMPCopyinClause final : public OMPVarListClause<OMPCopyinClause>, private llvm::TrailingObjects<OMPCopyinClause, Expr *> { @@ -2446,16 +2706,16 @@ class OMPCopyinClause final // threadprivate variables to local instances of that variables in other // implicit threads. - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPCopyinClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPCopyinClause>(OMPC_copyin, StartLoc, LParenLoc, @@ -2464,7 +2724,6 @@ class OMPCopyinClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPCopyinClause(unsigned N) : OMPVarListClause<OMPCopyinClause>(OMPC_copyin, SourceLocation(), SourceLocation(), SourceLocation(), @@ -2532,43 +2791,47 @@ public: /// Required for proper codegen of propagation of master's thread values of /// threadprivate variables to local instances of that variables in other /// implicit threads. - /// static OMPCopyinClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps); + /// \brief Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPCopyinClause *CreateEmpty(const ASTContext &C, unsigned N); - typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; - typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; - typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; - typedef llvm::iterator_range<helper_expr_const_iterator> - helper_expr_const_range; + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; helper_expr_const_range source_exprs() const { return helper_expr_const_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_range source_exprs() { return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_const_range destination_exprs() const { return helper_expr_const_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_range destination_exprs() { return helper_expr_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_const_range assignment_ops() const { return helper_expr_const_range(getAssignmentOps().begin(), getAssignmentOps().end()); } + helper_expr_range assignment_ops() { return helper_expr_range(getAssignmentOps().begin(), getAssignmentOps().end()); @@ -2592,20 +2855,19 @@ public: /// \endcode /// In this example directive '#pragma omp single' has clause 'copyprivate' /// with the variables 'a' and 'b'. -/// class OMPCopyprivateClause final : public OMPVarListClause<OMPCopyprivateClause>, private llvm::TrailingObjects<OMPCopyprivateClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPCopyprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPCopyprivateClause>(OMPC_copyprivate, StartLoc, @@ -2614,7 +2876,6 @@ class OMPCopyprivateClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPCopyprivateClause(unsigned N) : OMPVarListClause<OMPCopyprivateClause>( OMPC_copyprivate, SourceLocation(), SourceLocation(), @@ -2681,43 +2942,47 @@ public: /// \endcode /// Required for proper codegen of final assignment performed by the /// copyprivate clause. - /// static OMPCopyprivateClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps); + /// \brief Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N); - typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator; - typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator; - typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range; - typedef llvm::iterator_range<helper_expr_const_iterator> - helper_expr_const_range; + using helper_expr_iterator = MutableArrayRef<Expr *>::iterator; + using helper_expr_const_iterator = ArrayRef<const Expr *>::iterator; + using helper_expr_range = llvm::iterator_range<helper_expr_iterator>; + using helper_expr_const_range = + llvm::iterator_range<helper_expr_const_iterator>; helper_expr_const_range source_exprs() const { return helper_expr_const_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_range source_exprs() { return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end()); } + helper_expr_const_range destination_exprs() const { return helper_expr_const_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_range destination_exprs() { return helper_expr_range(getDestinationExprs().begin(), getDestinationExprs().end()); } + helper_expr_const_range assignment_ops() const { return helper_expr_const_range(getAssignmentOps().begin(), getAssignmentOps().end()); } + helper_expr_range assignment_ops() { return helper_expr_range(getAssignmentOps().begin(), getAssignmentOps().end()); @@ -2745,19 +3010,18 @@ public: /// \endcode /// In this example directive '#pragma omp flush' has implicit clause 'flush' /// with the variables 'a' and 'b'. -/// class OMPFlushClause final : public OMPVarListClause<OMPFlushClause>, private llvm::TrailingObjects<OMPFlushClause, Expr *> { - friend TrailingObjects; friend OMPVarListClause; + friend TrailingObjects; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPFlushClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPFlushClause>(OMPC_flush, StartLoc, LParenLoc, @@ -2766,7 +3030,6 @@ class OMPFlushClause final /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPFlushClause(unsigned N) : OMPVarListClause<OMPFlushClause>(OMPC_flush, SourceLocation(), SourceLocation(), SourceLocation(), @@ -2780,15 +3043,14 @@ public: /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param VL List of references to the variables. - /// static OMPFlushClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPFlushClause *CreateEmpty(const ASTContext &C, unsigned N); child_range children() { @@ -2809,41 +3071,41 @@ public: /// \endcode /// In this example directive '#pragma omp task' with clause 'depend' with the /// variables 'a' and 'b' with dependency 'in'. -/// class OMPDependClause final : public OMPVarListClause<OMPDependClause>, private llvm::TrailingObjects<OMPDependClause, Expr *> { - friend TrailingObjects; - friend OMPVarListClause; friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + /// \brief Dependency type (one of in, out, inout). - OpenMPDependClauseKind DepKind; + OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown; + /// \brief Dependency type location. SourceLocation DepLoc; + /// \brief Colon location. SourceLocation ColonLoc; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. - /// OMPDependClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N) : OMPVarListClause<OMPDependClause>(OMPC_depend, StartLoc, LParenLoc, - EndLoc, N), - DepKind(OMPC_DEPEND_unknown) {} + EndLoc, N) {} /// \brief Build an empty clause. /// /// \param N Number of variables. - /// explicit OMPDependClause(unsigned N) : OMPVarListClause<OMPDependClause>(OMPC_depend, SourceLocation(), SourceLocation(), SourceLocation(), - N), - DepKind(OMPC_DEPEND_unknown) {} + N) {} + /// \brief Set dependency kind. void setDependencyKind(OpenMPDependClauseKind K) { DepKind = K; } @@ -2868,25 +3130,29 @@ public: Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - /// static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N); /// \brief Get dependency type. OpenMPDependClauseKind getDependencyKind() const { return DepKind; } + /// \brief Get dependency type location. SourceLocation getDependencyLoc() const { return DepLoc; } + /// \brief Get colon location. SourceLocation getColonLoc() const { return ColonLoc; } /// Set the loop counter value for the depend clauses with 'sink|source' kind /// of dependency. Required for codegen. void setCounterValue(Expr *V); + /// Get the loop counter value. Expr *getCounterValue(); + /// Get the loop counter value. const Expr *getCounterValue() const; @@ -2908,17 +3174,18 @@ public: /// \endcode /// In this example directive '#pragma omp target' has clause 'device' /// with single expression 'a'. -/// -class OMPDeviceClause : public OMPClause { +class OMPDeviceClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Device number. - Stmt *Device; + Stmt *Device = nullptr; + /// \brief Set the device number. /// /// \param E Device number. - /// void setDevice(Expr *E) { Device = E; } public: @@ -2928,31 +3195,35 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// - OMPDeviceClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) - : OMPClause(OMPC_device, StartLoc, EndLoc), LParenLoc(LParenLoc), - Device(E) {} + OMPDeviceClause(Expr *E, Stmt *HelperE, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_device, StartLoc, EndLoc), OMPClauseWithPreInit(this), + LParenLoc(LParenLoc), Device(E) { + setPreInitStmt(HelperE); + } /// \brief Build an empty clause. - /// OMPDeviceClause() - : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Device(nullptr) {} + : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), + OMPClauseWithPreInit(this) {} + /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return device number. Expr *getDevice() { return cast<Expr>(Device); } + /// \brief Return device number. Expr *getDevice() const { return cast<Expr>(Device); } + child_range children() { return child_range(&Device, &Device + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_device; } - - child_range children() { return child_range(&Device, &Device + 1); } }; /// \brief This represents 'threads' clause in the '#pragma omp ...' directive. @@ -2961,29 +3232,26 @@ public: /// #pragma omp ordered threads /// \endcode /// In this example directive '#pragma omp ordered' has simple 'threads' clause. -/// class OMPThreadsClause : public OMPClause { public: /// \brief Build 'threads' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_threads, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPThreadsClause() : OMPClause(OMPC_threads, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_threads; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_threads; + } }; /// \brief This represents 'simd' clause in the '#pragma omp ...' directive. @@ -2992,28 +3260,25 @@ public: /// #pragma omp ordered simd /// \endcode /// In this example directive '#pragma omp ordered' has simple 'simd' clause. -/// class OMPSIMDClause : public OMPClause { public: /// \brief Build 'simd' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_simd, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPSIMDClause() : OMPClause(OMPC_simd, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_simd; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_simd; + } }; /// \brief Struct that defines common infrastructure to handle mappable @@ -3029,13 +3294,14 @@ public: class MappableComponent { // \brief Expression associated with the component. Expr *AssociatedExpression = nullptr; + // \brief Declaration associated with the declaration. If the component does // not have a declaration (e.g. array subscripts or section), this is set to // nullptr. ValueDecl *AssociatedDeclaration = nullptr; public: - explicit MappableComponent() {} + explicit MappableComponent() = default; explicit MappableComponent(Expr *AssociatedExpression, ValueDecl *AssociatedDeclaration) : AssociatedExpression(AssociatedExpression), @@ -3045,6 +3311,7 @@ public: : nullptr) {} Expr *getAssociatedExpression() const { return AssociatedExpression; } + ValueDecl *getAssociatedDeclaration() const { return AssociatedDeclaration; } @@ -3052,14 +3319,14 @@ public: // \brief List of components of an expression. This first one is the whole // expression and the last one is the base expression. - typedef SmallVector<MappableComponent, 8> MappableExprComponentList; - typedef ArrayRef<MappableComponent> MappableExprComponentListRef; + using MappableExprComponentList = SmallVector<MappableComponent, 8>; + using MappableExprComponentListRef = ArrayRef<MappableComponent>; // \brief List of all component lists associated to the same base declaration. // E.g. if both 'S.a' and 'S.b' are a mappable expressions, each will have // their component list but the same base declaration 'S'. - typedef SmallVector<MappableExprComponentList, 8> MappableExprComponentLists; - typedef ArrayRef<MappableExprComponentList> MappableExprComponentListsRef; + using MappableExprComponentLists = SmallVector<MappableExprComponentList, 8>; + using MappableExprComponentListsRef = ArrayRef<MappableExprComponentList>; protected: // \brief Return the total number of elements in a list of component lists. @@ -3091,6 +3358,28 @@ class OMPMappableExprListClause : public OMPVarListClause<T>, unsigned NumComponents; protected: + /// \brief Build a clause for \a NumUniqueDeclarations declarations, \a + /// NumComponentLists total component lists, and \a NumComponents total + /// components. + /// + /// \param K Kind of the clause. + /// \param StartLoc Starting location of the clause (the clause keyword). + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param NumVars Number of expressions listed in the clause. + /// \param NumUniqueDeclarations Number of unique base declarations in this + /// clause. + /// \param NumComponentLists Number of component lists in this clause - one + /// list for each expression in the clause. + /// \param NumComponents Total number of expression components in the clause. + OMPMappableExprListClause(OpenMPClauseKind K, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + unsigned NumVars, unsigned NumUniqueDeclarations, + unsigned NumComponentLists, unsigned NumComponents) + : OMPVarListClause<T>(K, StartLoc, LParenLoc, EndLoc, NumVars), + NumUniqueDeclarations(NumUniqueDeclarations), + NumComponentLists(NumComponentLists), NumComponents(NumComponents) {} + /// \brief Get the unique declarations that are in the trailing objects of the /// class. MutableArrayRef<ValueDecl *> getUniqueDeclsRef() { @@ -3270,34 +3559,13 @@ protected: } } - /// \brief Build a clause for \a NumUniqueDeclarations declarations, \a - /// NumComponentLists total component lists, and \a NumComponents total - /// components. - /// - /// \param K Kind of the clause. - /// \param StartLoc Starting location of the clause (the clause keyword). - /// \param LParenLoc Location of '('. - /// \param EndLoc Ending location of the clause. - /// \param NumVars Number of expressions listed in the clause. - /// \param NumUniqueDeclarations Number of unique base declarations in this - /// clause. - /// \param NumComponentLists Number of component lists in this clause - one - /// list for each expression in the clause. - /// \param NumComponents Total number of expression components in the clause. - /// - OMPMappableExprListClause(OpenMPClauseKind K, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc, - unsigned NumVars, unsigned NumUniqueDeclarations, - unsigned NumComponentLists, unsigned NumComponents) - : OMPVarListClause<T>(K, StartLoc, LParenLoc, EndLoc, NumVars), - NumUniqueDeclarations(NumUniqueDeclarations), - NumComponentLists(NumComponentLists), NumComponents(NumComponents) {} - public: /// \brief Return the number of unique base declarations in this clause. unsigned getUniqueDeclarationsNum() const { return NumUniqueDeclarations; } + /// \brief Return the number of lists derived from the clause expressions. unsigned getTotalComponentListNum() const { return NumComponentLists; } + /// \brief Return the total number of components in all lists derived from the /// clause. unsigned getTotalComponentsNum() const { return NumComponents; } @@ -3317,11 +3585,11 @@ public: ArrayRef<unsigned>::iterator NumListsCur; // Remaining lists for the current declaration. - unsigned RemainingLists; + unsigned RemainingLists = 0; // The cumulative size of the previous list, or zero if there is no previous // list. - unsigned PrevListSize; + unsigned PrevListSize = 0; // The cumulative sizes of the current list - it will delimit the remaining // range of interest. @@ -3340,7 +3608,6 @@ public: : const_component_lists_iterator::iterator_adaptor_base( Components.begin()), DeclCur(UniqueDecls.begin()), NumListsCur(DeclsListNum.begin()), - RemainingLists(0u), PrevListSize(0u), ListSizeCur(CumulativeListSizes.begin()), ListSizeEnd(CumulativeListSizes.end()), End(Components.end()) { assert(UniqueDecls.size() == DeclsListNum.size() && @@ -3357,7 +3624,6 @@ public: MappableExprComponentListRef Components) : const_component_lists_iterator(UniqueDecls, DeclsListNum, CumulativeListSizes, Components) { - // Look for the desired declaration. While we are looking for it, we // update the state so that we know the component where a given list // starts. @@ -3437,8 +3703,8 @@ public: } }; - typedef llvm::iterator_range<const_component_lists_iterator> - const_component_lists_range; + using const_component_lists_range = + llvm::iterator_range<const_component_lists_iterator>; /// \brief Iterators for all component lists. const_component_lists_iterator component_lists_begin() const { @@ -3473,32 +3739,36 @@ public: /// Iterators to access all the declarations, number of lists, list sizes, and /// components. - typedef ArrayRef<ValueDecl *>::iterator const_all_decls_iterator; - typedef llvm::iterator_range<const_all_decls_iterator> const_all_decls_range; + using const_all_decls_iterator = ArrayRef<ValueDecl *>::iterator; + using const_all_decls_range = llvm::iterator_range<const_all_decls_iterator>; + const_all_decls_range all_decls() const { auto A = getUniqueDeclsRef(); return const_all_decls_range(A.begin(), A.end()); } - typedef ArrayRef<unsigned>::iterator const_all_num_lists_iterator; - typedef llvm::iterator_range<const_all_num_lists_iterator> - const_all_num_lists_range; + using const_all_num_lists_iterator = ArrayRef<unsigned>::iterator; + using const_all_num_lists_range = + llvm::iterator_range<const_all_num_lists_iterator>; + const_all_num_lists_range all_num_lists() const { auto A = getDeclNumListsRef(); return const_all_num_lists_range(A.begin(), A.end()); } - typedef ArrayRef<unsigned>::iterator const_all_lists_sizes_iterator; - typedef llvm::iterator_range<const_all_lists_sizes_iterator> - const_all_lists_sizes_range; + using const_all_lists_sizes_iterator = ArrayRef<unsigned>::iterator; + using const_all_lists_sizes_range = + llvm::iterator_range<const_all_lists_sizes_iterator>; + const_all_lists_sizes_range all_lists_sizes() const { auto A = getComponentListSizesRef(); return const_all_lists_sizes_range(A.begin(), A.end()); } - typedef ArrayRef<MappableComponent>::iterator const_all_components_iterator; - typedef llvm::iterator_range<const_all_components_iterator> - const_all_components_range; + using const_all_components_iterator = ArrayRef<MappableComponent>::iterator; + using const_all_components_range = + llvm::iterator_range<const_all_components_iterator>; + const_all_components_range all_components() const { auto A = getComponentsRef(); return const_all_components_range(A.begin(), A.end()); @@ -3513,15 +3783,14 @@ public: /// \endcode /// In this example directive '#pragma omp target' has clause 'map' /// with the variables 'a' and 'b'. -/// class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, private llvm::TrailingObjects< OMPMapClause, Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent> { - friend TrailingObjects; - friend OMPVarListClause; - friend OMPMappableExprListClause; friend class OMPClauseReader; + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; /// Define the sizes of each trailing object array except the last one. This /// is required for TrailingObjects to work properly. @@ -3536,37 +3805,20 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, } /// \brief Map type modifier for the 'map' clause. - OpenMPMapClauseKind MapTypeModifier; + OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; + /// \brief Map type for the 'map' clause. - OpenMPMapClauseKind MapType; + OpenMPMapClauseKind MapType = OMPC_MAP_unknown; + /// \brief Is this an implicit map type or not. - bool MapTypeIsImplicit; + bool MapTypeIsImplicit = false; + /// \brief Location of the map type. SourceLocation MapLoc; + /// \brief Colon location. SourceLocation ColonLoc; - /// \brief Set type modifier for the clause. - /// - /// \param T Type Modifier for the clause. - /// - void setMapTypeModifier(OpenMPMapClauseKind T) { MapTypeModifier = T; } - - /// \brief Set type for the clause. - /// - /// \param T Type for the clause. - /// - void setMapType(OpenMPMapClauseKind T) { MapType = T; } - - /// \brief Set type location. - /// - /// \param TLoc Type location. - /// - void setMapLoc(SourceLocation TLoc) { MapLoc = TLoc; } - - /// \brief Set colon location. - void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } - /// \brief Build a clause for \a NumVars listed expressions, \a /// NumUniqueDeclarations declarations, \a NumComponentLists total component /// lists, and \a NumComponents total expression components. @@ -3582,7 +3834,6 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPMapClause(OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool MapTypeIsImplicit, SourceLocation MapLoc, SourceLocation StartLoc, @@ -3602,14 +3853,29 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPMapClause(unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents) : OMPMappableExprListClause( OMPC_map, SourceLocation(), SourceLocation(), SourceLocation(), - NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents), - MapTypeModifier(OMPC_MAP_unknown), MapType(OMPC_MAP_unknown), - MapTypeIsImplicit(false), MapLoc() {} + NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents) {} + + /// \brief Set type modifier for the clause. + /// + /// \param T Type Modifier for the clause. + void setMapTypeModifier(OpenMPMapClauseKind T) { MapTypeModifier = T; } + + /// \brief Set type for the clause. + /// + /// \param T Type for the clause. + void setMapType(OpenMPMapClauseKind T) { MapType = T; } + + /// \brief Set type location. + /// + /// \param TLoc Type location. + void setMapLoc(SourceLocation TLoc) { MapLoc = TLoc; } + + /// \brief Set colon location. + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } public: /// \brief Creates clause with a list of variables \a VL. @@ -3624,7 +3890,6 @@ public: /// \param Type Map type. /// \param TypeIsImplicit Map type is inferred implicitly. /// \param TypeLoc Location of the map type. - /// static OMPMapClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> Vars, @@ -3633,6 +3898,7 @@ public: OpenMPMapClauseKind TypeModifier, OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc); + /// \brief Creates an empty clause with the place for for \a NumVars original /// expressions, \a NumUniqueDeclarations declarations, \NumComponentLists /// lists, and \a NumComponents expression components. @@ -3644,7 +3910,6 @@ public: /// \param NumComponentLists Number of unique base declarations in this /// clause. /// \param NumComponents Total number of expression components in the clause. - /// static OMPMapClause *CreateEmpty(const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, @@ -3671,15 +3936,15 @@ public: /// \brief Get colon location. SourceLocation getColonLoc() const { return ColonLoc; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_map; - } - child_range children() { return child_range( reinterpret_cast<Stmt **>(varlist_begin()), reinterpret_cast<Stmt **>(varlist_end())); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_map; + } }; /// \brief This represents 'num_teams' clause in the '#pragma omp ...' @@ -3690,17 +3955,18 @@ public: /// \endcode /// In this example directive '#pragma omp teams' has clause 'num_teams' /// with single expression 'n'. -/// class OMPNumTeamsClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief NumTeams number. - Stmt *NumTeams; + Stmt *NumTeams = nullptr; + /// \brief Set the NumTeams number. /// /// \param E NumTeams number. - /// void setNumTeams(Expr *E) { NumTeams = E; } public: @@ -3713,7 +3979,6 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPNumTeamsClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) @@ -3723,25 +3988,27 @@ public: } /// \brief Build an empty clause. - /// OMPNumTeamsClause() : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), LParenLoc(SourceLocation()), - NumTeams(nullptr) {} + OMPClauseWithPreInit(this) {} + /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return NumTeams number. Expr *getNumTeams() { return cast<Expr>(NumTeams); } + /// \brief Return NumTeams number. Expr *getNumTeams() const { return cast<Expr>(NumTeams); } + child_range children() { return child_range(&NumTeams, &NumTeams + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_num_teams; } - - child_range children() { return child_range(&NumTeams, &NumTeams + 1); } }; /// \brief This represents 'thread_limit' clause in the '#pragma omp ...' @@ -3752,17 +4019,18 @@ public: /// \endcode /// In this example directive '#pragma omp teams' has clause 'thread_limit' /// with single expression 'n'. -/// class OMPThreadLimitClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief ThreadLimit number. - Stmt *ThreadLimit; + Stmt *ThreadLimit = nullptr; + /// \brief Set the ThreadLimit number. /// /// \param E ThreadLimit number. - /// void setThreadLimit(Expr *E) { ThreadLimit = E; } public: @@ -3775,7 +4043,6 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPThreadLimitClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -3786,25 +4053,27 @@ public: } /// \brief Build an empty clause. - /// OMPThreadLimitClause() : OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), LParenLoc(SourceLocation()), - ThreadLimit(nullptr) {} + OMPClauseWithPreInit(this) {} + /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return ThreadLimit number. Expr *getThreadLimit() { return cast<Expr>(ThreadLimit); } + /// \brief Return ThreadLimit number. Expr *getThreadLimit() const { return cast<Expr>(ThreadLimit); } + child_range children() { return child_range(&ThreadLimit, &ThreadLimit + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_thread_limit; } - - child_range children() { return child_range(&ThreadLimit, &ThreadLimit + 1); } }; /// \brief This represents 'priority' clause in the '#pragma omp ...' @@ -3815,17 +4084,18 @@ public: /// \endcode /// In this example directive '#pragma omp teams' has clause 'priority' with /// single expression 'n'. -/// class OMPPriorityClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Priority number. - Stmt *Priority; + Stmt *Priority = nullptr; + /// \brief Set the Priority number. /// /// \param E Priority number. - /// void setPriority(Expr *E) { Priority = E; } public: @@ -3835,31 +4105,32 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPPriorityClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_priority, StartLoc, EndLoc), LParenLoc(LParenLoc), Priority(E) {} /// \brief Build an empty clause. - /// OMPPriorityClause() - : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Priority(nullptr) {} + : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()) {} + /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Return Priority number. Expr *getPriority() { return cast<Expr>(Priority); } + /// \brief Return Priority number. Expr *getPriority() const { return cast<Expr>(Priority); } + child_range children() { return child_range(&Priority, &Priority + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_priority; } - - child_range children() { return child_range(&Priority, &Priority + 1); } }; /// \brief This represents 'grainsize' clause in the '#pragma omp ...' @@ -3870,13 +4141,14 @@ public: /// \endcode /// In this example directive '#pragma omp taskloop' has clause 'grainsize' /// with single expression '4'. -/// class OMPGrainsizeClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Safe iteration space distance. - Stmt *Grainsize; + Stmt *Grainsize = nullptr; /// \brief Set safelen. void setGrainsize(Expr *Size) { Grainsize = Size; } @@ -3887,31 +4159,29 @@ public: /// \param Size Expression associated with this clause. /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_grainsize, StartLoc, EndLoc), LParenLoc(LParenLoc), Grainsize(Size) {} /// \brief Build an empty clause. - /// explicit OMPGrainsizeClause() - : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Grainsize(nullptr) {} + : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return safe iteration space distance. Expr *getGrainsize() const { return cast_or_null<Expr>(Grainsize); } + child_range children() { return child_range(&Grainsize, &Grainsize + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_grainsize; } - - child_range children() { return child_range(&Grainsize, &Grainsize + 1); } }; /// \brief This represents 'nogroup' clause in the '#pragma omp ...' directive. @@ -3920,29 +4190,26 @@ public: /// #pragma omp taskloop nogroup /// \endcode /// In this example directive '#pragma omp taskloop' has 'nogroup' clause. -/// class OMPNogroupClause : public OMPClause { public: /// \brief Build 'nogroup' clause. /// /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc) : OMPClause(OMPC_nogroup, StartLoc, EndLoc) {} /// \brief Build an empty clause. - /// OMPNogroupClause() : OMPClause(OMPC_nogroup, SourceLocation(), SourceLocation()) {} - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_nogroup; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_nogroup; + } }; /// \brief This represents 'num_tasks' clause in the '#pragma omp ...' @@ -3953,13 +4220,14 @@ public: /// \endcode /// In this example directive '#pragma omp taskloop' has clause 'num_tasks' /// with single expression '4'. -/// class OMPNumTasksClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Safe iteration space distance. - Stmt *NumTasks; + Stmt *NumTasks = nullptr; /// \brief Set safelen. void setNumTasks(Expr *Size) { NumTasks = Size; } @@ -3970,31 +4238,29 @@ public: /// \param Size Expression associated with this clause. /// \param StartLoc Starting location of the clause. /// \param EndLoc Ending location of the clause. - /// OMPNumTasksClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_num_tasks, StartLoc, EndLoc), LParenLoc(LParenLoc), NumTasks(Size) {} /// \brief Build an empty clause. - /// explicit OMPNumTasksClause() - : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), NumTasks(nullptr) {} + : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Return safe iteration space distance. Expr *getNumTasks() const { return cast_or_null<Expr>(NumTasks); } + child_range children() { return child_range(&NumTasks, &NumTasks + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_num_tasks; } - - child_range children() { return child_range(&NumTasks, &NumTasks + 1); } }; /// \brief This represents 'hint' clause in the '#pragma omp ...' directive. @@ -4004,16 +4270,16 @@ public: /// \endcode /// In this example directive '#pragma omp critical' has name 'name' and clause /// 'hint' with argument '6'. -/// class OMPHintClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Hint expression of the 'hint' clause. - Stmt *Hint; + Stmt *Hint = nullptr; /// \brief Set hint expression. - /// void setHint(Expr *H) { Hint = H; } public: @@ -4023,31 +4289,28 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// OMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) : OMPClause(OMPC_hint, StartLoc, EndLoc), LParenLoc(LParenLoc), Hint(Hint) {} /// \brief Build an empty clause. - /// - OMPHintClause() - : OMPClause(OMPC_hint, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Hint(nullptr) {} + OMPHintClause() : OMPClause(OMPC_hint, SourceLocation(), SourceLocation()) {} /// \brief Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. SourceLocation getLParenLoc() const { return LParenLoc; } /// \brief Returns number of threads. Expr *getHint() const { return cast_or_null<Expr>(Hint); } + child_range children() { return child_range(&Hint, &Hint + 1); } + static bool classof(const OMPClause *T) { return T->getClauseKind() == OMPC_hint; } - - child_range children() { return child_range(&Hint, &Hint + 1); } }; /// \brief This represents 'dist_schedule' clause in the '#pragma omp ...' @@ -4058,44 +4321,47 @@ public: /// \endcode /// In this example directive '#pragma omp distribute' has 'dist_schedule' /// clause with arguments 'static' and '3'. -/// class OMPDistScheduleClause : public OMPClause, public OMPClauseWithPreInit { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief A kind of the 'schedule' clause. - OpenMPDistScheduleClauseKind Kind; + OpenMPDistScheduleClauseKind Kind = OMPC_DIST_SCHEDULE_unknown; + /// \brief Start location of the schedule kind in source code. SourceLocation KindLoc; + /// \brief Location of ',' (if any). SourceLocation CommaLoc; + /// \brief Chunk size. - Expr *ChunkSize; + Expr *ChunkSize = nullptr; /// \brief Set schedule kind. /// /// \param K Schedule kind. - /// void setDistScheduleKind(OpenMPDistScheduleClauseKind K) { Kind = K; } + /// \brief Sets the location of '('. /// /// \param Loc Location of '('. - /// void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Set schedule kind start location. /// /// \param KLoc Schedule kind location. - /// void setDistScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + /// \brief Set location of ','. /// /// \param Loc Location of ','. - /// void setCommaLoc(SourceLocation Loc) { CommaLoc = Loc; } + /// \brief Set chunk size. /// /// \param E Chunk size. - /// void setChunkSize(Expr *E) { ChunkSize = E; } public: @@ -4110,7 +4376,6 @@ public: /// \param Kind DistSchedule kind. /// \param ChunkSize Chunk size. /// \param HelperChunkSize Helper chunk size for combined directives. - /// OMPDistScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KLoc, SourceLocation CommaLoc, SourceLocation EndLoc, @@ -4123,39 +4388,36 @@ public: } /// \brief Build an empty clause. - /// explicit OMPDistScheduleClause() : OMPClause(OMPC_dist_schedule, SourceLocation(), SourceLocation()), - OMPClauseWithPreInit(this), Kind(OMPC_DIST_SCHEDULE_unknown), - ChunkSize(nullptr) {} + OMPClauseWithPreInit(this) {} /// \brief Get kind of the clause. - /// OpenMPDistScheduleClauseKind getDistScheduleKind() const { return Kind; } + /// \brief Get location of '('. - /// SourceLocation getLParenLoc() { return LParenLoc; } + /// \brief Get kind location. - /// SourceLocation getDistScheduleKindLoc() { return KindLoc; } + /// \brief Get location of ','. - /// SourceLocation getCommaLoc() { return CommaLoc; } + /// \brief Get chunk size. - /// Expr *getChunkSize() { return ChunkSize; } + /// \brief Get chunk size. - /// const Expr *getChunkSize() const { return ChunkSize; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_dist_schedule; - } - child_range children() { return child_range(reinterpret_cast<Stmt **>(&ChunkSize), reinterpret_cast<Stmt **>(&ChunkSize) + 1); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_dist_schedule; + } }; /// \brief This represents 'defaultmap' clause in the '#pragma omp ...' directive. @@ -4165,46 +4427,49 @@ public: /// \endcode /// In this example directive '#pragma omp target' has 'defaultmap' clause of kind /// 'scalar' with modifier 'tofrom'. -/// class OMPDefaultmapClause : public OMPClause { friend class OMPClauseReader; + /// \brief Location of '('. SourceLocation LParenLoc; + /// \brief Modifiers for 'defaultmap' clause. - OpenMPDefaultmapClauseModifier Modifier; + OpenMPDefaultmapClauseModifier Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown; + /// \brief Locations of modifiers. SourceLocation ModifierLoc; + /// \brief A kind of the 'defaultmap' clause. - OpenMPDefaultmapClauseKind Kind; + OpenMPDefaultmapClauseKind Kind = OMPC_DEFAULTMAP_unknown; + /// \brief Start location of the defaultmap kind in source code. SourceLocation KindLoc; /// \brief Set defaultmap kind. /// /// \param K Defaultmap kind. - /// void setDefaultmapKind(OpenMPDefaultmapClauseKind K) { Kind = K; } + /// \brief Set the defaultmap modifier. /// /// \param M Defaultmap modifier. - /// void setDefaultmapModifier(OpenMPDefaultmapClauseModifier M) { Modifier = M; } + /// \brief Set location of the defaultmap modifier. - /// void setDefaultmapModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// \brief Sets the location of '('. /// /// \param Loc Location of '('. - /// void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Set defaultmap kind start location. /// /// \param KLoc Defaultmap kind location. - /// void setDefaultmapKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } public: @@ -4217,7 +4482,6 @@ public: /// \param Kind Defaultmap kind. /// \param M The modifier applied to 'defaultmap' clause. /// \param MLoc Location of the modifier - /// OMPDefaultmapClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KLoc, SourceLocation EndLoc, OpenMPDefaultmapClauseKind Kind, @@ -4226,39 +4490,35 @@ public: Modifier(M), ModifierLoc(MLoc), Kind(Kind), KindLoc(KLoc) {} /// \brief Build an empty clause. - /// explicit OMPDefaultmapClause() - : OMPClause(OMPC_defaultmap, SourceLocation(), SourceLocation()), - Modifier(OMPC_DEFAULTMAP_MODIFIER_unknown), - Kind(OMPC_DEFAULTMAP_unknown) {} + : OMPClause(OMPC_defaultmap, SourceLocation(), SourceLocation()) {} /// \brief Get kind of the clause. - /// OpenMPDefaultmapClauseKind getDefaultmapKind() const { return Kind; } + /// \brief Get the modifier of the clause. - /// OpenMPDefaultmapClauseModifier getDefaultmapModifier() const { return Modifier; } + /// \brief Get location of '('. - /// SourceLocation getLParenLoc() { return LParenLoc; } + /// \brief Get kind location. - /// SourceLocation getDefaultmapKindLoc() { return KindLoc; } + /// \brief Get the modifier location. - /// SourceLocation getDefaultmapModifierLoc() const { return ModifierLoc; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_defaultmap; - } - child_range children() { return child_range(child_iterator(), child_iterator()); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_defaultmap; + } }; /// \brief This represents clause 'to' in the '#pragma omp ...' @@ -4269,27 +4529,14 @@ public: /// \endcode /// In this example directive '#pragma omp target update' has clause 'to' /// with the variables 'a' and 'b'. -/// class OMPToClause final : public OMPMappableExprListClause<OMPToClause>, private llvm::TrailingObjects< OMPToClause, Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent> { - friend TrailingObjects; - friend OMPVarListClause; - friend OMPMappableExprListClause; friend class OMPClauseReader; - - /// Define the sizes of each trailing object array except the last one. This - /// is required for TrailingObjects to work properly. - size_t numTrailingObjects(OverloadToken<Expr *>) const { - return varlist_size(); - } - size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { - return getUniqueDeclarationsNum(); - } - size_t numTrailingObjects(OverloadToken<unsigned>) const { - return getUniqueDeclarationsNum() + getTotalComponentListNum(); - } + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; /// \brief Build clause with number of variables \a NumVars. /// @@ -4300,7 +4547,6 @@ class OMPToClause final : public OMPMappableExprListClause<OMPToClause>, /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPToClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned NumVars, unsigned NumUniqueDeclarations, @@ -4316,13 +4562,24 @@ class OMPToClause final : public OMPMappableExprListClause<OMPToClause>, /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPToClause(unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents) : OMPMappableExprListClause( OMPC_to, SourceLocation(), SourceLocation(), SourceLocation(), NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents) {} + /// Define the sizes of each trailing object array except the last one. This + /// is required for TrailingObjects to work properly. + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return varlist_size(); + } + size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { + return getUniqueDeclarationsNum(); + } + size_t numTrailingObjects(OverloadToken<unsigned>) const { + return getUniqueDeclarationsNum() + getTotalComponentListNum(); + } + public: /// \brief Creates clause with a list of variables \a Vars. /// @@ -4332,7 +4589,6 @@ public: /// \param Vars The original expression used in the clause. /// \param Declarations Declarations used in the clause. /// \param ComponentLists Component lists used in the clause. - /// static OMPToClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> Vars, @@ -4348,20 +4604,19 @@ public: /// \param NumComponentLists Number of unique base declarations in this /// clause. /// \param NumComponents Total number of expression components in the clause. - /// static OMPToClause *CreateEmpty(const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents); - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_to; - } - child_range children() { return child_range(reinterpret_cast<Stmt **>(varlist_begin()), reinterpret_cast<Stmt **>(varlist_end())); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_to; + } }; /// \brief This represents clause 'from' in the '#pragma omp ...' @@ -4372,28 +4627,15 @@ public: /// \endcode /// In this example directive '#pragma omp target update' has clause 'from' /// with the variables 'a' and 'b'. -/// class OMPFromClause final : public OMPMappableExprListClause<OMPFromClause>, private llvm::TrailingObjects< OMPFromClause, Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent> { - friend TrailingObjects; - friend OMPVarListClause; - friend OMPMappableExprListClause; friend class OMPClauseReader; - - /// Define the sizes of each trailing object array except the last one. This - /// is required for TrailingObjects to work properly. - size_t numTrailingObjects(OverloadToken<Expr *>) const { - return varlist_size(); - } - size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { - return getUniqueDeclarationsNum(); - } - size_t numTrailingObjects(OverloadToken<unsigned>) const { - return getUniqueDeclarationsNum() + getTotalComponentListNum(); - } + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; /// \brief Build clause with number of variables \a NumVars. /// @@ -4404,7 +4646,6 @@ class OMPFromClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPFromClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned NumVars, unsigned NumUniqueDeclarations, @@ -4420,13 +4661,24 @@ class OMPFromClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPFromClause(unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents) : OMPMappableExprListClause( OMPC_from, SourceLocation(), SourceLocation(), SourceLocation(), NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents) {} + /// Define the sizes of each trailing object array except the last one. This + /// is required for TrailingObjects to work properly. + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return varlist_size(); + } + size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { + return getUniqueDeclarationsNum(); + } + size_t numTrailingObjects(OverloadToken<unsigned>) const { + return getUniqueDeclarationsNum() + getTotalComponentListNum(); + } + public: /// \brief Creates clause with a list of variables \a Vars. /// @@ -4436,7 +4688,6 @@ public: /// \param Vars The original expression used in the clause. /// \param Declarations Declarations used in the clause. /// \param ComponentLists Component lists used in the clause. - /// static OMPFromClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> Vars, @@ -4452,20 +4703,19 @@ public: /// \param NumComponentLists Number of unique base declarations in this /// clause. /// \param NumComponents Total number of expression components in the clause. - /// static OMPFromClause *CreateEmpty(const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents); - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_from; - } - child_range children() { return child_range(reinterpret_cast<Stmt **>(varlist_begin()), reinterpret_cast<Stmt **>(varlist_end())); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_from; + } }; /// This represents clause 'use_device_ptr' in the '#pragma omp ...' @@ -4476,28 +4726,15 @@ public: /// \endcode /// In this example directive '#pragma omp target data' has clause /// 'use_device_ptr' with the variables 'a' and 'b'. -/// class OMPUseDevicePtrClause final : public OMPMappableExprListClause<OMPUseDevicePtrClause>, private llvm::TrailingObjects< OMPUseDevicePtrClause, Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent> { - friend TrailingObjects; - friend OMPVarListClause; - friend OMPMappableExprListClause; friend class OMPClauseReader; - - /// Define the sizes of each trailing object array except the last one. This - /// is required for TrailingObjects to work properly. - size_t numTrailingObjects(OverloadToken<Expr *>) const { - return 3 * varlist_size(); - } - size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { - return getUniqueDeclarationsNum(); - } - size_t numTrailingObjects(OverloadToken<unsigned>) const { - return getUniqueDeclarationsNum() + getTotalComponentListNum(); - } + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; /// Build clause with number of variables \a NumVars. /// @@ -4508,7 +4745,6 @@ class OMPUseDevicePtrClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPUseDevicePtrClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned NumVars, @@ -4526,7 +4762,6 @@ class OMPUseDevicePtrClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPUseDevicePtrClause(unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, @@ -4536,6 +4771,18 @@ class OMPUseDevicePtrClause final NumUniqueDeclarations, NumComponentLists, NumComponents) {} + /// Define the sizes of each trailing object array except the last one. This + /// is required for TrailingObjects to work properly. + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return 3 * varlist_size(); + } + size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { + return getUniqueDeclarationsNum(); + } + size_t numTrailingObjects(OverloadToken<unsigned>) const { + return getUniqueDeclarationsNum() + getTotalComponentListNum(); + } + /// Sets the list of references to private copies with initializers for new /// private variables. /// \param VL List of references. @@ -4575,7 +4822,6 @@ public: /// \param Inits Expressions referring to private copy initializers. /// \param Declarations Declarations used in the clause. /// \param ComponentLists Component lists used in the clause. - /// static OMPUseDevicePtrClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> Vars, @@ -4592,36 +4838,37 @@ public: /// \param NumComponentLists Number of unique base declarations in this /// clause. /// \param NumComponents Total number of expression components in the clause. - /// static OMPUseDevicePtrClause *CreateEmpty(const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, unsigned NumComponents); - typedef MutableArrayRef<Expr *>::iterator private_copies_iterator; - typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator; - typedef llvm::iterator_range<private_copies_iterator> private_copies_range; - typedef llvm::iterator_range<private_copies_const_iterator> - private_copies_const_range; + using private_copies_iterator = MutableArrayRef<Expr *>::iterator; + using private_copies_const_iterator = ArrayRef<const Expr *>::iterator; + using private_copies_range = llvm::iterator_range<private_copies_iterator>; + using private_copies_const_range = + llvm::iterator_range<private_copies_const_iterator>; private_copies_range private_copies() { return private_copies_range(getPrivateCopies().begin(), getPrivateCopies().end()); } + private_copies_const_range private_copies() const { return private_copies_const_range(getPrivateCopies().begin(), getPrivateCopies().end()); } - typedef MutableArrayRef<Expr *>::iterator inits_iterator; - typedef ArrayRef<const Expr *>::iterator inits_const_iterator; - typedef llvm::iterator_range<inits_iterator> inits_range; - typedef llvm::iterator_range<inits_const_iterator> inits_const_range; + using inits_iterator = MutableArrayRef<Expr *>::iterator; + using inits_const_iterator = ArrayRef<const Expr *>::iterator; + using inits_range = llvm::iterator_range<inits_iterator>; + using inits_const_range = llvm::iterator_range<inits_const_iterator>; inits_range inits() { return inits_range(getInits().begin(), getInits().end()); } + inits_const_range inits() const { return inits_const_range(getInits().begin(), getInits().end()); } @@ -4644,28 +4891,16 @@ public: /// \endcode /// In this example directive '#pragma omp target' has clause /// 'is_device_ptr' with the variables 'a' and 'b'. -/// class OMPIsDevicePtrClause final : public OMPMappableExprListClause<OMPIsDevicePtrClause>, private llvm::TrailingObjects< OMPIsDevicePtrClause, Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent> { - friend TrailingObjects; - friend OMPVarListClause; - friend OMPMappableExprListClause; friend class OMPClauseReader; + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; - /// Define the sizes of each trailing object array except the last one. This - /// is required for TrailingObjects to work properly. - size_t numTrailingObjects(OverloadToken<Expr *>) const { - return varlist_size(); - } - size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { - return getUniqueDeclarationsNum(); - } - size_t numTrailingObjects(OverloadToken<unsigned>) const { - return getUniqueDeclarationsNum() + getTotalComponentListNum(); - } /// Build clause with number of variables \a NumVars. /// /// \param StartLoc Starting location of the clause. @@ -4675,7 +4910,6 @@ class OMPIsDevicePtrClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPIsDevicePtrClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, unsigned NumVars, @@ -4693,7 +4927,6 @@ class OMPIsDevicePtrClause final /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - /// explicit OMPIsDevicePtrClause(unsigned NumVars, unsigned NumUniqueDeclarations, unsigned NumComponentLists, @@ -4703,6 +4936,18 @@ class OMPIsDevicePtrClause final NumUniqueDeclarations, NumComponentLists, NumComponents) {} + /// Define the sizes of each trailing object array except the last one. This + /// is required for TrailingObjects to work properly. + size_t numTrailingObjects(OverloadToken<Expr *>) const { + return varlist_size(); + } + size_t numTrailingObjects(OverloadToken<ValueDecl *>) const { + return getUniqueDeclarationsNum(); + } + size_t numTrailingObjects(OverloadToken<unsigned>) const { + return getUniqueDeclarationsNum() + getTotalComponentListNum(); + } + public: /// Creates clause with a list of variables \a Vars. /// @@ -4712,7 +4957,6 @@ public: /// \param Vars The original expression used in the clause. /// \param Declarations Declarations used in the clause. /// \param ComponentLists Component lists used in the clause. - /// static OMPIsDevicePtrClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> Vars, @@ -4728,7 +4972,6 @@ public: /// \param NumComponentLists Number of unique base declarations in this /// clause. /// \param NumComponents Total number of expression components in the clause. - /// static OMPIsDevicePtrClause *CreateEmpty(const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, @@ -4744,6 +4987,7 @@ public: return T->getClauseKind() == OMPC_is_device_ptr; } }; -} // end namespace clang + +} // namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.def b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.def index 2d48a7df47b7a..b13cf3b63276f 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.def +++ b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.def @@ -327,12 +327,13 @@ CAST_OPERATION(ZeroToOCLQueue) // Convert a pointer to a different address space. CAST_OPERATION(AddressSpaceConversion) -// Convert an integer initializer to an OpenCL sampler.
+// Convert an integer initializer to an OpenCL sampler. CAST_OPERATION(IntToOCLSampler) //===- Binary Operations -------------------------------------------------===// // Operators listed in order of precedence. -// Note that additions to this should also update the StmtVisitor class. +// Note that additions to this should also update the StmtVisitor class and +// BinaryOperator::getOverloadedOperator. // [C++ 5.5] Pointer-to-member operators. BINARY_OPERATION(PtrMemD, ".*") @@ -347,6 +348,8 @@ BINARY_OPERATION(Sub, "-") // [C99 6.5.7] Bitwise shift operators. BINARY_OPERATION(Shl, "<<") BINARY_OPERATION(Shr, ">>") +// C++20 [expr.spaceship] Three-way comparison operator. +BINARY_OPERATION(Cmp, "<=>") // [C99 6.5.8] Relational operators. BINARY_OPERATION(LT, "<") BINARY_OPERATION(GT, ">") @@ -382,7 +385,8 @@ BINARY_OPERATION(Comma, ",") //===- Unary Operations ---------------------------------------------------===// -// Note that additions to this should also update the StmtVisitor class. +// Note that additions to this should also update the StmtVisitor class and +// UnaryOperator::getOverloadedOperator. // [C99 6.5.2.4] Postfix increment and decrement UNARY_OPERATION(PostInc, "++") diff --git a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h index 00f060fe9e3d0..e3832689d64b8 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h +++ b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h @@ -23,8 +23,6 @@ enum CastKind { #include "clang/AST/OperationKinds.def" }; -static const CastKind CK_Invalid = static_cast<CastKind>(-1); - enum BinaryOperatorKind { #define BINARY_OPERATION(Name, Spelling) BO_##Name, #include "clang/AST/OperationKinds.def" diff --git a/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h b/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h index 274df220e160e..e831b903cbae6 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h +++ b/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h @@ -30,8 +30,8 @@ public: virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0; }; -/// \brief Describes how types, statements, expressions, and -/// declarations should be printed. +/// Describes how types, statements, expressions, and declarations should be +/// printed. /// /// This type is intended to be small and suitable for passing by value. /// It is very frequently copied. @@ -50,22 +50,24 @@ struct PrintingPolicy { UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), - IncludeNewlines(true), MSVCFormatting(false) { } + IncludeNewlines(true), MSVCFormatting(false), + ConstantsAsWritten(false), SuppressImplicitBase(false), + FullyQualifiedName(false) { } - /// \brief 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 construct). This should not be used if a real LangOptions - /// object is available. + /// 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 + /// construct). This should not be used if a real LangOptions object is + /// available. void adjustForCPlusPlus() { SuppressTagKeyword = true; Bool = true; UseVoidForZeroParams = false; } - /// \brief The number of spaces to use to indent each line. + /// The number of spaces to use to indent each line. unsigned Indentation : 8; - /// \brief Whether we should suppress printing of the actual specifiers for + /// Whether we should suppress printing of the actual specifiers for /// the given type or declaration. /// /// This flag is only used when we are printing declarators beyond @@ -81,7 +83,7 @@ struct PrintingPolicy { /// "const int" type specifier and instead only print the "*y". bool SuppressSpecifiers : 1; - /// \brief Whether type printing should skip printing the tag keyword. + /// Whether type printing should skip printing the tag keyword. /// /// This is used when printing the inner type of elaborated types, /// (as the tag keyword is part of the elaborated type): @@ -91,7 +93,7 @@ struct PrintingPolicy { /// \endcode bool SuppressTagKeyword : 1; - /// \brief When true, include the body of a tag definition. + /// When true, include the body of a tag definition. /// /// This is used to place the definition of a struct /// in the middle of another declaration as with: @@ -101,14 +103,14 @@ struct PrintingPolicy { /// \endcode bool IncludeTagDefinition : 1; - /// \brief Suppresses printing of scope specifiers. + /// Suppresses printing of scope specifiers. bool SuppressScope : 1; - /// \brief Suppress printing parts of scope specifiers that don't need + /// Suppress printing parts of scope specifiers that don't need /// to be written, e.g., for inline or anonymous namespaces. bool SuppressUnwrittenScope : 1; - /// \brief Suppress printing of variable initializers. + /// Suppress printing of variable initializers. /// /// This flag is used when printing the loop variable in a for-range /// statement. For example, given: @@ -121,8 +123,8 @@ struct PrintingPolicy { /// internal initializer constructed for x will not be printed. bool SuppressInitializers : 1; - /// \brief Whether we should print the sizes of constant array expressions - /// as written in the sources. + /// Whether we should print the sizes of constant array expressions as written + /// in the sources. /// /// This flag determines whether array types declared as /// @@ -139,67 +141,90 @@ struct PrintingPolicy { /// \endcode bool ConstantArraySizeAsWritten : 1; - /// \brief When printing an anonymous tag name, also print the location of - /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just - /// prints "(anonymous)" for the name. + /// When printing an anonymous tag name, also print the location of that + /// entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just prints + /// "(anonymous)" for the name. bool AnonymousTagLocations : 1; - /// \brief When true, suppress printing of the __strong lifetime qualifier in - /// ARC. + /// When true, suppress printing of the __strong lifetime qualifier in ARC. unsigned SuppressStrongLifetime : 1; - /// \brief When true, suppress printing of lifetime qualifier in - /// ARC. + /// When true, suppress printing of lifetime qualifier in ARC. unsigned SuppressLifetimeQualifiers : 1; /// When true, suppresses printing template arguments in names of C++ /// constructors. unsigned SuppressTemplateArgsInCXXConstructors : 1; - /// \brief Whether we can use 'bool' rather than '_Bool' (even if the language + /// Whether we can use 'bool' rather than '_Bool' (even if the language /// doesn't actually have 'bool', because, e.g., it is defined as a macro). unsigned Bool : 1; - /// \brief Whether we can use 'restrict' rather than '__restrict'. + /// Whether we can use 'restrict' rather than '__restrict'. unsigned Restrict : 1; - /// \brief Whether we can use 'alignof' rather than '__alignof'. + /// Whether we can use 'alignof' rather than '__alignof'. unsigned Alignof : 1; - /// \brief Whether we can use '_Alignof' rather than '__alignof'. + /// Whether we can use '_Alignof' rather than '__alignof'. unsigned UnderscoreAlignof : 1; - /// \brief Whether we should use '(void)' rather than '()' for a function - /// prototype with zero parameters. + /// Whether we should use '(void)' rather than '()' for a function prototype + /// with zero parameters. unsigned UseVoidForZeroParams : 1; - /// \brief Provide a 'terse' output. + /// Provide a 'terse' output. /// /// For example, in this mode we don't print function bodies, class members, /// declarations inside namespaces etc. Effectively, this should print /// only the requested declaration. unsigned TerseOutput : 1; - /// \brief When true, do certain refinement needed for producing proper - /// declaration tag; such as, do not print attributes attached to the declaration. + /// When true, do certain refinement needed for producing proper declaration + /// tag; such as, do not print attributes attached to the declaration. /// unsigned PolishForDeclaration : 1; - /// \brief When true, print the half-precision floating-point type as 'half' + /// When true, print the half-precision floating-point type as 'half' /// instead of '__fp16' unsigned Half : 1; - /// \brief When true, print the built-in wchar_t type as __wchar_t. For use in + /// When true, print the built-in wchar_t type as __wchar_t. For use in /// Microsoft mode when wchar_t is not available. unsigned MSWChar : 1; - /// \brief When true, include newlines after statements like "break", etc. + /// When true, include newlines after statements like "break", etc. unsigned IncludeNewlines : 1; - /// \brief Use whitespace and punctuation like MSVC does. In particular, this - /// prints anonymous namespaces as `anonymous namespace' and does not insert - /// spaces after template arguments. + /// Use whitespace and punctuation like MSVC does. In particular, this prints + /// anonymous namespaces as `anonymous namespace' and does not insert spaces + /// after template arguments. bool MSVCFormatting : 1; + + /// Whether we should print the constant expressions as written in the + /// sources. + /// + /// This flag determines whether constants expressions like + /// + /// \code + /// 0x10 + /// 2.5e3 + /// \endcode + /// + /// will be printed as written or as follows: + /// + /// \code + /// 0x10 + /// 2.5e3 + /// \endcode + bool ConstantsAsWritten : 1; + + /// When true, don't print the implicit 'self' or 'this' expressions. + bool SuppressImplicitBase : 1; + + /// When true, print the fully qualified name of function declarations. + /// This is the opposite of SuppressScope and thus overrules it. + bool FullyQualifiedName : 1; }; } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Core/QualTypeNames.h b/contrib/llvm/tools/clang/include/clang/AST/QualTypeNames.h index 7248356e748e8..86d805feeed76 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Core/QualTypeNames.h +++ b/contrib/llvm/tools/clang/include/clang/AST/QualTypeNames.h @@ -56,8 +56,8 @@ // // ===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H -#define LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H +#ifndef LLVM_CLANG_AST_QUALTYPENAMES_H +#define LLVM_CLANG_AST_QUALTYPENAMES_H #include "clang/AST/ASTContext.h" @@ -71,9 +71,20 @@ namespace TypeName { /// \param[in] Ctx - the ASTContext to be used. /// \param[in] WithGlobalNsPrefix - If true, then the global namespace /// specifier "::" will be prepended to the fully qualified name. -std::string getFullyQualifiedName(QualType QT, - const ASTContext &Ctx, +std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx, bool WithGlobalNsPrefix = false); -} // end namespace TypeName -} // end namespace clang -#endif // LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H + +/// \brief Generates a QualType that can be used to name the same type +/// if used at the end of the current translation unit. This ignores +/// issues such as type shadowing. +/// +/// \param[in] QT - the type for which the fully qualified type will be +/// returned. +/// \param[in] Ctx - the ASTContext to be used. +/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace +/// specifier "::" should be prepended or not. +QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, + bool WithGlobalNsPrefix = false); +} // end namespace TypeName +} // end namespace clang +#endif // LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h b/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h index 7a39c3b2539df..696d44efa0d9d 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h +++ b/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h @@ -1,4 +1,4 @@ -//===--- RecordLayout.h - Layout information for a struct/union -*- C++ -*-===// +//===- RecordLayout.h - Layout information for a struct/union ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,15 +14,20 @@ #ifndef LLVM_CLANG_AST_RECORDLAYOUT_H #define LLVM_CLANG_AST_RECORDLAYOUT_H +#include "clang/AST/ASTVector.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include <cassert> +#include <cstdint> namespace clang { - class ASTContext; - class FieldDecl; - class RecordDecl; - class CXXRecordDecl; + +class ASTContext; +class CXXRecordDecl; /// ASTRecordLayout - /// This class contains layout information for one RecordDecl, @@ -42,21 +47,21 @@ public: /// Whether this virtual base requires a vtordisp field in the /// Microsoft ABI. These fields are required for certain operations /// in constructors and destructors. - bool HasVtorDisp; + bool HasVtorDisp = false; public: - bool hasVtorDisp() const { return HasVtorDisp; } - - VBaseInfo() : HasVtorDisp(false) {} + VBaseInfo() = default; + VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp) + : VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {} - VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp) : - VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {} + bool hasVtorDisp() const { return HasVtorDisp; } }; - typedef llvm::DenseMap<const CXXRecordDecl *, VBaseInfo> - VBaseOffsetsMapTy; + using VBaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>; private: + friend class ASTContext; + /// Size - Size of record in characters. CharUnits Size; @@ -117,7 +122,7 @@ private: const CXXRecordDecl *BaseSharingVBPtr; /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) - typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; + using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>; /// BaseOffsets - Contains a map from base classes to their offset. BaseOffsetsMapTy BaseOffsets; @@ -128,16 +133,15 @@ private: /// CXXInfo - If the record layout is for a C++ record, this will have /// C++ specific information about the record. - CXXRecordLayoutInfo *CXXInfo; - - friend class ASTContext; + CXXRecordLayoutInfo *CXXInfo = nullptr; ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits requiredAlignment, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets); + using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy; + // Constructor for C++ records. - typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits requiredAlignment, @@ -159,9 +163,9 @@ private: void Destroy(ASTContext &Ctx); - ASTRecordLayout(const ASTRecordLayout &) = delete; - void operator=(const ASTRecordLayout &) = delete; public: + ASTRecordLayout(const ASTRecordLayout &) = delete; + ASTRecordLayout &operator=(const ASTRecordLayout &) = delete; /// getAlignment - Get the record alignment in characters. CharUnits getAlignment() const { return Alignment; } @@ -305,6 +309,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_RECORDLAYOUT_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h index e7f271cc0812d..ba76ea0a0df55 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h @@ -63,8 +63,8 @@ OPERATOR(PtrMemD) OPERATOR(PtrMemI) OPERATOR(Mul) OPERATOR(Div) \ OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) OPERATOR(Shr) \ OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) OPERATOR(GE) OPERATOR(EQ) \ - OPERATOR(NE) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) OPERATOR(LAnd) \ - OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma) + OPERATOR(NE) OPERATOR(Cmp) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) \ + OPERATOR(LAnd) OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma) // All compound assign operators. #define CAO_LIST() \ @@ -83,7 +83,7 @@ namespace clang { return false; \ } while (false) -/// \brief A class that does preordor or postorder +/// \brief A class that does preorder or postorder /// depth-first traversal on the entire Clang AST and visits each node. /// /// This class performs three distinct tasks: @@ -267,6 +267,12 @@ public: bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + /// \brief Recursively visit a base specifier. This can be overridden by a + /// subclass. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base); + /// \brief Recursively visit a constructor initializer. This /// automatically dispatches to another visitor for the initializer /// expression, but not for the name of the initializer, so may @@ -309,6 +315,8 @@ public: // ---- Methods on Stmts ---- + Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } + private: template<typename T, typename U> struct has_same_member_pointer_type : std::false_type {}; @@ -491,6 +499,8 @@ public: bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } #include "clang/AST/DeclNodes.inc" + bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child); + private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); @@ -978,6 +988,11 @@ DEF_TRAVERSE_TYPE(DependentSizedArrayType, { TRY_TO(TraverseStmt(T->getSizeExpr())); }) +DEF_TRAVERSE_TYPE(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(T->getAddrSpaceExpr())); + TRY_TO(TraverseType(T->getPointeeType())); +}) + DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { if (T->getSizeExpr()) TRY_TO(TraverseStmt(T->getSizeExpr())); @@ -1188,6 +1203,11 @@ DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { return TraverseArrayTypeLocHelper(TL); }) +DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getAddrSpaceExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getPointeeType())); +}) + // FIXME: order? why not size expr first? // FIXME: base VectorTypeLoc is unfinished DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { @@ -1339,14 +1359,20 @@ DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) // than those. template <typename Derived> +bool RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext( + const Decl *Child) { + // BlockDecls and CapturedDecls are traversed through BlockExprs and + // CapturedStmts respectively. + return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child); +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) { if (!DC) return true; for (auto *Child : DC->decls()) { - // BlockDecls and CapturedDecls are traversed through BlockExprs and - // CapturedStmts respectively. - if (!isa<BlockDecl>(Child) && !isa<CapturedDecl>(Child)) + if (!canIgnoreChildDeclWhileTraversingDeclContext(Child)) TRY_TO(TraverseDecl(Child)); } @@ -1674,8 +1700,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( // template declarations. #define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \ DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \ - TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \ + TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ \ /* By default, we do not traverse the instantiations of \ class templates since they do not appear in the user code. The \ @@ -1769,12 +1795,19 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseCXXBaseSpecifier( + const CXXBaseSpecifier &Base) { + TRY_TO(TraverseTypeLoc(Base.getTypeSourceInfo()->getTypeLoc())); + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(CXXRecordDecl *D) { if (!TraverseRecordHelper(D)) return false; if (D->isCompleteDefinition()) { for (const auto &I : D->bases()) { - TRY_TO(TraverseTypeLoc(I.getTypeSourceInfo()->getTypeLoc())); + TRY_TO(TraverseCXXBaseSpecifier(I)); } // We don't traverse the friends or the conversions, as they are // already in decls_begin()/decls_end(). @@ -2057,7 +2090,7 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { TRY_TO(WalkUpFrom##STMT(S)); \ { CODE; } \ if (ShouldVisitChildren) { \ - for (Stmt *SubStmt : S->children()) { \ + for (Stmt * SubStmt : getDerived().getStmtChildren(S)) { \ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \ } \ } \ @@ -3039,6 +3072,30 @@ bool RecursiveASTVisitor<Derived>::VisitOMPTaskReductionClause( } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPInReductionClause( + OMPInReductionClause *C) { + TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); + TRY_TO(VisitOMPClauseList(C)); + TRY_TO(VisitOMPClauseWithPostUpdate(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->lhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->rhs_exprs()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->reduction_ops()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->taskgroup_descriptors()) + TRY_TO(TraverseStmt(E)); + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) { TRY_TO(VisitOMPClauseList(C)); return true; @@ -3052,6 +3109,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) { + TRY_TO(VisitOMPClauseWithPreInit(C)); TRY_TO(TraverseStmt(C->getDevice())); return true; } diff --git a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h index 89a9d3c4cc212..86b0f356e7b53 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h @@ -1,4 +1,4 @@ -//===-- Redeclarable.h - Base for Decls that can be redeclared -*- C++ -*-====// +//===- Redeclarable.h - Base for Decls that can be redeclared --*- C++ -*-====// // // The LLVM Compiler Infrastructure // @@ -15,11 +15,18 @@ #define LLVM_CLANG_AST_REDECLARABLE_H #include "clang/AST/ExternalASTSource.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" +#include <cassert> +#include <cstddef> #include <iterator> namespace clang { + class ASTContext; +class Decl; // Some notes on redeclarables: // @@ -82,21 +89,21 @@ protected: class DeclLink { /// A pointer to a known latest declaration, either statically known or /// generationally updated as decls are added by an external source. - typedef LazyGenerationalUpdatePtr<const Decl*, Decl*, - &ExternalASTSource::CompleteRedeclChain> - KnownLatest; + using KnownLatest = + LazyGenerationalUpdatePtr<const Decl *, Decl *, + &ExternalASTSource::CompleteRedeclChain>; /// We store a pointer to the ASTContext in the UninitializedLatest /// pointer, but to avoid circular type dependencies when we steal the low /// bits of this pointer, we use a raw void* here. - typedef const void *UninitializedLatest; + using UninitializedLatest = const void *; - typedef Decl *Previous; + using Previous = Decl *; /// A pointer to either an uninitialized latest declaration (where either /// we've not yet set the previous decl or there isn't one), or to a known /// previous declaration. - typedef llvm::PointerUnion<Previous, UninitializedLatest> NotKnownLatest; + using NotKnownLatest = llvm::PointerUnion<Previous, UninitializedLatest>; mutable llvm::PointerUnion<NotKnownLatest, KnownLatest> Next; @@ -106,8 +113,7 @@ protected: DeclLink(LatestTag, const ASTContext &Ctx) : Next(NotKnownLatest(reinterpret_cast<UninitializedLatest>(&Ctx))) {} - DeclLink(PreviousTag, decl_type *D) - : Next(NotKnownLatest(Previous(D))) {} + DeclLink(PreviousTag, decl_type *D) : Next(NotKnownLatest(Previous(D))) {} bool NextIsPrevious() const { return Next.is<NotKnownLatest>() && @@ -182,6 +188,7 @@ protected: /// /// If there is only one declaration, it is <pointer to self, true> DeclLink RedeclLink; + decl_type *First; decl_type *getNextRedeclaration() const { @@ -189,8 +196,12 @@ protected: } public: - Redeclarable(const ASTContext &Ctx) - : RedeclLink(LatestDeclLink(Ctx)), First(static_cast<decl_type *>(this)) {} + friend class ASTDeclReader; + friend class ASTDeclWriter; + + Redeclarable(const ASTContext &Ctx) + : RedeclLink(LatestDeclLink(Ctx)), + First(static_cast<decl_type *>(this)) {} /// \brief Return the previous declaration of this declaration or NULL if this /// is the first declaration. @@ -232,20 +243,19 @@ public: /// \brief Iterates through all the redeclarations of the same decl. class redecl_iterator { /// Current - The current declaration. - decl_type *Current; + decl_type *Current = nullptr; decl_type *Starter; - bool PassedFirst; + bool PassedFirst = false; public: - typedef decl_type* value_type; - typedef decl_type* reference; - typedef decl_type* pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = decl_type *; + using reference = decl_type *; + using pointer = decl_type *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; - redecl_iterator() : Current(nullptr) { } - explicit redecl_iterator(decl_type *C) - : Current(C), Starter(C), PassedFirst(false) { } + redecl_iterator() = default; + explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) {} reference operator*() const { return Current; } pointer operator->() const { return Current; } @@ -282,7 +292,7 @@ public: } }; - typedef llvm::iterator_range<redecl_iterator> redecl_range; + using redecl_range = llvm::iterator_range<redecl_iterator>; /// \brief Returns an iterator range for all the redeclarations of the same /// decl. It will iterate at least once (when this decl is the only one). @@ -294,9 +304,6 @@ public: redecl_iterator redecls_begin() const { return redecls().begin(); } redecl_iterator redecls_end() const { return redecls().end(); } - - friend class ASTDeclReader; - friend class ASTDeclWriter; }; /// \brief Get the primary declaration for a declaration from an AST file. That @@ -309,7 +316,7 @@ Decl *getPrimaryMergedDecl(Decl *D); template<typename decl_type> class Mergeable { public: - Mergeable() {} + Mergeable() = default; /// \brief Return the first declaration of this declaration or itself if this /// is the only declaration. @@ -344,7 +351,7 @@ public: /// remember to call getCanonicalDecl() everywhere. template <typename decl_type> class CanonicalDeclPtr { public: - CanonicalDeclPtr() : Ptr(nullptr) {} + CanonicalDeclPtr() = default; CanonicalDeclPtr(decl_type *Ptr) : Ptr(Ptr ? Ptr->getCanonicalDecl() : nullptr) {} CanonicalDeclPtr(const CanonicalDeclPtr &) = default; @@ -362,11 +369,13 @@ public: private: friend struct llvm::DenseMapInfo<CanonicalDeclPtr<decl_type>>; - decl_type *Ptr; + decl_type *Ptr = nullptr; }; + } // namespace clang namespace llvm { + template <typename decl_type> struct DenseMapInfo<clang::CanonicalDeclPtr<decl_type>> { using CanonicalDeclPtr = clang::CanonicalDeclPtr<decl_type>; @@ -395,6 +404,7 @@ struct DenseMapInfo<clang::CanonicalDeclPtr<decl_type>> { return BaseInfo::isEqual(LHS, RHS); } }; + } // namespace llvm -#endif +#endif // LLVM_CLANG_AST_REDECLARABLE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h index c210bd1cec2e3..6bd07af1affa5 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h @@ -1,4 +1,4 @@ -//===--- Stmt.h - Classes for representing statements -----------*- C++ -*-===// +//===- Stmt.h - Classes for representing statements -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -22,34 +22,40 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> #include <string> namespace llvm { - class FoldingSetNodeID; -} + +class FoldingSetNodeID; + +} // namespace llvm namespace clang { - class ASTContext; - class Attr; - class CapturedDecl; - class Decl; - class Expr; - class IdentifierInfo; - class LabelDecl; - class ODRHash; - class ParmVarDecl; - class PrinterHelper; - struct PrintingPolicy; - class QualType; - class RecordDecl; - class SourceManager; - class StringLiteral; - class SwitchStmt; - class Token; - class VarDecl; + +class ASTContext; +class Attr; +class CapturedDecl; +class Decl; +class Expr; +class LabelDecl; +class ODRHash; +class PrinterHelper; +struct PrintingPolicy; +class RecordDecl; +class SourceManager; +class StringLiteral; +class Token; +class VarDecl; //===----------------------------------------------------------------------===// // AST classes for statements. @@ -72,9 +78,13 @@ public: // Make vanilla 'new' and 'delete' illegal for Stmts. protected: + friend class ASTStmtReader; + friend class ASTStmtWriter; + void *operator new(size_t bytes) noexcept { llvm_unreachable("Stmts cannot be allocated with regular 'new'."); } + void operator delete(void *data) noexcept { llvm_unreachable("Stmts cannot be released with regular 'delete'."); } @@ -89,6 +99,7 @@ protected: class CompoundStmtBitfields { friend class CompoundStmt; + unsigned : NumStmtBits; unsigned NumStmts : 32 - NumStmtBits; @@ -96,34 +107,36 @@ protected: class IfStmtBitfields { friend class IfStmt; + unsigned : NumStmtBits; unsigned IsConstexpr : 1; }; class ExprBitfields { - friend class Expr; - friend class DeclRefExpr; // computeDependence - friend class InitListExpr; // ctor - friend class DesignatedInitExpr; // ctor - friend class BlockDeclRefExpr; // ctor friend class ASTStmtReader; // deserialization + friend class AtomicExpr; // ctor + friend class BlockDeclRefExpr; // ctor + friend class CallExpr; // ctor + friend class CXXConstructExpr; // ctor + friend class CXXDependentScopeMemberExpr; // ctor friend class CXXNewExpr; // ctor + friend class CXXUnresolvedConstructExpr; // ctor + friend class DeclRefExpr; // computeDependence friend class DependentScopeDeclRefExpr; // ctor - friend class CXXConstructExpr; // ctor - friend class CallExpr; // ctor - friend class OffsetOfExpr; // ctor - friend class ObjCMessageExpr; // ctor + friend class DesignatedInitExpr; // ctor + friend class Expr; + friend class InitListExpr; // ctor friend class ObjCArrayLiteral; // ctor friend class ObjCDictionaryLiteral; // ctor - friend class ShuffleVectorExpr; // ctor - friend class ParenListExpr; // ctor - friend class CXXUnresolvedConstructExpr; // ctor - friend class CXXDependentScopeMemberExpr; // ctor + friend class ObjCMessageExpr; // ctor + friend class OffsetOfExpr; // ctor + friend class OpaqueValueExpr; // ctor friend class OverloadExpr; // ctor + friend class ParenListExpr; // ctor friend class PseudoObjectExpr; // ctor - friend class AtomicExpr; // ctor - friend class OpaqueValueExpr; // ctor + friend class ShuffleVectorExpr; // ctor + unsigned : NumStmtBits; unsigned ValueKind : 2; @@ -137,6 +150,7 @@ protected: class CharacterLiteralBitfields { friend class CharacterLiteral; + unsigned : NumExprBits; unsigned Kind : 3; @@ -153,6 +167,7 @@ protected: class FloatingLiteralBitfields { friend class FloatingLiteral; + unsigned : NumExprBits; unsigned Semantics : 3; // Provides semantics for APFloat construction @@ -161,6 +176,7 @@ protected: class UnaryExprOrTypeTraitExprBitfields { friend class UnaryExprOrTypeTraitExpr; + unsigned : NumExprBits; unsigned Kind : 2; @@ -168,8 +184,9 @@ protected: }; class DeclRefExprBitfields { - friend class DeclRefExpr; friend class ASTStmtReader; // deserialization + friend class DeclRefExpr; + unsigned : NumExprBits; unsigned HasQualifier : 1; @@ -181,6 +198,7 @@ protected: class CastExprBitfields { friend class CastExpr; + unsigned : NumExprBits; unsigned Kind : 6; @@ -189,14 +207,15 @@ protected: class CallExprBitfields { friend class CallExpr; + unsigned : NumExprBits; unsigned NumPreArgs : 1; }; class ExprWithCleanupsBitfields { - friend class ExprWithCleanups; friend class ASTStmtReader; // deserialization + friend class ExprWithCleanups; unsigned : NumExprBits; @@ -207,8 +226,8 @@ protected: }; class PseudoObjectExprBitfields { - friend class PseudoObjectExpr; friend class ASTStmtReader; // deserialization + friend class PseudoObjectExpr; unsigned : NumExprBits; @@ -220,6 +239,7 @@ protected: class ObjCIndirectCopyRestoreExprBitfields { friend class ObjCIndirectCopyRestoreExpr; + unsigned : NumExprBits; unsigned ShouldCopy : 1; @@ -236,9 +256,9 @@ protected: }; class TypeTraitExprBitfields { - friend class TypeTraitExpr; friend class ASTStmtReader; friend class ASTStmtWriter; + friend class TypeTraitExpr; unsigned : NumExprBits; @@ -280,9 +300,6 @@ protected: CoawaitExprBitfields CoawaitBits; }; - friend class ASTStmtReader; - friend class ASTStmtWriter; - public: // Only allow allocation of Stmts using the allocator in ASTContext // or by doing a placement new. @@ -305,7 +322,7 @@ public: /// \brief A placeholder type used to construct an empty shell of a /// type, that will be filled in later (e.g., by some /// de-serialization). - struct EmptyShell { }; + struct EmptyShell {}; protected: /// Iterator for iterating over Stmt * arrays that contain only Expr * @@ -361,6 +378,7 @@ public: StmtClass getStmtClass() const { return static_cast<StmtClass>(StmtBits.sClass); } + const char *getStmtClassName() const; /// SourceLocation tokens are not useful in isolation - they are low level @@ -389,8 +407,8 @@ public: /// back to its original source language syntax. void dumpPretty(const ASTContext &Context) const; void printPretty(raw_ostream &OS, PrinterHelper *Helper, - const PrintingPolicy &Policy, - unsigned Indentation = 0) const; + const PrintingPolicy &Policy, unsigned Indentation = 0, + const ASTContext *Context = nullptr) const; /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only /// works on systems with GraphViz (Mac OS X) or dot+gv installed. @@ -406,6 +424,9 @@ public: /// \brief Skip no-op (attributed, compound) container stmts and skip captured /// stmt at the top, if \a IgnoreCaptured is true. Stmt *IgnoreContainers(bool IgnoreCaptured = false); + const Stmt *IgnoreContainers(bool IgnoreCaptured = false) const { + return const_cast<Stmt *>(this)->IgnoreContainers(IgnoreCaptured); + } const Stmt *stripLabelLikeStatements() const; Stmt *stripLabelLikeStatements() { @@ -416,11 +437,11 @@ public: /// Child Iterators: All subclasses must implement 'children' /// to permit easy iteration over the substatements/subexpessions of an /// AST node. This permits easy iteration over all nodes in the AST. - typedef StmtIterator child_iterator; - typedef ConstStmtIterator const_child_iterator; + using child_iterator = StmtIterator; + using const_child_iterator = ConstStmtIterator; - typedef llvm::iterator_range<child_iterator> child_range; - typedef llvm::iterator_range<const_child_iterator> const_child_range; + using child_range = llvm::iterator_range<child_iterator>; + using const_child_range = llvm::iterator_range<const_child_iterator>; child_range children(); const_child_range children() const { @@ -463,18 +484,16 @@ public: /// expressions. For example, CompoundStmt mixes statements, expressions /// and declarations (variables, types). Another example is ForStmt, where /// the first statement can be an expression or a declaration. -/// class DeclStmt : public Stmt { DeclGroupRef DG; SourceLocation StartLoc, EndLoc; public: - DeclStmt(DeclGroupRef dg, SourceLocation startLoc, - SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), - StartLoc(startLoc), EndLoc(endLoc) {} + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, SourceLocation endLoc) + : Stmt(DeclStmtClass), DG(dg), StartLoc(startLoc), EndLoc(endLoc) {} /// \brief Build an empty declaration statement. - explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } + explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) {} /// isSingleDecl - This method returns true if this DeclStmt refers /// to a single Decl. @@ -507,10 +526,10 @@ public: child_iterator(DG.end(), DG.end())); } - typedef DeclGroupRef::iterator decl_iterator; - typedef DeclGroupRef::const_iterator const_decl_iterator; - typedef llvm::iterator_range<decl_iterator> decl_range; - typedef llvm::iterator_range<const_decl_iterator> decl_const_range; + using decl_iterator = DeclGroupRef::iterator; + using const_decl_iterator = DeclGroupRef::const_iterator; + using decl_range = llvm::iterator_range<decl_iterator>; + using decl_const_range = llvm::iterator_range<const_decl_iterator>; decl_range decls() { return decl_range(decl_begin(), decl_end()); } decl_const_range decls() const { @@ -521,10 +540,12 @@ public: const_decl_iterator decl_begin() const { return DG.begin(); } const_decl_iterator decl_end() const { return DG.end(); } - typedef std::reverse_iterator<decl_iterator> reverse_decl_iterator; + using reverse_decl_iterator = std::reverse_iterator<decl_iterator>; + reverse_decl_iterator decl_rbegin() { return reverse_decl_iterator(decl_end()); } + reverse_decl_iterator decl_rend() { return reverse_decl_iterator(decl_begin()); } @@ -540,15 +561,18 @@ class NullStmt : public Stmt { /// #define CALL(x) /// CALL(0); /// @endcode - bool HasLeadingEmptyMacro; + bool HasLeadingEmptyMacro = false; + public: + friend class ASTStmtReader; + friend class ASTStmtWriter; + NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false) - : Stmt(NullStmtClass), SemiLoc(L), - HasLeadingEmptyMacro(hasLeadingEmptyMacro) {} + : Stmt(NullStmtClass), SemiLoc(L), + HasLeadingEmptyMacro(hasLeadingEmptyMacro) {} /// \brief Build an empty null statement. - explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty), - HasLeadingEmptyMacro(false) { } + explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) {} SourceLocation getSemiLoc() const { return SemiLoc; } void setSemiLoc(SourceLocation L) { SemiLoc = L; } @@ -565,32 +589,27 @@ public: child_range children() { return child_range(child_iterator(), child_iterator()); } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// CompoundStmt - This represents a group of statements like { stmt stmt }. -/// class CompoundStmt : public Stmt { - Stmt** Body; - SourceLocation LBraceLoc, RBraceLoc; - friend class ASTStmtReader; + Stmt** Body = nullptr; + SourceLocation LBraceLoc, RBraceLoc; + public: CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts, SourceLocation LB, SourceLocation RB); // \brief Build an empty compound statement with a location. explicit CompoundStmt(SourceLocation Loc) - : Stmt(CompoundStmtClass), Body(nullptr), LBraceLoc(Loc), RBraceLoc(Loc) { + : Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(Loc) { CompoundStmtBits.NumStmts = 0; } // \brief Build an empty compound statement. - explicit CompoundStmt(EmptyShell Empty) - : Stmt(CompoundStmtClass, Empty), Body(nullptr) { + explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) { CompoundStmtBits.NumStmts = 0; } @@ -599,8 +618,8 @@ public: bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } unsigned size() const { return CompoundStmtBits.NumStmts; } - typedef Stmt** body_iterator; - typedef llvm::iterator_range<body_iterator> body_range; + using body_iterator = Stmt **; + using body_range = llvm::iterator_range<body_iterator>; body_range body() { return body_range(body_begin(), body_end()); } body_iterator body_begin() { return Body; } @@ -613,31 +632,36 @@ public: Body[size()-1] = S; } - typedef Stmt* const * const_body_iterator; - typedef llvm::iterator_range<const_body_iterator> body_const_range; + using const_body_iterator = Stmt* const *; + using body_const_range = llvm::iterator_range<const_body_iterator>; body_const_range body() const { return body_const_range(body_begin(), body_end()); } + const_body_iterator body_begin() const { return Body; } const_body_iterator body_end() const { return Body + size(); } + const Stmt *body_front() const { return !body_empty() ? Body[0] : nullptr; } + const Stmt *body_back() const { return !body_empty() ? Body[size() - 1] : nullptr; } - typedef std::reverse_iterator<body_iterator> reverse_body_iterator; + using reverse_body_iterator = std::reverse_iterator<body_iterator>; + reverse_body_iterator body_rbegin() { return reverse_body_iterator(body_end()); } + reverse_body_iterator body_rend() { return reverse_body_iterator(body_begin()); } - typedef std::reverse_iterator<const_body_iterator> - const_reverse_body_iterator; + using const_reverse_body_iterator = + std::reverse_iterator<const_body_iterator>; const_reverse_body_iterator body_rbegin() const { return const_reverse_body_iterator(body_end()); @@ -673,16 +697,14 @@ class SwitchCase : public Stmt { protected: // A pointer to the following CaseStmt or DefaultStmt class, // used by SwitchStmt. - SwitchCase *NextSwitchCase; + SwitchCase *NextSwitchCase = nullptr; SourceLocation KeywordLoc; SourceLocation ColonLoc; SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc) - : Stmt(SC), NextSwitchCase(nullptr), KeywordLoc(KWLoc), ColonLoc(ColonLoc) { - } + : Stmt(SC), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {} - SwitchCase(StmtClass SC, EmptyShell) - : Stmt(SC), NextSwitchCase(nullptr) {} + SwitchCase(StmtClass SC, EmptyShell) : Stmt(SC) {} public: const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } @@ -715,6 +737,7 @@ class CaseStmt : public SwitchCase { enum { LHS, RHS, SUBSTMT, END_EXPR }; Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for // GNU "case 1 ... 4" extension + public: CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, SourceLocation ellipsisLoc, SourceLocation colonLoc) @@ -726,7 +749,7 @@ public: } /// \brief Build an empty switch case statement. - explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) { } + explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) {} SourceLocation getCaseLoc() const { return KeywordLoc; } void setCaseLoc(SourceLocation L) { KeywordLoc = L; } @@ -742,9 +765,11 @@ public: const Expr *getLHS() const { return reinterpret_cast<const Expr*>(SubExprs[LHS]); } + const Expr *getRHS() const { return reinterpret_cast<const Expr*>(SubExprs[RHS]); } + const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } @@ -752,6 +777,7 @@ public: void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { // Handle deeply nested case statements with iteration instead of recursion. const CaseStmt *CS = this; @@ -773,13 +799,14 @@ public: class DefaultStmt : public SwitchCase { Stmt* SubStmt; + public: DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {} /// \brief Build an empty default statement. explicit DefaultStmt(EmptyShell Empty) - : SwitchCase(DefaultStmtClass, Empty) { } + : SwitchCase(DefaultStmtClass, Empty) {} Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } @@ -809,7 +836,6 @@ inline SourceLocation SwitchCase::getLocEnd() const { /// LabelStmt - Represents a label, which has a substatement. For example: /// foo: return; -/// class LabelStmt : public Stmt { SourceLocation IdentLoc; LabelDecl *TheDecl; @@ -824,7 +850,7 @@ public: } // \brief Build an empty label statement. - explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) {} SourceLocation getIdentLoc() const { return IdentLoc; } LabelDecl *getDecl() const { return TheDecl; } @@ -845,19 +871,17 @@ public: } }; - /// \brief Represents an attribute applied to a statement. /// /// Represents an attribute applied to a statement. For example: /// [[omp::for(...)]] for (...) { ... } -/// class AttributedStmt : public Stmt { + friend class ASTStmtReader; + Stmt *SubStmt; SourceLocation AttrLoc; unsigned NumAttrs; - friend class ASTStmtReader; - AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt) : Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc), NumAttrs(Attrs.size()) { @@ -879,6 +903,7 @@ class AttributedStmt : public Stmt { public: static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt); + // \brief Build an empty attributed statement. static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs); @@ -886,6 +911,7 @@ public: ArrayRef<const Attr*> getAttrs() const { return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs); } + Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } @@ -899,9 +925,7 @@ public: } }; - /// IfStmt - This represents an if/then/else. -/// class IfStmt : public Stmt { enum { INIT, VAR, COND, THEN, ELSE, END_EXPR }; Stmt* SubExprs[END_EXPR]; @@ -916,7 +940,7 @@ public: Stmt *elsev = nullptr); /// \brief Build an empty if/then/else statement - explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {} /// \brief Retrieve the variable declared in this "if" statement, if any. /// @@ -960,6 +984,7 @@ public: bool isObjCAvailabilityCheck() const; SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { if (SubExprs[ELSE]) return SubExprs[ELSE]->getLocEnd(); @@ -979,11 +1004,11 @@ public: }; /// SwitchStmt - This represents a 'switch' stmt. -/// class SwitchStmt : public Stmt { SourceLocation SwitchLoc; enum { INIT, VAR, COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; + // 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 @@ -994,7 +1019,7 @@ public: SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond); /// \brief Build a empty switch statement. - explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) {} /// \brief Retrieve the variable declared in this "switch" statement, if any. /// @@ -1037,6 +1062,7 @@ public: SubExprs[BODY] = S; SwitchLoc = SL; } + void addSwitchCase(SwitchCase *SC) { assert(!SC->getNextSwitchCase() && "case/default already added to a switch"); @@ -1053,6 +1079,7 @@ public: bool isAllEnumCasesCovered() const { return FirstCase.getInt(); } SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExprs[BODY] ? SubExprs[BODY]->getLocEnd() : SubExprs[COND]->getLocEnd(); } @@ -1067,19 +1094,18 @@ public: } }; - /// WhileStmt - This represents a 'while' stmt. -/// class WhileStmt : public Stmt { SourceLocation WhileLoc; enum { VAR, COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; + public: WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL); /// \brief Build an empty while statement. - explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) {} /// \brief Retrieve the variable declared in this "while" statement, if any. /// @@ -1109,6 +1135,7 @@ public: void setWhileLoc(SourceLocation L) { WhileLoc = L; } SourceLocation getLocStart() const LLVM_READONLY { return WhileLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExprs[BODY]->getLocEnd(); } @@ -1124,7 +1151,6 @@ public: }; /// DoStmt - This represents a 'do/while' stmt. -/// class DoStmt : public Stmt { SourceLocation DoLoc; enum { BODY, COND, END_EXPR }; @@ -1141,7 +1167,7 @@ public: } /// \brief Build an empty do-while statement. - explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } + 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]);} @@ -1171,11 +1197,9 @@ public: } }; - /// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of /// 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 }; @@ -1188,7 +1212,7 @@ public: SourceLocation RP); /// \brief Build an empty for statement. - explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } + explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) {} Stmt *getInit() { return SubExprs[INIT]; } @@ -1231,6 +1255,7 @@ public: void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return SubExprs[BODY]->getLocEnd(); } @@ -1246,17 +1271,17 @@ 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), GotoLoc(GL), LabelLoc(LL) {} /// \brief Build an empty goto statement. - explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) {} LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *D) { Label = D; } @@ -1280,11 +1305,11 @@ 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) @@ -1293,7 +1318,7 @@ public: /// \brief Build an empty indirect goto statement. explicit IndirectGotoStmt(EmptyShell Empty) - : Stmt(IndirectGotoStmtClass, Empty) { } + : Stmt(IndirectGotoStmtClass, Empty) {} void setGotoLoc(SourceLocation L) { GotoLoc = L; } SourceLocation getGotoLoc() const { return GotoLoc; } @@ -1322,16 +1347,15 @@ public: 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) {} /// \brief Build an empty continue statement. - explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } + explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) {} SourceLocation getContinueLoc() const { return ContinueLoc; } void setContinueLoc(SourceLocation L) { ContinueLoc = L; } @@ -1350,7 +1374,6 @@ public: }; /// BreakStmt - This represents a break. -/// class BreakStmt : public Stmt { SourceLocation BreakLoc; @@ -1361,7 +1384,7 @@ public: } /// \brief Build an empty break statement. - explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } + explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) {} SourceLocation getBreakLoc() const { return BreakLoc; } void setBreakLoc(SourceLocation L) { BreakLoc = L; } @@ -1379,7 +1402,6 @@ public: } }; - /// ReturnStmt - This represents a return, optionally of an expression: /// return; /// return 4; @@ -1388,7 +1410,6 @@ 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; Stmt *RetExpr; @@ -1402,7 +1423,7 @@ public: NRVOCandidate(NRVOCandidate) {} /// \brief Build an empty return expression. - explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } + explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) {} const Expr *getRetValue() const; Expr *getRetValue(); @@ -1420,6 +1441,7 @@ public: void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } SourceLocation getLocStart() const LLVM_READONLY { return RetLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RetExpr ? RetExpr->getLocEnd() : RetLoc; } @@ -1436,10 +1458,12 @@ public: }; /// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt. -/// class AsmStmt : public Stmt { protected: + friend class ASTStmtReader; + SourceLocation AsmLoc; + /// \brief True if the assembly statement does not have any input or output /// operands. bool IsSimple; @@ -1452,19 +1476,17 @@ protected: unsigned NumInputs; unsigned NumClobbers; - Stmt **Exprs; + Stmt **Exprs = nullptr; AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile, - unsigned numoutputs, unsigned numinputs, unsigned numclobbers) : - Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile), - NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { } - - friend class ASTStmtReader; + unsigned numoutputs, unsigned numinputs, unsigned numclobbers) + : Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile), + NumOutputs(numoutputs), NumInputs(numinputs), + NumClobbers(numclobbers) {} public: /// \brief Build an empty inline-assembly statement. - explicit AsmStmt(StmtClass SC, EmptyShell Empty) : - Stmt(SC, Empty), Exprs(nullptr) { } + explicit AsmStmt(StmtClass SC, EmptyShell Empty) : Stmt(SC, Empty) {} SourceLocation getAsmLoc() const { return AsmLoc; } void setAsmLoc(SourceLocation L) { AsmLoc = L; } @@ -1527,10 +1549,10 @@ public: // Input expr iterators. - typedef ExprIterator inputs_iterator; - typedef ConstExprIterator const_inputs_iterator; - typedef llvm::iterator_range<inputs_iterator> inputs_range; - typedef llvm::iterator_range<const_inputs_iterator> inputs_const_range; + using inputs_iterator = ExprIterator; + using const_inputs_iterator = ConstExprIterator; + using inputs_range = llvm::iterator_range<inputs_iterator>; + using inputs_const_range = llvm::iterator_range<const_inputs_iterator>; inputs_iterator begin_inputs() { return &Exprs[0] + NumOutputs; @@ -1556,17 +1578,19 @@ public: // Output expr iterators. - typedef ExprIterator outputs_iterator; - typedef ConstExprIterator const_outputs_iterator; - typedef llvm::iterator_range<outputs_iterator> outputs_range; - typedef llvm::iterator_range<const_outputs_iterator> outputs_const_range; + using outputs_iterator = ExprIterator; + using const_outputs_iterator = ConstExprIterator; + using outputs_range = llvm::iterator_range<outputs_iterator>; + using outputs_const_range = llvm::iterator_range<const_outputs_iterator>; outputs_iterator begin_outputs() { return &Exprs[0]; } + outputs_iterator end_outputs() { return &Exprs[0] + NumOutputs; } + outputs_range outputs() { return outputs_range(begin_outputs(), end_outputs()); } @@ -1574,9 +1598,11 @@ public: const_outputs_iterator begin_outputs() const { return &Exprs[0]; } + const_outputs_iterator end_outputs() const { return &Exprs[0] + NumOutputs; } + outputs_const_range outputs() const { return outputs_const_range(begin_outputs(), end_outputs()); } @@ -1587,17 +1613,16 @@ public: }; /// This represents a GCC inline-assembly statement extension. -/// class GCCAsmStmt : public AsmStmt { + friend class ASTStmtReader; + SourceLocation RParenLoc; StringLiteral *AsmStr; // FIXME: If we wanted to, we could allocate all of these in one big array. - StringLiteral **Constraints; - StringLiteral **Clobbers; - IdentifierInfo **Names; - - friend class ASTStmtReader; + StringLiteral **Constraints = nullptr; + StringLiteral **Clobbers = nullptr; + IdentifierInfo **Names = nullptr; public: GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple, @@ -1607,8 +1632,7 @@ public: StringLiteral **clobbers, SourceLocation rparenloc); /// \brief Build an empty inline-assembly statement. - explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty), - Constraints(nullptr), Clobbers(nullptr), Names(nullptr) { } + explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {} SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } @@ -1628,6 +1652,7 @@ public: String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". Operand // Operand reference, with optional modifier %c4. }; + private: Kind MyKind; std::string Str; @@ -1635,13 +1660,13 @@ public: // Source range for operand references. CharSourceRange Range; + public: AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation Begin, SourceLocation End) - : MyKind(Operand), Str(S), OperandNo(OpNo), - Range(CharSourceRange::getCharRange(Begin, End)) { - } + : MyKind(Operand), Str(S), OperandNo(OpNo), + Range(CharSourceRange::getCharRange(Begin, End)) {} bool isString() const { return MyKind == String; } bool isOperand() const { return MyKind == Operand; } @@ -1742,8 +1767,8 @@ private: unsigned NumInputs, StringLiteral **Clobbers, unsigned NumClobbers); -public: +public: //===--- Other ---===// /// getNamedOperand - Given a symbolic operand reference like %[foo], @@ -1752,6 +1777,7 @@ public: int getNamedOperand(StringRef SymbolicName) const; StringRef getClobber(unsigned i) const; + StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; } const StringLiteral *getClobberStringLiteral(unsigned i) const { return Clobbers[i]; @@ -1766,18 +1792,17 @@ public: }; /// This represents a Microsoft inline-assembly statement extension. -/// class MSAsmStmt : public AsmStmt { + friend class ASTStmtReader; + SourceLocation LBraceLoc, EndLoc; StringRef AsmStr; - unsigned NumAsmToks; - - Token *AsmToks; - StringRef *Constraints; - StringRef *Clobbers; + unsigned NumAsmToks = 0; - friend class ASTStmtReader; + Token *AsmToks = nullptr; + StringRef *Constraints = nullptr; + StringRef *Clobbers = nullptr; public: MSAsmStmt(const ASTContext &C, SourceLocation asmloc, @@ -1788,8 +1813,7 @@ public: ArrayRef<StringRef> clobbers, SourceLocation endloc); /// \brief Build an empty MS-style inline-assembly statement. - explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty), - NumAsmToks(0), AsmToks(nullptr), Constraints(nullptr), Clobbers(nullptr) { } + explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty) {} SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation L) { LBraceLoc = L; } @@ -1839,9 +1863,11 @@ public: ArrayRef<StringRef> getAllConstraints() const { return llvm::makeArrayRef(Constraints, NumInputs + NumOutputs); } + ArrayRef<StringRef> getClobbers() const { return llvm::makeArrayRef(Clobbers, NumClobbers); } + ArrayRef<Expr*> getAllExprs() const { return llvm::makeArrayRef(reinterpret_cast<Expr**>(Exprs), NumInputs + NumOutputs); @@ -1853,8 +1879,8 @@ private: void initialize(const ASTContext &C, StringRef AsmString, ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints, ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers); -public: +public: SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } @@ -1868,18 +1894,16 @@ public: }; class SEHExceptStmt : public Stmt { + friend class ASTReader; + friend class ASTStmtReader; + SourceLocation Loc; - Stmt *Children[2]; + Stmt *Children[2]; enum { FILTER_EXPR, BLOCK }; - SEHExceptStmt(SourceLocation Loc, - Expr *FilterExpr, - Stmt *Block); - - friend class ASTReader; - friend class ASTStmtReader; - explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { } + SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); + explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) {} public: static SEHExceptStmt* Create(const ASTContext &C, @@ -1908,19 +1932,17 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == SEHExceptStmtClass; } - }; class SEHFinallyStmt : public Stmt { - SourceLocation Loc; - Stmt *Block; - - SEHFinallyStmt(SourceLocation Loc, - Stmt *Block); - friend class ASTReader; friend class ASTStmtReader; - explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { } + + SourceLocation Loc; + Stmt *Block; + + SEHFinallyStmt(SourceLocation Loc, Stmt *Block); + explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) {} public: static SEHFinallyStmt* Create(const ASTContext &C, @@ -1942,13 +1964,15 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == SEHFinallyStmtClass; } - }; class SEHTryStmt : public Stmt { - bool IsCXXTry; + friend class ASTReader; + friend class ASTStmtReader; + + bool IsCXXTry; SourceLocation TryLoc; - Stmt *Children[2]; + Stmt *Children[2]; enum { TRY = 0, HANDLER = 1 }; @@ -1957,9 +1981,7 @@ class SEHTryStmt : public Stmt { Stmt *TryBlock, Stmt *Handler); - friend class ASTReader; - friend class ASTStmtReader; - explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } + explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) {} public: static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry, @@ -1994,15 +2016,15 @@ public: }; /// Represents a __leave statement. -/// class SEHLeaveStmt : public Stmt { SourceLocation LeaveLoc; + public: explicit SEHLeaveStmt(SourceLocation LL) : Stmt(SEHLeaveStmtClass), LeaveLoc(LL) {} /// \brief Build an empty __leave statement. - explicit SEHLeaveStmt(EmptyShell Empty) : Stmt(SEHLeaveStmtClass, Empty) { } + explicit SEHLeaveStmt(EmptyShell Empty) : Stmt(SEHLeaveStmtClass, Empty) {} SourceLocation getLeaveLoc() const { return LeaveLoc; } void setLeaveLoc(SourceLocation L) { LeaveLoc = L; } @@ -2047,6 +2069,8 @@ public: SourceLocation Loc; public: + friend class ASTStmtReader; + /// \brief Create a new capture. /// /// \param Loc The source location associated with this capture. @@ -2054,7 +2078,6 @@ public: /// \param Kind The kind of capture (this, ByRef, ...). /// /// \param Var The variable being captured, or null if capturing this. - /// Capture(SourceLocation Loc, VariableCaptureKind Kind, VarDecl *Var = nullptr); @@ -2086,8 +2109,6 @@ public: /// /// This operation is only valid if this capture captures a variable. VarDecl *getCapturedVar() const; - - friend class ASTStmtReader; }; private: @@ -2099,7 +2120,7 @@ private: llvm::PointerIntPair<CapturedDecl *, 1, CapturedRegionKind> CapDeclAndKind; /// \brief The record for captured variables, a RecordDecl or CXXRecordDecl. - RecordDecl *TheRecordDecl; + RecordDecl *TheRecordDecl = nullptr; /// \brief Construct a captured statement. CapturedStmt(Stmt *S, CapturedRegionKind Kind, ArrayRef<Capture> Captures, @@ -2119,6 +2140,8 @@ private: void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; } public: + friend class ASTStmtReader; + static CapturedStmt *Create(const ASTContext &Context, Stmt *S, CapturedRegionKind Kind, ArrayRef<Capture> Captures, @@ -2158,10 +2181,10 @@ public: bool capturesVariable(const VarDecl *Var) const; /// \brief An iterator that walks over the captures. - typedef Capture *capture_iterator; - typedef const Capture *const_capture_iterator; - typedef llvm::iterator_range<capture_iterator> capture_range; - typedef llvm::iterator_range<const_capture_iterator> capture_const_range; + using capture_iterator = Capture *; + using const_capture_iterator = const Capture *; + using capture_range = llvm::iterator_range<capture_iterator>; + using capture_const_range = llvm::iterator_range<const_capture_iterator>; capture_range captures() { return capture_range(capture_begin(), capture_end()); @@ -2184,14 +2207,14 @@ public: unsigned capture_size() const { return NumCaptures; } /// \brief Iterator that walks over the capture initialization arguments. - typedef Expr **capture_init_iterator; - typedef llvm::iterator_range<capture_init_iterator> capture_init_range; + using capture_init_iterator = Expr **; + using capture_init_range = llvm::iterator_range<capture_init_iterator>; /// \brief Const iterator that walks over the capture initialization /// arguments. - typedef Expr *const *const_capture_init_iterator; - typedef llvm::iterator_range<const_capture_init_iterator> - const_capture_init_range; + using const_capture_init_iterator = Expr *const *; + using const_capture_init_range = + llvm::iterator_range<const_capture_init_iterator>; capture_init_range capture_inits() { return capture_init_range(capture_init_begin(), capture_init_end()); @@ -2223,9 +2246,11 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return getCapturedStmt()->getLocStart(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getCapturedStmt()->getLocEnd(); } + SourceRange getSourceRange() const LLVM_READONLY { return getCapturedStmt()->getSourceRange(); } @@ -2235,10 +2260,8 @@ public: } child_range children(); - - friend class ASTStmtReader; }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_STMT_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtDataCollectors.td b/contrib/llvm/tools/clang/include/clang/AST/StmtDataCollectors.td new file mode 100644 index 0000000000000..bf5f8c21707f9 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtDataCollectors.td @@ -0,0 +1,242 @@ +class Stmt { + code Code = [{ + addData(S->getStmtClass()); + // This ensures that non-macro-generated code isn't identical to + // macro-generated code. + addData(data_collection::getMacroStack(S->getLocStart(), Context)); + addData(data_collection::getMacroStack(S->getLocEnd(), Context)); + }]; +} + +class Expr { + code Code = [{ + addData(S->getType()); + }]; +} + +//--- Builtin functionality ----------------------------------------------// +class ArrayTypeTraitExpr { + code Code = [{ + addData(S->getTrait()); + }]; +} +class ExpressionTraitExpr { + code Code = [{ + addData(S->getTrait()); + }]; +} +class PredefinedExpr { + code Code = [{ + addData(S->getIdentType()); + }]; +} +class TypeTraitExpr { + code Code = [{ + addData(S->getTrait()); + for (unsigned i = 0; i < S->getNumArgs(); ++i) + addData(S->getArg(i)->getType()); + }]; +} + +//--- Calls --------------------------------------------------------------// +class CallExpr { + code Code = [{ + // Function pointers don't have a callee and we just skip hashing it. + if (const FunctionDecl *D = S->getDirectCallee()) { + // If the function is a template specialization, we also need to handle + // the template arguments as they are not included in the qualified name. + if (auto Args = D->getTemplateSpecializationArgs()) { + std::string ArgString; + + // Print all template arguments into ArgString + llvm::raw_string_ostream OS(ArgString); + for (unsigned i = 0; i < Args->size(); ++i) { + Args->get(i).print(Context.getLangOpts(), OS); + // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. + OS << '\n'; + } + OS.flush(); + + addData(ArgString); + } + addData(D->getQualifiedNameAsString()); + } + }]; +} + +//--- Value references ---------------------------------------------------// +class DeclRefExpr { + code Code = [{ + addData(S->getDecl()->getQualifiedNameAsString()); + }]; +} +class MemberExpr { + code Code = [{ + addData(S->getMemberDecl()->getName()); + }]; +} + +//--- Literals -----------------------------------------------------------// +class IntegerLiteral { + code Code = [{ + addData(llvm::hash_value(S->getValue())); + }]; +} +class FloatingLiteral { + code Code = [{ + addData(llvm::hash_value(S->getValue())); + }]; +} +class StringLiteral { + code Code = [{ + addData(S->getString()); +}]; +} +class CXXBoolLiteralExpr { + code Code = [{ + addData(S->getValue()); + }]; +} +class CharacterLiteral { + code Code = [{ + addData(S->getValue()); + }]; +} + +//--- Exceptions ---------------------------------------------------------// +class CXXCatchStmt { + code Code = [{ + addData(S->getCaughtType()); + }]; +} + +//--- C++ OOP Stmts ------------------------------------------------------// +class CXXDeleteExpr { + code Code = [{ + addData(S->isArrayFormAsWritten()); addData(S->isGlobalDelete()); + }]; +} + +//--- Casts --------------------------------------------------------------// +class ObjCBridgedCastExpr { + code Code = [{ + addData(S->getBridgeKind()); + }]; +} + +//--- Miscellaneous Exprs ------------------------------------------------// +class BinaryOperator { + code Code = [{ + addData(S->getOpcode()); + }]; +} +class UnaryOperator { + code Code = [{ + addData(S->getOpcode()); + }]; +} + +//--- Control flow -------------------------------------------------------// +class GotoStmt { + code Code = [{ + addData(S->getLabel()->getName()); + }]; +} +class IndirectGotoStmt { + code Code = [{ + if (S->getConstantTarget()) + addData(S->getConstantTarget()->getName()); + }]; +} +class LabelStmt { + code Code = [{ + addData(S->getDecl()->getName()); + }]; +} +class MSDependentExistsStmt { + code Code = [{ + addData(S->isIfExists()); + }]; +} +class AddrLabelExpr { + code Code = [{ + addData(S->getLabel()->getName()); + }]; +} + +//--- Objective-C --------------------------------------------------------// +class ObjCIndirectCopyRestoreExpr { + code Code = [{ + addData(S->shouldCopy()); + }]; +} +class ObjCPropertyRefExpr { + code Code = [{ + addData(S->isSuperReceiver()); addData(S->isImplicitProperty()); + }]; +} +class ObjCAtCatchStmt { + code Code = [{ + addData(S->hasEllipsis()); + }]; +} + +//--- Miscellaneous Stmts ------------------------------------------------// +class CXXFoldExpr { + code Code = [{ + addData(S->isRightFold()); addData(S->getOperator()); + }]; +} +class GenericSelectionExpr { + code Code = [{ + for (unsigned i = 0; i < S->getNumAssocs(); ++i) { + addData(S->getAssocType(i)); + } + }]; +} +class LambdaExpr { + code Code = [{ + for (const LambdaCapture &C : S->captures()) { + addData(C.isPackExpansion()); + addData(C.getCaptureKind()); + if (C.capturesVariable()) + addData(C.getCapturedVar()->getType()); + } + addData(S->isGenericLambda()); + addData(S->isMutable()); + }]; +} +class DeclStmt { + code Code = [{ + auto numDecls = std::distance(S->decl_begin(), S->decl_end()); + addData(static_cast<unsigned>(numDecls)); + for (const Decl *D : S->decls()) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + addData(VD->getType()); + } + } + }]; +} +class AsmStmt { + code Code = [{ + addData(S->isSimple()); + addData(S->isVolatile()); + addData(S->generateAsmString(Context)); + for (unsigned i = 0; i < S->getNumInputs(); ++i) { + addData(S->getInputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumOutputs(); ++i) { + addData(S->getOutputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumClobbers(); ++i) { + addData(S->getClobber(i)); + } + }]; +} +class AttributedStmt { + code Code = [{ + for (const Attr *A : S->getAttrs()) { + addData(std::string(A->getSpelling())); + } + }]; +} diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h b/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h index 92eb64430f73e..02c77b242c7c8 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtGraphTraits.h @@ -1,4 +1,4 @@ -//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- C++ -*-===// +//===- StmtGraphTraits.h - Graph Traits for the class Stmt ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -21,13 +21,10 @@ namespace llvm { -//template <typename T> struct GraphTraits; - - -template <> struct GraphTraits<clang::Stmt*> { - typedef clang::Stmt * NodeRef; - typedef clang::Stmt::child_iterator ChildIteratorType; - typedef llvm::df_iterator<clang::Stmt*> nodes_iterator; +template <> struct GraphTraits<clang::Stmt *> { + using NodeRef = clang::Stmt *; + using ChildIteratorType = clang::Stmt::child_iterator; + using nodes_iterator = llvm::df_iterator<clang::Stmt *>; static NodeRef getEntryNode(clang::Stmt *S) { return S; } @@ -50,11 +47,10 @@ template <> struct GraphTraits<clang::Stmt*> { } }; - -template <> struct GraphTraits<const clang::Stmt*> { - typedef const clang::Stmt * NodeRef; - typedef clang::Stmt::const_child_iterator ChildIteratorType; - typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator; +template <> struct GraphTraits<const clang::Stmt *> { + using NodeRef = const clang::Stmt *; + using ChildIteratorType = clang::Stmt::const_child_iterator; + using nodes_iterator = llvm::df_iterator<const clang::Stmt *>; static NodeRef getEntryNode(const clang::Stmt *S) { return S; } @@ -77,7 +73,6 @@ template <> struct GraphTraits<const clang::Stmt*> { } }; +} // namespace llvm -} // end namespace llvm - -#endif +#endif // LLVM_CLANG_AST_STMTGRAPHTRAITS_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h index 5d3bce8d83bae..33aab08bbb713 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h @@ -1,4 +1,4 @@ -//===--- StmtIterator.h - Iterators for Statements --------------*- C++ -*-===// +//===- StmtIterator.h - Iterators for Statements ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,31 +14,38 @@ #ifndef LLVM_CLANG_AST_STMTITERATOR_H #define LLVM_CLANG_AST_STMTITERATOR_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" #include <cassert> #include <cstddef> +#include <cstdint> #include <iterator> -#include <utility> namespace clang { -class Stmt; class Decl; +class Stmt; class VariableArrayType; class StmtIteratorBase { protected: - enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2, - Flags = 0x3 }; + enum { + StmtMode = 0x0, + SizeOfTypeVAMode = 0x1, + DeclGroupMode = 0x2, + Flags = 0x3 + }; union { Stmt **stmt; Decl **DGI; }; - uintptr_t RawVAPtr; + uintptr_t RawVAPtr = 0; Decl **DGE; + StmtIteratorBase(Stmt **s) : stmt(s) {} + StmtIteratorBase(const VariableArrayType *t); + StmtIteratorBase(Decl **dgi, Decl **dge); + StmtIteratorBase() : stmt(nullptr) {} + bool inDeclGroup() const { return (RawVAPtr & Flags) == DeclGroupMode; } @@ -56,7 +63,7 @@ protected: } void setVAPtr(const VariableArrayType *P) { - assert (inDeclGroup() || inSizeOfTypeVA()); + assert(inDeclGroup() || inSizeOfTypeVA()); RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); } @@ -65,14 +72,8 @@ protected: void NextVA(); Stmt*& GetDeclExpr() const; - - StmtIteratorBase(Stmt **s) : stmt(s), RawVAPtr(0) {} - StmtIteratorBase(const VariableArrayType *t); - StmtIteratorBase(Decl **dgi, Decl **dge); - StmtIteratorBase() : stmt(nullptr), RawVAPtr(0) {} }; - template <typename DERIVED, typename REFERENCE> class StmtIteratorImpl : public StmtIteratorBase, public std::iterator<std::forward_iterator_tag, @@ -80,8 +81,9 @@ class StmtIteratorImpl : public StmtIteratorBase, REFERENCE, REFERENCE> { protected: StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {} + public: - StmtIteratorImpl() {} + StmtIteratorImpl() = default; StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {} StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {} StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {} @@ -120,16 +122,13 @@ public: struct ConstStmtIterator; -struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { - explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} - - StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {} - +struct StmtIterator : public StmtIteratorImpl<StmtIterator, Stmt*&> { + explicit StmtIterator() = default; + StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator, Stmt*&>(S) {} StmtIterator(Decl** dgi, Decl** dge) - : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} - + : StmtIteratorImpl<StmtIterator, Stmt*&>(dgi, dge) {} StmtIterator(const VariableArrayType *t) - : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} + : StmtIteratorImpl<StmtIterator, Stmt*&>(t) {} private: StmtIterator(const StmtIteratorBase &RHS) @@ -141,11 +140,9 @@ private: struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, const Stmt*> { - explicit ConstStmtIterator() : - StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {} - - ConstStmtIterator(const StmtIterator& RHS) : - StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} + explicit ConstStmtIterator() = default; + ConstStmtIterator(const StmtIterator& RHS) + : StmtIteratorImpl<ConstStmtIterator, const Stmt*>(RHS) {} ConstStmtIterator(Stmt * const *S) : StmtIteratorImpl<ConstStmtIterator, const Stmt *>( @@ -155,6 +152,7 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, inline StmtIterator cast_away_const(const ConstStmtIterator &RHS) { return RHS; } -} // end namespace clang -#endif +} // namespace clang + +#endif // LLVM_CLANG_AST_STMTITERATOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h index 09dd87fdc8bc0..66fb037fc33cb 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h @@ -899,7 +899,9 @@ public: } const Stmt *getBody() const { // This relies on the loop form is already checked by Sema. - Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); + const Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); + while(const auto *CS = dyn_cast<CapturedStmt>(Body)) + Body = CS->getCapturedStmt(); Body = cast<ForStmt>(Body)->getBody(); for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { Body = Body->IgnoreContainers(); @@ -955,8 +957,15 @@ public: T->getStmtClass() == OMPTargetSimdDirectiveClass || T->getStmtClass() == OMPTeamsDistributeDirectiveClass || T->getStmtClass() == OMPTeamsDistributeSimdDirectiveClass || - T->getStmtClass() == OMPTeamsDistributeParallelForSimdDirectiveClass || - T->getStmtClass() == OMPTeamsDistributeParallelForDirectiveClass; + T->getStmtClass() == + OMPTeamsDistributeParallelForSimdDirectiveClass || + T->getStmtClass() == OMPTeamsDistributeParallelForDirectiveClass || + T->getStmtClass() == + OMPTargetTeamsDistributeParallelForDirectiveClass || + T->getStmtClass() == + OMPTargetTeamsDistributeParallelForSimdDirectiveClass || + T->getStmtClass() == OMPTargetTeamsDistributeDirectiveClass || + T->getStmtClass() == OMPTargetTeamsDistributeSimdDirectiveClass; } }; @@ -1912,7 +1921,7 @@ class OMPTaskgroupDirective : public OMPExecutableDirective { OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned NumClauses) : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, - StartLoc, EndLoc, NumClauses, 1) {} + StartLoc, EndLoc, NumClauses, 2) {} /// Build an empty directive. /// \param NumClauses Number of clauses. @@ -1920,7 +1929,12 @@ class OMPTaskgroupDirective : public OMPExecutableDirective { explicit OMPTaskgroupDirective(unsigned NumClauses) : OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup, SourceLocation(), SourceLocation(), NumClauses, - 1) {} + 2) {} + + /// Sets the task_reduction return variable. + void setReductionRef(Expr *RR) { + *std::next(child_begin(), 1) = RR; + } public: /// Creates directive. @@ -1930,10 +1944,12 @@ public: /// \param EndLoc Ending Location of the directive. /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. + /// \param ReductionRef Reference to the task_reduction return variable. /// static OMPTaskgroupDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + Expr *ReductionRef); /// Creates an empty directive. /// @@ -1943,6 +1959,15 @@ public: static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, EmptyShell); + + /// Returns reference to the task_reduction return variable. + const Expr *getReductionRef() const { + return static_cast<const Expr *>(*std::next(child_begin(), 1)); + } + Expr *getReductionRef() { + return static_cast<Expr *>(*std::next(child_begin(), 1)); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTaskgroupDirectiveClass; } @@ -2330,7 +2355,7 @@ class OMPTargetEnterDataDirective : public OMPExecutableDirective { unsigned NumClauses) : OMPExecutableDirective(this, OMPTargetEnterDataDirectiveClass, OMPD_target_enter_data, StartLoc, EndLoc, - NumClauses, /*NumChildren=*/0) {} + NumClauses, /*NumChildren=*/1) {} /// \brief Build an empty directive. /// @@ -2340,7 +2365,7 @@ class OMPTargetEnterDataDirective : public OMPExecutableDirective { : OMPExecutableDirective(this, OMPTargetEnterDataDirectiveClass, OMPD_target_enter_data, SourceLocation(), SourceLocation(), NumClauses, - /*NumChildren=*/0) {} + /*NumChildren=*/1) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -2349,11 +2374,11 @@ public: /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - static OMPTargetEnterDataDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses); + static OMPTargetEnterDataDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); /// \brief Creates an empty directive with the place for \a N clauses. /// @@ -2389,7 +2414,7 @@ class OMPTargetExitDataDirective : public OMPExecutableDirective { unsigned NumClauses) : OMPExecutableDirective(this, OMPTargetExitDataDirectiveClass, OMPD_target_exit_data, StartLoc, EndLoc, - NumClauses, /*NumChildren=*/0) {} + NumClauses, /*NumChildren=*/1) {} /// \brief Build an empty directive. /// @@ -2399,7 +2424,7 @@ class OMPTargetExitDataDirective : public OMPExecutableDirective { : OMPExecutableDirective(this, OMPTargetExitDataDirectiveClass, OMPD_target_exit_data, SourceLocation(), SourceLocation(), NumClauses, - /*NumChildren=*/0) {} + /*NumChildren=*/1) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -2408,11 +2433,11 @@ public: /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - static OMPTargetExitDataDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses); + static OMPTargetExitDataDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); /// \brief Creates an empty directive with the place for \a N clauses. /// @@ -2966,7 +2991,7 @@ class OMPTargetUpdateDirective : public OMPExecutableDirective { unsigned NumClauses) : OMPExecutableDirective(this, OMPTargetUpdateDirectiveClass, OMPD_target_update, StartLoc, EndLoc, NumClauses, - 0) {} + 1) {} /// \brief Build an empty directive. /// @@ -2975,7 +3000,7 @@ class OMPTargetUpdateDirective : public OMPExecutableDirective { explicit OMPTargetUpdateDirective(unsigned NumClauses) : OMPExecutableDirective(this, OMPTargetUpdateDirectiveClass, OMPD_target_update, SourceLocation(), - SourceLocation(), NumClauses, 0) {} + SourceLocation(), NumClauses, 1) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -2984,11 +3009,11 @@ public: /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - static OMPTargetUpdateDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses); + static OMPTargetUpdateDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt); /// \brief Creates an empty directive with the place for \a NumClauses /// clauses. @@ -3015,6 +3040,8 @@ public: /// class OMPDistributeParallelForDirective : public OMPLoopDirective { friend class ASTStmtReader; + /// true if the construct has inner cancel directive. + bool HasCancel = false; /// \brief Build directive with the given start and end location. /// @@ -3028,7 +3055,7 @@ class OMPDistributeParallelForDirective : public OMPLoopDirective { unsigned CollapsedNum, unsigned NumClauses) : OMPLoopDirective(this, OMPDistributeParallelForDirectiveClass, OMPD_distribute_parallel_for, StartLoc, EndLoc, - CollapsedNum, NumClauses) {} + CollapsedNum, NumClauses), HasCancel(false) {} /// \brief Build an empty directive. /// @@ -3039,7 +3066,11 @@ class OMPDistributeParallelForDirective : public OMPLoopDirective { unsigned NumClauses) : OMPLoopDirective(this, OMPDistributeParallelForDirectiveClass, OMPD_distribute_parallel_for, SourceLocation(), - SourceLocation(), CollapsedNum, NumClauses) {} + SourceLocation(), CollapsedNum, NumClauses), + HasCancel(false) {} + + /// Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } public: /// \brief Creates directive with a list of \a Clauses. @@ -3051,11 +3082,12 @@ public: /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. /// \param Exprs Helper expressions for CodeGen. + /// \param HasCancel true if this directive has inner cancel directive. /// static OMPDistributeParallelForDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt, const HelperExprs &Exprs); + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool HasCancel); /// \brief Creates an empty directive with the place /// for \a NumClauses clauses. @@ -3069,6 +3101,9 @@ public: unsigned CollapsedNum, EmptyShell); + /// Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPDistributeParallelForDirectiveClass; } @@ -3565,6 +3600,8 @@ public: /// class OMPTeamsDistributeParallelForDirective final : public OMPLoopDirective { friend class ASTStmtReader; + /// true if the construct has inner cancel directive. + bool HasCancel = false; /// Build directive with the given start and end location. /// @@ -3579,7 +3616,7 @@ class OMPTeamsDistributeParallelForDirective final : public OMPLoopDirective { unsigned NumClauses) : OMPLoopDirective(this, OMPTeamsDistributeParallelForDirectiveClass, OMPD_teams_distribute_parallel_for, StartLoc, EndLoc, - CollapsedNum, NumClauses) {} + CollapsedNum, NumClauses), HasCancel(false) {} /// Build an empty directive. /// @@ -3590,7 +3627,11 @@ class OMPTeamsDistributeParallelForDirective final : public OMPLoopDirective { unsigned NumClauses) : OMPLoopDirective(this, OMPTeamsDistributeParallelForDirectiveClass, OMPD_teams_distribute_parallel_for, SourceLocation(), - SourceLocation(), CollapsedNum, NumClauses) {} + SourceLocation(), CollapsedNum, NumClauses), + HasCancel(false) {} + + /// Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } public: /// Creates directive with a list of \a Clauses. @@ -3602,11 +3643,12 @@ public: /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. /// \param Exprs Helper expressions for CodeGen. + /// \param HasCancel true if this directive has inner cancel directive. /// static OMPTeamsDistributeParallelForDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt, const HelperExprs &Exprs); + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool HasCancel); /// Creates an empty directive with the place for \a NumClauses clauses. /// @@ -3618,6 +3660,9 @@ public: CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, EmptyShell); + /// Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTeamsDistributeParallelForDirectiveClass; } @@ -3761,6 +3806,8 @@ public: class OMPTargetTeamsDistributeParallelForDirective final : public OMPLoopDirective { friend class ASTStmtReader; + /// true if the construct has inner cancel directive. + bool HasCancel = false; /// Build directive with the given start and end location. /// @@ -3776,7 +3823,8 @@ class OMPTargetTeamsDistributeParallelForDirective final : OMPLoopDirective(this, OMPTargetTeamsDistributeParallelForDirectiveClass, OMPD_target_teams_distribute_parallel_for, StartLoc, - EndLoc, CollapsedNum, NumClauses) {} + EndLoc, CollapsedNum, NumClauses), + HasCancel(false) {} /// Build an empty directive. /// @@ -3788,7 +3836,11 @@ class OMPTargetTeamsDistributeParallelForDirective final : OMPLoopDirective( this, OMPTargetTeamsDistributeParallelForDirectiveClass, OMPD_target_teams_distribute_parallel_for, SourceLocation(), - SourceLocation(), CollapsedNum, NumClauses) {} + SourceLocation(), CollapsedNum, NumClauses), + HasCancel(false) {} + + /// Set cancel state. + void setHasCancel(bool Has) { HasCancel = Has; } public: /// Creates directive with a list of \a Clauses. @@ -3800,11 +3852,12 @@ public: /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. /// \param Exprs Helper expressions for CodeGen. + /// \param HasCancel true if this directive has inner cancel directive. /// static OMPTargetTeamsDistributeParallelForDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt, const HelperExprs &Exprs); + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool HasCancel); /// Creates an empty directive with the place for \a NumClauses clauses. /// @@ -3816,6 +3869,9 @@ public: CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, EmptyShell); + /// Return true if current directive has inner cancel directive. + bool hasCancel() const { return HasCancel; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTargetTeamsDistributeParallelForDirectiveClass; diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h index df4a2d8bc3d7b..98fa113274069 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h @@ -1,4 +1,4 @@ -//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===// +//===- StmtVisitor.h - Visitor for Stmt subclasses --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,28 +17,33 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" +#include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <utility> namespace clang { -template <typename T> struct make_ptr { typedef T *type; }; -template <typename T> struct make_const_ptr { typedef const T *type; }; +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. -template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void, + class... ParamTys> class StmtVisitorBase { public: - #define PTR(CLASS) typename Ptr<CLASS>::type #define DISPATCH(NAME, CLASS) \ - return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S)) - - RetTy Visit(PTR(Stmt) S) { + return static_cast<ImplClass*>(this)->Visit ## NAME( \ + static_cast<PTR(CLASS)>(S), std::forward<ParamTys>(P)...) + RetTy Visit(PTR(Stmt) S, ParamTys... P) { // If we have a binary expr, dispatch to the subcode of the binop. A smart // optimizer (e.g. LLVM) will fold this comparison into the switch stmt // below. @@ -60,6 +65,7 @@ public: case BO_GE: DISPATCH(BinGE, BinaryOperator); case BO_EQ: DISPATCH(BinEQ, BinaryOperator); case BO_NE: DISPATCH(BinNE, BinaryOperator); + case BO_Cmp: DISPATCH(BinCmp, BinaryOperator); case BO_And: DISPATCH(BinAnd, BinaryOperator); case BO_Xor: DISPATCH(BinXor, BinaryOperator); @@ -111,13 +117,13 @@ public: // If the implementation chooses not to implement a certain visit method, fall // back on VisitExpr or whatever else is the superclass. #define STMT(CLASS, PARENT) \ - RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); } + RetTy Visit ## CLASS(PTR(CLASS) S, ParamTys... P) { DISPATCH(PARENT, PARENT); } #include "clang/AST/StmtNodes.inc" // If the implementation doesn't implement binary operator methods, fall back // on VisitBinaryOperator. #define BINOP_FALLBACK(NAME) \ - RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \ + RetTy VisitBin ## NAME(PTR(BinaryOperator) S, ParamTys... P) { \ DISPATCH(BinaryOperator, BinaryOperator); \ } BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) @@ -127,6 +133,8 @@ public: BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) + BINOP_FALLBACK(Cmp) + BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr) @@ -137,7 +145,7 @@ public: // If the implementation doesn't implement compound assignment operator // methods, fall back on VisitCompoundAssignOperator. #define CAO_FALLBACK(NAME) \ - RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \ + RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S, ParamTys... P) { \ DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \ } CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) @@ -149,7 +157,7 @@ public: // If the implementation doesn't implement unary operator methods, fall back // on VisitUnaryOperator. #define UNARYOP_FALLBACK(NAME) \ - RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \ + RetTy VisitUnary ## NAME(PTR(UnaryOperator) S, ParamTys... P) { \ DISPATCH(UnaryOperator, UnaryOperator); \ } UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) @@ -163,7 +171,7 @@ public: #undef UNARYOP_FALLBACK // Base case, ignore it. :) - RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); } + RetTy VisitStmt(PTR(Stmt) Node, ParamTys... P) { return RetTy(); } #undef PTR #undef DISPATCH @@ -174,18 +182,18 @@ public: /// /// This class does not preserve constness of Stmt pointers (see also /// ConstStmtVisitor). -template<typename ImplClass, typename RetTy=void> +template<typename ImplClass, typename RetTy=void, typename... ParamTys> class StmtVisitor - : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {}; + : public StmtVisitorBase<make_ptr, 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> +template<typename ImplClass, typename RetTy=void, typename... ParamTys> class ConstStmtVisitor - : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {}; + : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy, ParamTys...> {}; /// \brief This class implements a simple visitor for OMPClause /// subclasses. @@ -222,6 +230,6 @@ template<class ImplClass, typename RetTy = void> class ConstOMPClauseVisitor : public OMPClauseVisitorBase <ImplClass, make_const_ptr, RetTy> {}; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_STMTVISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h index 84fbcda6e0873..850250b9c0a21 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h +++ b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h @@ -1,4 +1,4 @@ -//===-- TemplateBase.h - Core classes for C++ templates ---------*- C++ -*-===// +//===- TemplateBase.h - Core classes for C++ templates ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,21 +15,32 @@ #ifndef LLVM_CLANG_AST_TEMPLATEBASE_H #define LLVM_CLANG_AST_TEMPLATEBASE_H +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> namespace llvm { - class FoldingSetNodeID; -} + +class FoldingSetNodeID; + +} // namespace llvm namespace clang { +class ASTContext; class DiagnosticBuilder; class Expr; struct PrintingPolicy; @@ -44,29 +55,37 @@ public: /// \brief Represents an empty template argument, e.g., one that has not /// been deduced. Null = 0, + /// The template argument is a type. Type, + /// The template argument is a declaration that was provided for a pointer, /// reference, or pointer to member non-type template parameter. Declaration, + /// The template argument is a null pointer or null pointer to member that /// was provided for a non-type template parameter. NullPtr, + /// The template argument is an integral value stored in an llvm::APSInt /// that was provided for an integral non-type template parameter. Integral, + /// The template argument is a template name that was provided for a /// template template parameter. Template, + /// The template argument is a pack expansion of a template name that was /// provided for a template template parameter. TemplateExpansion, + /// The template argument is an expression, and we've not resolved it to one /// of the other forms yet, either because it's dependent or because we're /// representing a non-canonical template argument (for instance, in a /// TemplateSpecializationType). Also used to represent a non-dependent /// __uuidof expression (a Microsoft extension). Expression, + /// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. Pack @@ -88,8 +107,11 @@ private: unsigned BitWidth : 31; unsigned IsUnsigned : 1; union { - uint64_t VAL; ///< Used to store the <= 64 bits integer value. - const uint64_t *pVal; ///< Used to store the >64 bits integer value. + /// Used to store the <= 64 bits integer value. + uint64_t VAL; + + /// Used to store the >64 bits integer value. + const uint64_t *pVal; }; void *Type; }; @@ -115,8 +137,6 @@ private: struct TV TypeOrValue; }; - TemplateArgument(TemplateName, bool) = delete; - public: /// \brief Construct an empty, invalid template argument. constexpr TemplateArgument() : TypeOrValue({Null, 0}) {} @@ -202,6 +222,8 @@ public: this->Args.NumArgs = Args.size(); } + TemplateArgument(TemplateName, bool) = delete; + static TemplateArgument getEmptyPack() { return TemplateArgument(None); } /// \brief Create a new template argument pack by copying the given set of @@ -278,7 +300,9 @@ public: // FIXME: Provide a way to read the integral data without copying the value. llvm::APSInt getAsIntegral() const { assert(getKind() == Integral && "Unexpected kind"); + using namespace llvm; + if (Integer.BitWidth <= 64) return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned); @@ -309,7 +333,7 @@ public: } /// \brief Iterator that traverses the elements of a template argument pack. - typedef const TemplateArgument * pack_iterator; + using pack_iterator = const TemplateArgument *; /// \brief Iterator referencing the first argument of a template argument /// pack. @@ -368,7 +392,6 @@ public: /// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { private: - struct T { // FIXME: We'd like to just use the qualifier in the TemplateName, // but template arguments get canonicalized too quickly. @@ -393,8 +416,7 @@ public: TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, - SourceLocation EllipsisLoc) - { + SourceLocation EllipsisLoc) { Template.Qualifier = QualifierLoc.getNestedNameSpecifier(); Template.QualifierLocData = QualifierLoc.getOpaqueData(); Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); @@ -434,16 +456,15 @@ public: TemplateArgumentLoc(const TemplateArgument &Argument, TemplateArgumentLocInfo Opaque) - : Argument(Argument), LocInfo(Opaque) { - } + : Argument(Argument), LocInfo(Opaque) {} TemplateArgumentLoc(const TemplateArgument &Argument, TypeSourceInfo *TInfo) - : Argument(Argument), LocInfo(TInfo) { + : Argument(Argument), LocInfo(TInfo) { assert(Argument.getKind() == TemplateArgument::Type); } TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) - : Argument(Argument), LocInfo(E) { + : Argument(Argument), LocInfo(E) { assert(Argument.getKind() == TemplateArgument::Expression); } @@ -451,7 +472,8 @@ public: NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc = SourceLocation()) - : Argument(Argument), LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) { + : Argument(Argument), + LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) { assert(Argument.getKind() == TemplateArgument::Template || Argument.getKind() == TemplateArgument::TemplateExpansion); } @@ -526,16 +548,16 @@ class TemplateArgumentListInfo { SourceLocation LAngleLoc; SourceLocation RAngleLoc; - // This can leak if used in an AST node, use ASTTemplateArgumentListInfo - // instead. - void *operator new(size_t bytes, ASTContext &C) = delete; - public: - TemplateArgumentListInfo() {} + TemplateArgumentListInfo() = default; TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc) - : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + + // This can leak if used in an AST node, use ASTTemplateArgumentListInfo + // instead. + void *operator new(size_t bytes, ASTContext &C) = delete; SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; } @@ -574,8 +596,8 @@ struct ASTTemplateArgumentListInfo final : private llvm::TrailingObjects<ASTTemplateArgumentListInfo, TemplateArgumentLoc> { private: - friend TrailingObjects; friend class ASTNodeImporter; + friend TrailingObjects; ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List); @@ -668,6 +690,6 @@ inline const TemplateArgument & return getArgs()[Idx]; } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_TEMPLATEBASE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h index bf4d008ee807a..fb33cf58d7960 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h +++ b/contrib/llvm/tools/clang/include/clang/AST/TemplateName.h @@ -1,4 +1,4 @@ -//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +//===- TemplateName.h - C++ Template Name Representation --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,10 +14,12 @@ #ifndef LLVM_CLANG_AST_TEMPLATENAME_H #define LLVM_CLANG_AST_TEMPLATENAME_H -#include "clang/AST/NestedNameSpecifier.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> namespace clang { @@ -94,7 +96,7 @@ class OverloadedTemplateStorage : public UncommonTemplateNameStorage { friend class ASTContext; OverloadedTemplateStorage(unsigned size) - : UncommonTemplateNameStorage(Overloaded, size) { } + : UncommonTemplateNameStorage(Overloaded, size) {} NamedDecl **getStorage() { return reinterpret_cast<NamedDecl **>(this + 1); @@ -104,7 +106,7 @@ class OverloadedTemplateStorage : public UncommonTemplateNameStorage { } public: - typedef NamedDecl *const *iterator; + using iterator = NamedDecl *const *; iterator begin() const { return getStorage(); } iterator end() const { return getStorage() + size(); } @@ -126,8 +128,8 @@ public: SubstTemplateTemplateParmPackStorage(TemplateTemplateParmDecl *Parameter, unsigned Size, const TemplateArgument *Arguments) - : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), - Parameter(Parameter), Arguments(Arguments) { } + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), + Parameter(Parameter), Arguments(Arguments) {} /// \brief Retrieve the template template parameter pack being substituted. TemplateTemplateParmDecl *getParameterPack() const { @@ -174,10 +176,9 @@ public: /// specifier in the typedef. "apply" is a nested template, and can /// only be understood in the context of class TemplateName { - typedef llvm::PointerUnion4<TemplateDecl *, - UncommonTemplateNameStorage *, - QualifiedTemplateName *, - DependentTemplateName *> StorageType; + using StorageType = + llvm::PointerUnion4<TemplateDecl *, UncommonTemplateNameStorage *, + QualifiedTemplateName *, DependentTemplateName *>; StorageType Storage; @@ -188,24 +189,29 @@ public: enum NameKind { /// \brief A single template declaration. Template, + /// \brief A set of overloaded template declarations. OverloadedTemplate, + /// \brief A qualified template name, where the qualification is kept /// to describe the source code as written. QualifiedTemplate, + /// \brief A dependent template name that has not been resolved to a /// template (or set of templates). DependentTemplate, + /// \brief A template template parameter that has been substituted /// for some other template name. SubstTemplateTemplateParm, + /// \brief A template template parameter pack that has been substituted for /// a template template argument pack, but has not yet been expanded into /// individual arguments. SubstTemplateTemplateParmPack }; - TemplateName() : Storage() { } + TemplateName() = default; explicit TemplateName(TemplateDecl *Template); explicit TemplateName(OverloadedTemplateStorage *Storage); explicit TemplateName(SubstTemplateTemplateParmStorage *Storage); @@ -262,6 +268,11 @@ public: TemplateName getUnderlying() const; + /// Get the template name to substitute when this template name is used as a + /// template template argument. This refers to the most recent declaration of + /// the template, including any default template arguments. + TemplateName getNameToSubstitute() const; + /// \brief Determines whether this is a dependent template name. bool isDependent() const; @@ -320,8 +331,8 @@ class SubstTemplateTemplateParmStorage SubstTemplateTemplateParmStorage(TemplateTemplateParmDecl *parameter, TemplateName replacement) - : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), - Parameter(parameter), Replacement(replacement) {} + : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), + Parameter(parameter), Replacement(replacement) {} public: TemplateTemplateParmDecl *getParameter() const { return Parameter; } @@ -353,6 +364,8 @@ inline TemplateName TemplateName::getUnderlying() const { /// manner, it is to TemplateName what ElaboratedType is to Type, /// providing extra syntactic sugar for downstream clients. class QualifiedTemplateName : public llvm::FoldingSetNode { + friend class ASTContext; + /// \brief The nested name specifier that qualifies the template name. /// /// The bit is used to indicate whether the "template" keyword was @@ -366,12 +379,9 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// that this qualified name refers to. TemplateDecl *Template; - friend class ASTContext; - QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) - : Qualifier(NNS, TemplateKeyword? 1 : 0), - Template(Template) { } + : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) {} public: /// \brief Return the nested name specifier that qualifies this name. @@ -410,6 +420,8 @@ public: /// where "MetaFun::" is the nested name specifier and "apply" is the /// template name referenced. The "template" keyword is implied. class DependentTemplateName : public llvm::FoldingSetNode { + friend class ASTContext; + /// \brief The nested name specifier that qualifies the template /// name. /// @@ -439,29 +451,27 @@ class DependentTemplateName : public llvm::FoldingSetNode { /// canonical. TemplateName CanonicalTemplateName; - friend class ASTContext; - DependentTemplateName(NestedNameSpecifier *Qualifier, const IdentifierInfo *Identifier) - : Qualifier(Qualifier, false), Identifier(Identifier), - CanonicalTemplateName(this) { } + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(this) {} DependentTemplateName(NestedNameSpecifier *Qualifier, const IdentifierInfo *Identifier, TemplateName Canon) - : Qualifier(Qualifier, false), Identifier(Identifier), - CanonicalTemplateName(Canon) { } + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(Canon) {} DependentTemplateName(NestedNameSpecifier *Qualifier, OverloadedOperatorKind Operator) - : Qualifier(Qualifier, true), Operator(Operator), - CanonicalTemplateName(this) { } + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(this) {} DependentTemplateName(NestedNameSpecifier *Qualifier, OverloadedOperatorKind Operator, TemplateName Canon) - : Qualifier(Qualifier, true), Operator(Operator), - CanonicalTemplateName(Canon) { } + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(Canon) {} public: /// \brief Return the nested name specifier that qualifies this name. @@ -509,14 +519,13 @@ public: } }; -} // end namespace clang. +} // namespace clang. namespace llvm { /// \brief The clang::TemplateName class is effectively a pointer. template<> -class PointerLikeTypeTraits<clang::TemplateName> { -public: +struct PointerLikeTypeTraits<clang::TemplateName> { static inline void *getAsVoidPointer(clang::TemplateName TN) { return TN.getAsVoidPointer(); } @@ -529,6 +538,6 @@ public: enum { NumLowBitsAvailable = 0 }; }; -} // end namespace llvm. +} // namespace llvm. -#endif +#endif // LLVM_CLANG_AST_TEMPLATENAME_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/Type.h b/contrib/llvm/tools/clang/include/clang/AST/Type.h index 984096ffa9877..7247838947a2e 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Type.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Type.h @@ -1,4 +1,4 @@ -//===--- Type.h - C Language Family Type Representation ---------*- C++ -*-===// +//===- Type.h - C Language Family Type Representation -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,12 +6,13 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// /// \file /// \brief C Language Family Type Representation /// /// This file defines the clang::Type interface and subclasses, used to /// represent types for languages in the C family. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPE_H @@ -25,85 +26,118 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <string> +#include <type_traits> +#include <utility> namespace clang { - enum { - TypeAlignmentInBits = 4, - TypeAlignment = 1 << TypeAlignmentInBits - }; - class Type; - class ExtQuals; - class QualType; -} + +class ExtQuals; +class QualType; +class Type; + +enum { + TypeAlignmentInBits = 4, + TypeAlignment = 1 << TypeAlignmentInBits +}; + +} // namespace clang namespace llvm { + template <typename T> - class PointerLikeTypeTraits; + struct PointerLikeTypeTraits; template<> - class PointerLikeTypeTraits< ::clang::Type*> { - public: + struct PointerLikeTypeTraits< ::clang::Type*> { static inline void *getAsVoidPointer(::clang::Type *P) { return P; } + static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; + template<> - class PointerLikeTypeTraits< ::clang::ExtQuals*> { - public: + struct PointerLikeTypeTraits< ::clang::ExtQuals*> { static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } + static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { return static_cast< ::clang::ExtQuals*>(P); } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template <> struct isPodLike<clang::QualType> { static const bool value = true; }; -} + +} // namespace llvm namespace clang { - class ASTContext; - class TypedefNameDecl; - class TemplateDecl; - class TemplateTypeParmDecl; - class NonTypeTemplateParmDecl; - class TemplateTemplateParmDecl; - class TagDecl; - class RecordDecl; - class CXXRecordDecl; - class EnumDecl; - class FieldDecl; - class FunctionDecl; - class ObjCInterfaceDecl; - class ObjCProtocolDecl; - class ObjCMethodDecl; - class ObjCTypeParamDecl; - class UnresolvedUsingTypenameDecl; - class Expr; - class Stmt; - class SourceLocation; - class StmtIteratorBase; - class TemplateArgument; - class TemplateArgumentLoc; - class TemplateArgumentListInfo; - class ElaboratedType; - class ExtQuals; - class ExtQualsTypeCommonBase; - struct PrintingPolicy; - template <typename> class CanQual; - typedef CanQual<Type> CanQualType; +class ArrayType; +class ASTContext; +class AttributedType; +class AutoType; +class BuiltinType; +template <typename> class CanQual; +class ComplexType; +class CXXRecordDecl; +class DeclContext; +class DeducedType; +class EnumDecl; +class Expr; +class ExtQualsTypeCommonBase; +class FunctionDecl; +class FunctionNoProtoType; +class FunctionProtoType; +class IdentifierInfo; +class InjectedClassNameType; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCObjectPointerType; +class ObjCObjectType; +class ObjCProtocolDecl; +class ObjCTypeParamDecl; +class ParenType; +struct PrintingPolicy; +class RecordDecl; +class RecordType; +class Stmt; +class TagDecl; +class TemplateArgument; +class TemplateArgumentListInfo; +class TemplateArgumentLoc; +class TemplateSpecializationType; +class TemplateTypeParmDecl; +class TypedefNameDecl; +class TypedefType; +class UnresolvedUsingTypenameDecl; + +using CanQualType = CanQual<Type>; // Provide forward declarations for all of the *Type classes #define TYPE(Class, Base) class Class##Type; @@ -164,8 +198,6 @@ public: FastMask = (1 << FastWidth) - 1 }; - Qualifiers() : Mask(0) {} - /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { @@ -332,9 +364,11 @@ public: } bool hasAddressSpace() const { return Mask & AddressSpaceMask; } - unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } + LangAS getAddressSpace() const { + return static_cast<LangAS>(Mask >> AddressSpaceShift); + } bool hasTargetSpecificAddressSpace() const { - return getAddressSpace() >= LangAS::FirstTargetAddressSpace; + return isTargetAddressSpace(getAddressSpace()); } /// Get the address space attribute value to be printed by diagnostics. unsigned getAddressSpaceAttributePrintValue() const { @@ -342,22 +376,22 @@ public: // This function is not supposed to be used with language specific // address spaces. If that happens, the diagnostic message should consider // printing the QualType instead of the address space value. - assert(Addr == 0 || hasTargetSpecificAddressSpace()); - if (Addr) - return Addr - LangAS::FirstTargetAddressSpace; + assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); + if (Addr != LangAS::Default) + return toTargetAddressSpace(Addr); // TODO: The diagnostic messages where Addr may be 0 should be fixed // since it cannot differentiate the situation where 0 denotes the default // address space or user specified __attribute__((address_space(0))). return 0; } - void setAddressSpace(unsigned space) { - assert(space <= MaxAddressSpace); + void setAddressSpace(LangAS space) { + assert((unsigned)space <= MaxAddressSpace); Mask = (Mask & ~AddressSpaceMask) | (((uint32_t) space) << AddressSpaceShift); } - void removeAddressSpace() { setAddressSpace(0); } - void addAddressSpace(unsigned space) { - assert(space); + void removeAddressSpace() { setAddressSpace(LangAS::Default); } + void addAddressSpace(LangAS space) { + assert(space != LangAS::Default); setAddressSpace(space); } @@ -538,10 +572,9 @@ public: } private: - // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| // |C R V|U|GCAttr|Lifetime|AddressSpace| - uint32_t Mask; + uint32_t Mask = 0; static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; @@ -558,12 +591,12 @@ private: /// into its local qualifiers and its locally-unqualified type. struct SplitQualType { /// The locally-unqualified type. - const Type *Ty; + const Type *Ty = nullptr; /// The local qualifiers. Qualifiers Quals; - SplitQualType() : Ty(nullptr), Quals() {} + SplitQualType() = default; SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} SplitQualType getSingleStepDesugaredType() const; // end of this file @@ -589,12 +622,16 @@ struct SplitQualType { enum class ObjCSubstitutionContext { /// An ordinary type. Ordinary, + /// The result type of a method or function. Result, + /// The parameter type of a method or function. Parameter, + /// The type of a property. Property, + /// The superclass of a type. Superclass, }; @@ -614,8 +651,10 @@ enum class ObjCSubstitutionContext { /// indicates whether there are extended qualifiers present, in which /// case the pointer points to a special structure. class QualType { + friend class QualifierCollector; + // Thankfully, these are efficiently composable. - llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>, + llvm::PointerIntPair<llvm::PointerUnion<const Type *, const ExtQuals *>, Qualifiers::FastWidth> Value; const ExtQuals *getExtQualsUnsafe() const { @@ -634,14 +673,10 @@ class QualType { return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); } - friend class QualifierCollector; public: - QualType() {} - - QualType(const Type *Ptr, unsigned Quals) - : Value(Ptr, Quals) {} - QualType(const ExtQuals *Ptr, unsigned Quals) - : Value(Ptr, Quals) {} + QualType() = default; + QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} unsigned getLocalFastQualifiers() const { return Value.getInt(); } void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } @@ -662,6 +697,7 @@ public: SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + static QualType getFromOpaquePtr(const void *Ptr) { QualType T; T.Value.setFromOpaqueValue(const_cast<void*>(Ptr)); @@ -939,12 +975,15 @@ public: friend bool operator!=(const QualType &LHS, const QualType &RHS) { return LHS.Value != RHS.Value; } + std::string getAsString() const { return getAsString(split()); } + static std::string getAsString(SplitQualType split) { return getAsString(split.Ty, split.Quals); } + static std::string getAsString(const Type *ty, Qualifiers qs); std::string getAsString(const PrintingPolicy &Policy) const; @@ -954,11 +993,13 @@ public: unsigned Indentation = 0) const { print(split(), OS, Policy, PlaceHolder, Indentation); } + static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0) { return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); } + static void print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, @@ -968,10 +1009,12 @@ public: const PrintingPolicy &Policy) const { return getAsStringInternal(split(), Str, Policy); } + static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { return getAsStringInternal(split.Ty, split.Quals, out, policy); } + static void getAsStringInternal(const Type *ty, Qualifiers qs, std::string &out, const PrintingPolicy &policy); @@ -981,11 +1024,12 @@ public: const PrintingPolicy &Policy; const Twine &PlaceHolder; unsigned Indentation; + public: StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, const Twine &PlaceHolder, unsigned Indentation) - : T(T), Policy(Policy), PlaceHolder(PlaceHolder), - Indentation(Indentation) { } + : T(T), Policy(Policy), PlaceHolder(PlaceHolder), + Indentation(Indentation) {} friend raw_ostream &operator<<(raw_ostream &OS, const StreamedQualTypeHelper &SQT) { @@ -1009,7 +1053,7 @@ public: } /// Return the address space of this type. - inline unsigned getAddressSpace() const; + inline LangAS getAddressSpace() const; /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; @@ -1129,13 +1173,15 @@ private: static DestructionKind isDestructedTypeImpl(QualType type); }; -} // end clang. +} // namespace clang namespace llvm { + /// Implement simplify_type for QualType, so that we can dyn_cast from QualType /// to a specific Type class. template<> struct simplify_type< ::clang::QualType> { - typedef const ::clang::Type *SimpleType; + using SimpleType = const ::clang::Type *; + static SimpleType getSimplifiedValue(::clang::QualType Val) { return Val.getTypePtr(); } @@ -1143,29 +1189,30 @@ template<> struct simplify_type< ::clang::QualType> { // Teach SmallPtrSet that QualType is "basically a pointer". template<> -class PointerLikeTypeTraits<clang::QualType> { -public: +struct PointerLikeTypeTraits<clang::QualType> { static inline void *getAsVoidPointer(clang::QualType P) { return P.getAsOpaquePtr(); } + static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } + // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; -} // end namespace llvm +} // namespace llvm namespace clang { /// \brief Base class that is common to both the \c ExtQuals and \c Type /// classes, which allows \c QualType to access the common fields between the /// two. -/// class ExtQualsTypeCommonBase { - ExtQualsTypeCommonBase(const Type *baseType, QualType canon) - : BaseType(baseType), CanonicalType(canon) {} + friend class ExtQuals; + friend class QualType; + friend class Type; /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or /// a self-referential pointer (for \c Type). @@ -1177,9 +1224,8 @@ class ExtQualsTypeCommonBase { /// \brief The canonical type of this type. A QualType. QualType CanonicalType; - friend class QualType; - friend class Type; - friend class ExtQuals; + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} }; /// We can encode up to four bits in the low bits of a @@ -1214,10 +1260,9 @@ class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { public: ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) - : ExtQualsTypeCommonBase(baseType, - canon.isNull() ? QualType(this_(), 0) : canon), - Quals(quals) - { + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + Quals(quals) { assert(Quals.hasNonFastQualifiers() && "ExtQuals created with no fast qualifiers"); assert(!Quals.hasFastQualifiers() @@ -1235,7 +1280,7 @@ public: } bool hasAddressSpace() const { return Quals.hasAddressSpace(); } - unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + LangAS getAddressSpace() const { return Quals.getAddressSpace(); } const Type *getBaseType() const { return BaseType; } @@ -1243,6 +1288,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, getBaseType(), Quals); } + static void Profile(llvm::FoldingSetNodeID &ID, const Type *BaseType, Qualifiers Quals) { @@ -1258,8 +1304,10 @@ public: enum RefQualifierKind { /// \brief No ref-qualifier was provided. RQ_None = 0, + /// \brief An lvalue ref-qualifier was provided (\c &). RQ_LValue, + /// \brief An rvalue ref-qualifier was provided (\c &&). RQ_RValue }; @@ -1268,8 +1316,10 @@ enum RefQualifierKind { enum class AutoTypeKeyword { /// \brief auto Auto, + /// \brief decltype(auto) DecltypeAuto, + /// \brief __auto_type (GNU extension) GNUAutoType }; @@ -1311,9 +1361,6 @@ public: }; private: - Type(const Type &) = delete; - void operator=(const Type &) = delete; - /// Bitfields required by the Type class. class TypeBitfields { friend class Type; @@ -1352,10 +1399,12 @@ private: bool isCacheValid() const { return CacheValid; } + Linkage getLinkage() const { assert(isCacheValid() && "getting linkage from invalid cache"); return static_cast<Linkage>(CachedLinkage); } + bool hasLocalOrUnnamedType() const { assert(isCacheValid() && "getting linkage from invalid cache"); return CachedLocalOrUnnamed; @@ -1392,8 +1441,8 @@ protected: }; class FunctionTypeBitfields { - friend class FunctionType; friend class FunctionProtoType; + friend class FunctionType; unsigned : NumTypeBits; @@ -1429,6 +1478,7 @@ protected: /// Whether this is a "kindof" type. unsigned IsKindOf : 1; }; + static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned"); class ReferenceTypeBitfields { @@ -1511,21 +1561,21 @@ protected: }; private: + template <class T> friend class TypePropertyCache; + /// \brief Set whether this type comes from an AST file. void setFromAST(bool V = true) const { TypeBits.FromAST = V; } - template <class T> friend class TypePropertyCache; - protected: - // silence VC++ warning C4355: 'this' : used in base member initializer list - Type *this_() { return this; } + friend class ASTContext; + Type(TypeClass tc, QualType canon, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) - : ExtQualsTypeCommonBase(this, - canon.isNull() ? QualType(this_(), 0) : canon) { + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; TypeBits.InstantiationDependent = Dependent || InstantiationDependent; @@ -1536,22 +1586,32 @@ protected: TypeBits.CachedLinkage = NoLinkage; TypeBits.FromAST = false; } - friend class ASTContext; + + // silence VC++ warning C4355: 'this' : used in base member initializer list + Type *this_() { return this; } void setDependent(bool D = true) { TypeBits.Dependent = D; if (D) TypeBits.InstantiationDependent = true; } + void setInstantiationDependent(bool D = true) { TypeBits.InstantiationDependent = D; } - void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; - } + + void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } + void setContainsUnexpandedParameterPack(bool PP = true) { TypeBits.ContainsUnexpandedParameterPack = PP; } public: + friend class ASTReader; + friend class ASTWriter; + + Type(const Type &) = delete; + Type &operator=(const Type &) = delete; + TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); } /// \brief Whether this type comes from an AST file. @@ -1658,6 +1718,7 @@ public: /// Determine whether this type is an integral or enumeration type. bool isIntegralOrEnumerationType() const; + /// Determine whether this type is an integral or unscoped enumeration type. bool isIntegralOrUnscopedEnumerationType() const; @@ -1708,6 +1769,7 @@ public: bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. + bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type @@ -1789,6 +1851,7 @@ public: STK_IntegralComplex, STK_FloatingComplex }; + /// Given that this is a scalar type, classify it. ScalarTypeKind getScalarTypeKind() const; @@ -1859,6 +1922,7 @@ public: const RecordType *getAsUnionType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. const ObjCObjectType *getAsObjCInterfaceType() const; + // The following is a convenience method that returns an ObjCObjectPointerType // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; @@ -2045,12 +2109,10 @@ public: QualType getCanonicalTypeInternal() const { return CanonicalType; } + CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; void dump(llvm::raw_ostream &OS) const; - - friend class ASTReader; - friend class ASTWriter; }; /// \brief This will check for a TypedefType by removing any existing sugar @@ -2078,7 +2140,6 @@ template <> inline const Class##Type *Type::castAs() const { \ } #include "clang/AST/TypeNodes.def" - /// This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { @@ -2095,15 +2156,16 @@ public: public: BuiltinType(Kind K) - : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), - /*InstantiationDependent=*/(K == Dependent), - /*VariablyModified=*/false, - /*Unexpanded parameter pack=*/false) { + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), + /*InstantiationDependent=*/(K == Dependent), + /*VariablyModified=*/false, + /*Unexpanded parameter pack=*/false) { BuiltinTypeBits.Kind = K; } Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); } StringRef getName(const PrintingPolicy &Policy) const; + const char *getNameAsCString(const PrintingPolicy &Policy) const { // The StringRef is null-terminated. StringRef str = getName(Policy); @@ -2160,17 +2222,17 @@ public: /// Complex values, per C99 6.2.5p11. This supports the C99 complex /// types (_Complex float etc) as well as the GCC integer complex extensions. -/// class ComplexType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType ElementType; - ComplexType(QualType Element, QualType CanonicalPtr) : - Type(Complex, CanonicalPtr, Element->isDependentType(), - Element->isInstantiationDependentType(), - Element->isVariablyModifiedType(), - Element->containsUnexpandedParameterPack()), - ElementType(Element) { - } - friend class ASTContext; // ASTContext creates these. + + ComplexType(QualType Element, QualType CanonicalPtr) + : Type(Complex, CanonicalPtr, Element->isDependentType(), + Element->isInstantiationDependentType(), + Element->isVariablyModifiedType(), + Element->containsUnexpandedParameterPack()), + ElementType(Element) {} public: QualType getElementType() const { return ElementType; } @@ -2181,6 +2243,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { ID.AddPointer(Element.getAsOpaquePtr()); } @@ -2189,21 +2252,19 @@ public: }; /// Sugar for parentheses used when specifying types. -/// class ParenType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType Inner; - ParenType(QualType InnerType, QualType CanonType) : - Type(Paren, CanonType, InnerType->isDependentType(), - InnerType->isInstantiationDependentType(), - InnerType->isVariablyModifiedType(), - InnerType->containsUnexpandedParameterPack()), - Inner(InnerType) { - } - friend class ASTContext; // ASTContext creates these. + ParenType(QualType InnerType, QualType CanonType) + : Type(Paren, CanonType, InnerType->isDependentType(), + InnerType->isInstantiationDependentType(), + InnerType->isVariablyModifiedType(), + InnerType->containsUnexpandedParameterPack()), + Inner(InnerType) {} public: - QualType getInnerType() const { return Inner; } bool isSugared() const { return true; } @@ -2212,6 +2273,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInnerType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { Inner.Profile(ID); } @@ -2220,21 +2282,19 @@ public: }; /// PointerType - C99 6.7.5.1 - Pointer Declarators. -/// class PointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType PointeeType; - PointerType(QualType Pointee, QualType CanonicalPtr) : - Type(Pointer, CanonicalPtr, Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), - PointeeType(Pointee) { - } - friend class ASTContext; // ASTContext creates these. + PointerType(QualType Pointee, QualType CanonicalPtr) + : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) {} public: - QualType getPointeeType() const { return PointeeType; } /// Returns true if address spaces of pointers overlap. @@ -2259,6 +2319,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } @@ -2274,6 +2335,8 @@ class AdjustedType : public Type, public llvm::FoldingSetNode { QualType AdjustedTy; protected: + friend class ASTContext; // ASTContext creates these. + AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, QualType CanonicalPtr) : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), @@ -2282,8 +2345,6 @@ protected: OriginalTy->containsUnexpandedParameterPack()), OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} - friend class ASTContext; // ASTContext creates these. - public: QualType getOriginalType() const { return OriginalTy; } QualType getAdjustedType() const { return AdjustedTy; } @@ -2294,6 +2355,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, OriginalTy, AdjustedTy); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { ID.AddPointer(Orig.getAsOpaquePtr()); ID.AddPointer(New.getAsOpaquePtr()); @@ -2306,12 +2368,11 @@ public: /// Represents a pointer type decayed from an array or function type. class DecayedType : public AdjustedType { + friend class ASTContext; // ASTContext creates these. inline DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); - friend class ASTContext; // ASTContext creates these. - public: QualType getDecayedType() const { return getAdjustedType(); } @@ -2323,20 +2384,20 @@ public: /// Pointer to a block type. /// This type is to represent types syntactically represented as /// "void (^)(int)", etc. Pointee is required to always be a function type. -/// class BlockPointerType : public Type, public llvm::FoldingSetNode { - QualType PointeeType; // Block is some kind of pointer type - BlockPointerType(QualType Pointee, QualType CanonicalCls) : - Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), - PointeeType(Pointee) { - } - friend class ASTContext; // ASTContext creates these. + friend class ASTContext; // ASTContext creates these. -public: + // Block is some kind of pointer type + QualType PointeeType; + BlockPointerType(QualType Pointee, QualType CanonicalCls) + : Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) {} + +public: // Get the pointee type. Pointee is required to always be a function type. QualType getPointeeType() const { return PointeeType; } @@ -2346,6 +2407,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } @@ -2356,19 +2418,17 @@ public: }; /// Base for LValueReferenceType and RValueReferenceType -/// class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue) : - Type(tc, CanonicalRef, Referencee->isDependentType(), - Referencee->isInstantiationDependentType(), - Referencee->isVariablyModifiedType(), - Referencee->containsUnexpandedParameterPack()), - PointeeType(Referencee) - { + bool SpelledAsLValue) + : Type(tc, CanonicalRef, Referencee->isDependentType(), + Referencee->isInstantiationDependentType(), + Referencee->isVariablyModifiedType(), + Referencee->containsUnexpandedParameterPack()), + PointeeType(Referencee) { ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } @@ -2378,6 +2438,7 @@ public: bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } QualType getPointeeTypeAsWritten() const { return PointeeType; } + QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; @@ -2389,6 +2450,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, PointeeType, isSpelledAsLValue()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, bool SpelledAsLValue) { @@ -2403,13 +2465,14 @@ public: }; /// An lvalue reference type, per C++11 [dcl.ref]. -/// class LValueReferenceType : public ReferenceType { - LValueReferenceType(QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue) : - ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) - {} friend class ASTContext; // ASTContext creates these + + LValueReferenceType(QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) + : ReferenceType(LValueReference, Referencee, CanonicalRef, + SpelledAsLValue) {} + public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2420,12 +2483,12 @@ public: }; /// An rvalue reference type, per C++11 [dcl.ref]. -/// class RValueReferenceType : public ReferenceType { - RValueReferenceType(QualType Referencee, QualType CanonicalRef) : - ReferenceType(RValueReference, Referencee, CanonicalRef, false) { - } friend class ASTContext; // ASTContext creates these + + RValueReferenceType(QualType Referencee, QualType CanonicalRef) + : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} + public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2438,24 +2501,24 @@ public: /// A pointer to member type per C++ 8.3.3 - Pointers to members. /// /// This includes both pointers to data members and pointer to member functions. -/// class MemberPointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType PointeeType; + /// The class of which the pointee is a member. Must ultimately be a /// RecordType, but could be a typedef or a template parameter too. const Type *Class; - MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : - Type(MemberPointer, CanonicalPtr, - Cls->isDependentType() || Pointee->isDependentType(), - (Cls->isInstantiationDependentType() || - Pointee->isInstantiationDependentType()), - Pointee->isVariablyModifiedType(), - (Cls->containsUnexpandedParameterPack() || - Pointee->containsUnexpandedParameterPack())), - PointeeType(Pointee), Class(Cls) { - } - friend class ASTContext; // ASTContext creates these. + MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) + : Type(MemberPointer, CanonicalPtr, + Cls->isDependentType() || Pointee->isDependentType(), + (Cls->isInstantiationDependentType() || + Pointee->isInstantiationDependentType()), + Pointee->isVariablyModifiedType(), + (Cls->containsUnexpandedParameterPack() || + Pointee->containsUnexpandedParameterPack())), + PointeeType(Pointee), Class(Cls) {} public: QualType getPointeeType() const { return PointeeType; } @@ -2481,6 +2544,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), getClass()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, const Type *Class) { ID.AddPointer(Pointee.getAsOpaquePtr()); @@ -2493,7 +2557,6 @@ public: }; /// Represents an array type, per C99 6.7.5.2 - Array Declarators. -/// class ArrayType : public Type, public llvm::FoldingSetNode { public: /// Capture whether this is a normal array (e.g. int X[4]) @@ -2503,11 +2566,14 @@ public: enum ArraySizeModifier { Normal, Static, Star }; + private: /// The element type of the array. QualType ElementType; protected: + friend class ASTContext; // ASTContext creates these. + // C++ [temp.dep.type]p1: // A type is dependent if it is... // - an array type constructed from any dependent type or whose @@ -2516,25 +2582,26 @@ protected: ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, bool ContainsUnexpandedParameterPack) - : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, - et->isInstantiationDependentType() || tc == DependentSizedArray, - (tc == VariableArray || et->isVariablyModifiedType()), - ContainsUnexpandedParameterPack), - ElementType(et) { + : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, + et->isInstantiationDependentType() || tc == DependentSizedArray, + (tc == VariableArray || et->isVariablyModifiedType()), + ContainsUnexpandedParameterPack), + ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; } - friend class ASTContext; // ASTContext creates these. - public: QualType getElementType() const { return ElementType; } + ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(ArrayTypeBits.SizeModifier); } + Qualifiers getIndexTypeQualifiers() const { return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); } + unsigned getIndexTypeCVRQualifiers() const { return ArrayTypeBits.IndexTypeQuals; } @@ -2555,21 +2622,23 @@ class ConstantArrayType : public ArrayType { ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) - : ArrayType(ConstantArray, et, can, sm, tq, - et->containsUnexpandedParameterPack()), - Size(size) {} + : ArrayType(ConstantArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + Size(size) {} + protected: + friend class ASTContext; // ASTContext creates these. + ConstantArrayType(TypeClass tc, QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) - : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), - Size(size) {} - friend class ASTContext; // ASTContext creates these. + : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), + Size(size) {} + public: const llvm::APInt &getSize() const { return Size; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - /// \brief Determine the number of bits required to address a member of // an array with the given element type and number of elements. static unsigned getNumAddressingBits(const ASTContext &Context, @@ -2584,6 +2653,7 @@ public: Profile(ID, getElementType(), getSize(), getSizeModifier(), getIndexTypeCVRQualifiers()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, unsigned TypeQuals) { @@ -2592,6 +2662,7 @@ public: ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } + static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray; } @@ -2601,13 +2672,16 @@ public: /// an IncompleteArrayType where the element type is 'int' and the size is /// unspecified. class IncompleteArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, unsigned tq) - : ArrayType(IncompleteArray, et, can, sm, tq, - et->containsUnexpandedParameterPack()) {} - friend class ASTContext; // ASTContext creates these. + : ArrayType(IncompleteArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()) {} + public: + friend class StmtIteratorBase; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2615,8 +2689,6 @@ public: return T->getTypeClass() == IncompleteArray; } - friend class StmtIteratorBase; - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers()); @@ -2644,28 +2716,32 @@ public: /// ++x; /// int Z[x]; /// } -/// class VariableArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + /// An assignment-expression. VLA's are only permitted within /// a function block. Stmt *SizeExpr; + /// The range spanned by the left and right array brackets. SourceRange Brackets; VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) - : ArrayType(VariableArray, et, can, sm, tq, - et->containsUnexpandedParameterPack()), - SizeExpr((Stmt*) e), Brackets(brackets) {} - friend class ASTContext; // ASTContext creates these. + : ArrayType(VariableArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + SizeExpr((Stmt*) e), Brackets(brackets) {} public: + friend class StmtIteratorBase; + Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } + SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } @@ -2677,8 +2753,6 @@ public: return T->getTypeClass() == VariableArray; } - friend class StmtIteratorBase; - void Profile(llvm::FoldingSetNodeID &ID) { llvm_unreachable("Cannot unique VariableArrayTypes."); } @@ -2698,6 +2772,8 @@ public: /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { + friend class ASTContext; // ASTContext creates these. + const ASTContext &Context; /// \brief An assignment expression that will instantiate to the @@ -2714,14 +2790,15 @@ class DependentSizedArrayType : public ArrayType { Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets); - friend class ASTContext; // ASTContext creates these. - public: + friend class StmtIteratorBase; + Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } + SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } @@ -2733,9 +2810,6 @@ public: return T->getTypeClass() == DependentSizedArray; } - friend class StmtIteratorBase; - - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); @@ -2746,6 +2820,49 @@ public: unsigned TypeQuals, Expr *E); }; +/// Represents an extended address space qualifier where the input address space +/// value is dependent. Non-dependent address spaces are not represented with a +/// special Type subclass; they are stored on an ExtQuals node as part of a QualType. +/// +/// For example: +/// \code +/// template<typename T, int AddrSpace> +/// class AddressSpace { +/// typedef T __attribute__((address_space(AddrSpace))) type; +/// } +/// \endcode +class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + + const ASTContext &Context; + Expr *AddrSpaceExpr; + QualType PointeeType; + SourceLocation loc; + + DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, + QualType can, Expr *AddrSpaceExpr, + SourceLocation loc); + +public: + Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } + QualType getPointeeType() const { return PointeeType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentAddressSpace; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType PointeeType, Expr *AddrSpaceExpr); +}; + /// Represents an extended vector type where either the type or size is /// dependent. /// @@ -2757,17 +2874,19 @@ public: /// } /// \endcode class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + const ASTContext &Context; Expr *SizeExpr; + /// The element type of the array. QualType ElementType; + SourceLocation loc; DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, QualType can, Expr *SizeExpr, SourceLocation loc); - friend class ASTContext; - public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } @@ -2797,14 +2916,28 @@ public: class VectorType : public Type, public llvm::FoldingSetNode { public: enum VectorKind { - GenericVector, ///< not a target-specific vector type - AltiVecVector, ///< is AltiVec vector - AltiVecPixel, ///< is AltiVec 'vector Pixel' - AltiVecBool, ///< is AltiVec 'vector bool ...' - NeonVector, ///< is ARM Neon vector - NeonPolyVector ///< is ARM Neon polynomial vector + /// not a target-specific vector type + GenericVector, + + /// is AltiVec vector + AltiVecVector, + + /// is AltiVec 'vector Pixel' + AltiVecPixel, + + /// is AltiVec 'vector bool ...' + AltiVecBool, + + /// is ARM Neon vector + NeonVector, + + /// is ARM Neon polynomial vector + NeonPolyVector }; + protected: + friend class ASTContext; // ASTContext creates these. + /// The element type of the vector. QualType ElementType; @@ -2814,12 +2947,10 @@ protected: VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); - friend class ASTContext; // ASTContext creates these. - public: - QualType getElementType() const { return ElementType; } unsigned getNumElements() const { return VectorTypeBits.NumElements; } + static bool isVectorSizeTooLarge(unsigned NumElements) { return NumElements > VectorTypeBitfields::MaxNumElements; } @@ -2835,6 +2966,7 @@ public: Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass, VectorKind VecKind) { @@ -2856,9 +2988,11 @@ public: /// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL /// Shading Language). class ExtVectorType : public VectorType { - ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : - VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} - friend class ASTContext; // ASTContext creates these. + friend class ASTContext; // ASTContext creates these. + + ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) + : VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} + public: static int getPointAccessorIdx(char c) { switch (c) { @@ -2869,6 +3003,7 @@ public: case 'w': case 'a': return 3; } } + static int getNumericAccessorIdx(char c) { switch (c) { default: return -1; @@ -2909,6 +3044,7 @@ public: return unsigned(idx-1) < getNumElements(); return false; } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2919,12 +3055,11 @@ public: /// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base /// class of FunctionNoProtoType and FunctionProtoType. -/// class FunctionType : public Type { // The type returned by the function. QualType ResultType; - public: +public: /// A class which abstracts out some details necessary for /// making a call. /// @@ -2946,6 +3081,8 @@ class FunctionType : public Type { // * AST read and write // * Codegen class ExtInfo { + friend class FunctionType; + // Feel free to rearrange or add bits, but if you go over 11, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. @@ -2964,15 +3101,13 @@ class FunctionType : public Type { RegParmOffset = 8 }; // Assumed to be the last field - uint16_t Bits; + uint16_t Bits = CC_C; ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {} - friend class FunctionType; - public: - // Constructor with no defaults. Use this when you know that you - // have all the elements (when reading an AST file for example). + // Constructor with no defaults. Use this when you know that you + // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); @@ -2984,22 +3119,24 @@ class FunctionType : public Type { // Constructor with all defaults. Use when for example creating a // function known to use defaults. - ExtInfo() : Bits(CC_C) { } + ExtInfo() = default; // Constructor with just the calling convention, which is an important part // of the canonical type. - ExtInfo(CallingConv CC) : Bits(CC) { } + ExtInfo(CallingConv CC) : Bits(CC) {} bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } + unsigned getRegParm() const { unsigned RegParm = Bits >> RegParmOffset; if (RegParm > 0) --RegParm; return RegParm; } + CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } bool operator==(ExtInfo Other) const { @@ -3054,11 +3191,12 @@ protected: bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) - : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, - ContainsUnexpandedParameterPack), - ResultType(res) { + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack), + ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; } + unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } public: @@ -3066,10 +3204,12 @@ public: bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + /// Determine whether this function type includes the GNU noreturn /// attribute. The C++11 [[noreturn]] attribute does not affect the function /// type. bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } + CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } bool isConst() const { return getTypeQuals() & Qualifiers::Const; } @@ -3093,13 +3233,13 @@ public: /// Represents a K&R-style 'int foo()' function, which has /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { - FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) - : FunctionType(FunctionNoProto, Result, Canonical, - /*Dependent=*/false, /*InstantiationDependent=*/false, - Result->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false, Info) {} + friend class ASTContext; // ASTContext creates these. - friend class ASTContext; // ASTContext creates these. + FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) + : FunctionType(FunctionNoProto, Result, Canonical, + /*Dependent=*/false, /*InstantiationDependent=*/false, + Result->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false, Info) {} public: // No additional state past what FunctionType provides. @@ -3110,6 +3250,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReturnType(), getExtInfo()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, ExtInfo Info) { Info.Profile(ID); @@ -3152,11 +3293,12 @@ public: ABIMask = 0x0F, IsConsumed = 0x10, HasPassObjSize = 0x20, + IsNoEscape = 0x40, }; - unsigned char Data; + unsigned char Data = 0; public: - ExtParameterInfo() : Data(0) {} + ExtParameterInfo() = default; /// Return the ABI treatment of this parameter. ParameterABI getABI() const { @@ -3192,6 +3334,19 @@ public: 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; @@ -3208,54 +3363,54 @@ public: }; struct ExceptionSpecInfo { - ExceptionSpecInfo() - : Type(EST_None), NoexceptExpr(nullptr), - SourceDecl(nullptr), SourceTemplate(nullptr) {} - - ExceptionSpecInfo(ExceptionSpecificationType EST) - : Type(EST), NoexceptExpr(nullptr), SourceDecl(nullptr), - SourceTemplate(nullptr) {} - /// The kind of exception specification this is. - ExceptionSpecificationType Type; + ExceptionSpecificationType Type = EST_None; + /// Explicitly-specified list of exception types. ArrayRef<QualType> Exceptions; + /// Noexcept expression, if this is EST_ComputedNoexcept. - Expr *NoexceptExpr; + Expr *NoexceptExpr = nullptr; + /// The function whose exception specification this is, for /// EST_Unevaluated and EST_Uninstantiated. - FunctionDecl *SourceDecl; + FunctionDecl *SourceDecl = nullptr; + /// The function template whose exception specification this is instantiated /// from, for EST_Uninstantiated. - FunctionDecl *SourceTemplate; + FunctionDecl *SourceTemplate = nullptr; + + ExceptionSpecInfo() = default; + + ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; /// Extra information about a function prototype. struct ExtProtoInfo { + FunctionType::ExtInfo ExtInfo; + bool Variadic : 1; + bool HasTrailingReturn : 1; + unsigned char TypeQuals = 0; + RefQualifierKind RefQualifier = RQ_None; + ExceptionSpecInfo ExceptionSpec; + const ExtParameterInfo *ExtParameterInfos = nullptr; + ExtProtoInfo() - : Variadic(false), HasTrailingReturn(false), TypeQuals(0), - RefQualifier(RQ_None), ExtParameterInfos(nullptr) {} + : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) - : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0), - RefQualifier(RQ_None), ExtParameterInfos(nullptr) {} + : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) { ExtProtoInfo Result(*this); Result.ExceptionSpec = O; return Result; } - - FunctionType::ExtInfo ExtInfo; - bool Variadic : 1; - bool HasTrailingReturn : 1; - unsigned char TypeQuals; - RefQualifierKind RefQualifier; - ExceptionSpecInfo ExceptionSpec; - const ExtParameterInfo *ExtParameterInfos; }; private: + friend class ASTContext; // ASTContext creates these. + /// \brief Determine whether there are any argument types that /// contain an unexpanded parameter pack. static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, @@ -3307,8 +3462,6 @@ private: // for each of the parameters. This only appears if HasExtParameterInfos // is true. - friend class ASTContext; // ASTContext creates these. - const ExtParameterInfo *getExtParameterInfosBuffer() const { assert(hasExtParameterInfos()); @@ -3336,10 +3489,12 @@ private: public: unsigned getNumParams() const { return NumParams; } + QualType getParamType(unsigned i) const { assert(i < NumParams && "invalid parameter index"); return param_type_begin()[i]; } + ArrayRef<QualType> getParamTypes() const { return llvm::makeArrayRef(param_type_begin(), param_type_end()); } @@ -3371,31 +3526,47 @@ public: ExceptionSpecificationType getExceptionSpecType() const { return static_cast<ExceptionSpecificationType>(ExceptionSpecType); } + /// Return whether this function has any kind of exception spec. bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } + /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { return isDynamicExceptionSpec(getExceptionSpecType()); } + /// Return whether this function has a noexcept exception spec. bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } + /// Return whether this function has a dependent exception spec. bool hasDependentExceptionSpec() const; + /// Return whether this function has an instantiation-dependent exception /// spec. bool hasInstantiationDependentExceptionSpec() const; + /// Result type of getNoexceptSpec(). enum NoexceptResult { - NR_NoNoexcept, ///< There is no noexcept specifier. - NR_BadNoexcept, ///< The noexcept specifier has a bad expression. - NR_Dependent, ///< The noexcept specifier is dependent. - NR_Throw, ///< The noexcept specifier evaluates to false. - NR_Nothrow ///< The noexcept specifier evaluates to true. + /// There is no noexcept specifier. + NR_NoNoexcept, + + /// The noexcept specifier has a bad expression. + NR_BadNoexcept, + + /// The noexcept specifier is dependent. + NR_Dependent, + + /// The noexcept specifier evaluates to false. + NR_Throw, + + /// The noexcept specifier evaluates to true. + NR_Nothrow }; + /// Get the meaning of the noexcept spec on this function, if any. NoexceptResult getNoexceptSpec(const ASTContext &Ctx) const; unsigned getNumExceptions() const { return NumExceptions; } @@ -3409,6 +3580,7 @@ public: // NoexceptExpr sits where the arguments end. return *reinterpret_cast<Expr *const *>(param_type_end()); } + /// \brief If this function type has an exception specification which hasn't /// been determined yet (either because it has not been evaluated or because /// it has not been instantiated), this is the function whose exception @@ -3419,6 +3591,7 @@ public: return nullptr; return reinterpret_cast<FunctionDecl *const *>(param_type_end())[0]; } + /// \brief If this function type has an uninstantiated exception /// specification, this is the function whose exception specification /// should be instantiated to find the exception specification for @@ -3428,9 +3601,11 @@ public: return nullptr; return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1]; } + /// Determine whether this function type has a non-throwing exception /// specification. CanThrowResult canThrow(const ASTContext &Ctx) const; + /// Determine whether this function type has a non-throwing exception /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. @@ -3453,34 +3628,37 @@ public: unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } - /// Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); } - typedef const QualType *param_type_iterator; - typedef llvm::iterator_range<param_type_iterator> param_type_range; + using param_type_iterator = const QualType *; + using param_type_range = llvm::iterator_range<param_type_iterator>; param_type_range param_types() const { return param_type_range(param_type_begin(), param_type_end()); } + param_type_iterator param_type_begin() const { return reinterpret_cast<const QualType *>(this+1); } + param_type_iterator param_type_end() const { return param_type_begin() + NumParams; } - typedef const QualType *exception_iterator; + using exception_iterator = const QualType *; ArrayRef<QualType> exceptions() const { return llvm::makeArrayRef(exception_begin(), exception_end()); } + exception_iterator exception_begin() const { // exceptions begin where arguments end return param_type_end(); } + exception_iterator exception_end() const { if (getExceptionSpecType() != EST_Dynamic) return exception_begin(); @@ -3495,6 +3673,7 @@ public: return ArrayRef<ExtParameterInfo>(getExtParameterInfosBuffer(), getNumParams()); } + /// Return a pointer to the beginning of the array of extra parameter /// information, if present, or else null if none of the parameters /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. @@ -3548,15 +3727,16 @@ public: /// /// Template instantiation turns these into the underlying type. class UnresolvedUsingType : public Type { + friend class ASTContext; // ASTContext creates these. + UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), true, true, false, - /*ContainsUnexpandedParameterPack=*/false), - Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {} - friend class ASTContext; // ASTContext creates these. -public: + : Type(UnresolvedUsing, QualType(), true, true, false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {} +public: UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } @@ -3569,27 +3749,29 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { return Profile(ID, Decl); } + static void Profile(llvm::FoldingSetNodeID &ID, UnresolvedUsingTypenameDecl *D) { ID.AddPointer(D); } }; - class TypedefType : public Type { TypedefNameDecl *Decl; + protected: + friend class ASTContext; // ASTContext creates these. + TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) - : Type(tc, can, can->isDependentType(), - can->isInstantiationDependentType(), - can->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), - Decl(const_cast<TypedefNameDecl*>(D)) { + : Type(tc, can, can->isDependentType(), + can->isInstantiationDependentType(), + can->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<TypedefNameDecl*>(D)) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } - friend class ASTContext; // ASTContext creates these. -public: +public: TypedefNameDecl *getDecl() const { return Decl; } bool isSugared() const { return true; } @@ -3603,8 +3785,10 @@ class TypeOfExprType : public Type { Expr *TOExpr; protected: + friend class ASTContext; // ASTContext creates these. + TypeOfExprType(Expr *E, QualType can = QualType()); - friend class ASTContext; // ASTContext creates these. + public: Expr *getUnderlyingExpr() const { return TOExpr; } @@ -3629,7 +3813,7 @@ class DependentTypeOfExprType public: DependentTypeOfExprType(const ASTContext &Context, Expr *E) - : TypeOfExprType(E), Context(Context) { } + : TypeOfExprType(E), Context(Context) {} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); @@ -3641,16 +3825,19 @@ public: /// Represents `typeof(type)`, a GCC extension. class TypeOfType : public Type { + friend class ASTContext; // ASTContext creates these. + QualType TOType; + TypeOfType(QualType T, QualType can) - : Type(TypeOf, can, T->isDependentType(), - T->isInstantiationDependentType(), - T->isVariablyModifiedType(), - T->containsUnexpandedParameterPack()), - TOType(T) { + : Type(TypeOf, can, T->isDependentType(), + T->isInstantiationDependentType(), + T->isVariablyModifiedType(), + T->containsUnexpandedParameterPack()), + TOType(T) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } - friend class ASTContext; // ASTContext creates these. + public: QualType getUnderlyingType() const { return TOType; } @@ -3669,8 +3856,10 @@ class DecltypeType : public Type { QualType UnderlyingType; protected: + friend class ASTContext; // ASTContext creates these. + DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); - friend class ASTContext; // ASTContext creates these. + public: Expr *getUnderlyingExpr() const { return E; } QualType getUnderlyingType() const { return UnderlyingType; } @@ -3714,14 +3903,18 @@ public: private: /// The untransformed type. QualType BaseType; + /// The transformed type if not dependent, otherwise the same as BaseType. QualType UnderlyingType; UTTKind UKind; + protected: + friend class ASTContext; + UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, QualType CanonicalTy); - friend class ASTContext; + public: bool isSugared() const { return !isDependentType(); } QualType desugar() const { return UnderlyingType; } @@ -3747,6 +3940,7 @@ class DependentUnaryTransformType : public UnaryTransformType, public: DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind); + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), getUTTKind()); } @@ -3759,11 +3953,11 @@ public: }; class TagType : public Type { + friend class ASTReader; + /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. - TagDecl * decl; - - friend class ASTReader; + TagDecl *decl; protected: TagType(TypeClass TC, const TagDecl *D, QualType can); @@ -3783,21 +3977,21 @@ public: /// to detect TagType objects of structs/unions/classes. class RecordType : public TagType { protected: + friend class ASTContext; // ASTContext creates these. + explicit RecordType(const RecordDecl *D) - : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) { } + : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) {} explicit RecordType(TypeClass TC, RecordDecl *D) - : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) { } - friend class ASTContext; // ASTContext creates these. -public: + : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) {} +public: RecordDecl *getDecl() const { return reinterpret_cast<RecordDecl*>(TagType::getDecl()); } - // FIXME: This predicate is a helper to QualType/Type. It needs to - // recursively check all fields for const-ness. If any field is declared - // const, it needs to return false. - bool hasConstFields() const { return false; } + /// Recursively check all fields in the record for const-ness. If any field + /// is declared const, return true. Otherwise, return false. + bool hasConstFields() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -3808,11 +4002,12 @@ public: /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. class EnumType : public TagType { + friend class ASTContext; // ASTContext creates these. + explicit EnumType(const EnumDecl *D) - : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) { } - friend class ASTContext; // ASTContext creates these. -public: + : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) {} +public: EnumDecl *getDecl() const { return reinterpret_cast<EnumDecl*>(TagType::getDecl()); } @@ -3887,11 +4082,11 @@ public: }; private: + friend class ASTContext; // ASTContext creates these + QualType ModifiedType; QualType EquivalentType; - friend class ASTContext; // creates these - AttributedType(QualType canon, Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), @@ -3980,6 +4175,8 @@ public: }; class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + // Helper data collector for canonical types. struct CanonicalTTPTInfo { unsigned Depth : 15; @@ -3990,31 +4187,30 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { union { // Info for the canonical type. CanonicalTTPTInfo CanTTPTInfo; + // Info for the non-canonical type. TemplateTypeParmDecl *TTPDecl; }; /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) - : Type(TemplateTypeParm, Canon, /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - Canon->containsUnexpandedParameterPack()), - TTPDecl(TTPDecl) { } + : Type(TemplateTypeParm, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + Canon->containsUnexpandedParameterPack()), + TTPDecl(TTPDecl) {} /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) - : Type(TemplateTypeParm, QualType(this, 0), - /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, PP) { + : Type(TemplateTypeParm, QualType(this, 0), + /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, PP) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; CanTTPTInfo.ParameterPack = PP; } - friend class ASTContext; // ASTContext creates these - const CanonicalTTPTInfo& getCanTTPTInfo() const { QualType Can = getCanonicalTypeInternal(); return Can->castAs<TemplateTypeParmType>()->CanTTPTInfo; @@ -4060,17 +4256,17 @@ public: /// type was originally written as a template type parameter; /// therefore they are never canonical. class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + // The original type parameter. const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) - : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), - Canon->isInstantiationDependentType(), - Canon->isVariablyModifiedType(), - Canon->containsUnexpandedParameterPack()), - Replaced(Param) { } - - friend class ASTContext; + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), + Canon->isInstantiationDependentType(), + Canon->isVariablyModifiedType(), + Canon->containsUnexpandedParameterPack()), + Replaced(Param) {} public: /// Gets the template parameter that was substituted for. @@ -4090,6 +4286,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacedParameter(), getReplacementType()); } + static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, QualType Replacement) { @@ -4115,6 +4312,8 @@ public: /// arguments), this type will be replaced with the \c SubstTemplateTypeParmType /// at the current pack substitution index. class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; + /// \brief The original type parameter. const TemplateTypeParmType *Replaced; @@ -4129,8 +4328,6 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { QualType Canon, const TemplateArgument &ArgPack); - friend class ASTContext; - public: IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } @@ -4204,6 +4401,8 @@ public: /// \brief Represents a C++11 auto or C++14 decltype(auto) type. class AutoType : public DeducedType, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, bool IsDeducedAsDependent) : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, @@ -4211,12 +4410,11 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode { AutoTypeBits.Keyword = (unsigned)Keyword; } - friend class ASTContext; // ASTContext creates these - public: bool isDecltypeAuto() const { return getKeyword() == AutoTypeKeyword::DecltypeAuto; } + AutoTypeKeyword getKeyword() const { return (AutoTypeKeyword)AutoTypeBits.Keyword; } @@ -4240,6 +4438,8 @@ public: /// \brief Represents a C++17 deduced template specialization type. class DeducedTemplateSpecializationType : public DeducedType, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + /// The name of the template whose arguments will be deduced. TemplateName Template; @@ -4252,8 +4452,6 @@ class DeducedTemplateSpecializationType : public DeducedType, Template.containsUnexpandedParameterPack()), Template(Template) {} - friend class ASTContext; // ASTContext creates these - public: /// Retrieve the name of the template that we are deducing. TemplateName getTemplateName() const { return Template;} @@ -4297,6 +4495,8 @@ public: class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) TemplateSpecializationType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + /// The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a @@ -4318,8 +4518,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) TemplateSpecializationType QualType Canon, QualType Aliased); - friend class ASTContext; // ASTContext creates these - public: /// Determine whether any of the given template arguments are dependent. static bool anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args, @@ -4328,21 +4526,6 @@ public: static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, bool &InstantiationDependent); - /// \brief Print a template argument list, including the '<' and '>' - /// enclosing the template arguments. - static void PrintTemplateArgumentList(raw_ostream &OS, - ArrayRef<TemplateArgument> Args, - const PrintingPolicy &Policy, - bool SkipBrackets = false); - - static void PrintTemplateArgumentList(raw_ostream &OS, - ArrayRef<TemplateArgumentLoc> Args, - const PrintingPolicy &Policy); - - static void PrintTemplateArgumentList(raw_ostream &OS, - const TemplateArgumentListInfo &, - const PrintingPolicy &Policy); - /// True if this template specialization type matches a current /// instantiation in the context in which it is found. bool isCurrentInstantiation() const { @@ -4373,7 +4556,7 @@ public: return *reinterpret_cast<const QualType*>(end()); } - typedef const TemplateArgument * iterator; + using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // defined inline in TemplateBase.h @@ -4400,6 +4583,7 @@ public: bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } + QualType desugar() const { return getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { @@ -4417,6 +4601,20 @@ public: } }; +/// \brief Print a template argument list, including the '<' and '>' +/// enclosing the template arguments. +void printTemplateArgumentList(raw_ostream &OS, + ArrayRef<TemplateArgument> Args, + const PrintingPolicy &Policy); + +void printTemplateArgumentList(raw_ostream &OS, + ArrayRef<TemplateArgumentLoc> Args, + const PrintingPolicy &Policy); + +void printTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy); + /// The injected class name of a C++ class template or class /// template partial specialization. Used to record that a type was /// spelled with a bare identifier rather than as a template-id; the @@ -4435,6 +4633,12 @@ public: /// will canonicalize to the injected class name (when appropriate /// according to the rules of the language). class InjectedClassNameType : public Type { + friend class ASTContext; // ASTContext creates these. + friend class ASTNodeImporter; + friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not + // currently suitable for AST reading, too much + // interdependencies. + CXXRecordDecl *Decl; /// The template specialization which this type represents. @@ -4448,18 +4652,12 @@ class InjectedClassNameType : public Type { /// and always dependent. QualType InjectedType; - friend class ASTContext; // ASTContext creates these. - friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not - // currently suitable for AST reading, too much - // interdependencies. - friend class ASTNodeImporter; - InjectedClassNameType(CXXRecordDecl *D, QualType TST) - : Type(InjectedClassName, QualType(), /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - /*ContainsUnexpandedParameterPack=*/false), - Decl(D), InjectedType(TST) { + : Type(InjectedClassName, QualType(), /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(D), InjectedType(TST) { assert(isa<TemplateSpecializationType>(TST)); assert(!TST.hasQualifiers()); assert(TST->isDependentType()); @@ -4467,9 +4665,11 @@ class InjectedClassNameType : public Type { public: QualType getInjectedSpecializationType() const { return InjectedType; } + const TemplateSpecializationType *getInjectedTST() const { return cast<TemplateSpecializationType>(InjectedType.getTypePtr()); } + TemplateName getTemplateName() const { return getInjectedTST()->getTemplateName(); } @@ -4488,12 +4688,16 @@ public: enum TagTypeKind { /// \brief The "struct" keyword. TTK_Struct, + /// \brief The "__interface" keyword. TTK_Interface, + /// \brief The "union" keyword. TTK_Union, + /// \brief The "class" keyword. TTK_Class, + /// \brief The "enum" keyword. TTK_Enum }; @@ -4503,17 +4707,23 @@ enum TagTypeKind { enum ElaboratedTypeKeyword { /// \brief The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, + /// \brief The "__interface" keyword introduces the elaborated-type-specifier. ETK_Interface, + /// \brief The "union" keyword introduces the elaborated-type-specifier. ETK_Union, + /// \brief The "class" keyword introduces the elaborated-type-specifier. ETK_Class, + /// \brief The "enum" keyword introduces the elaborated-type-specifier. ETK_Enum, + /// \brief The "typename" keyword precedes the qualified type name, e.g., /// \c typename T::type. ETK_Typename, + /// \brief No keyword precedes the qualified type name. ETK_None }; @@ -4528,8 +4738,8 @@ protected: QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) - : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, - ContainsUnexpandedParameterPack) { + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack) { TypeWithKeywordBits.Keyword = Keyword; } @@ -4574,6 +4784,7 @@ public: /// The type itself is always "sugar", used to express what was written /// in the source code but containing no additional semantic information. class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; @@ -4594,8 +4805,6 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { "and name qualifier both null."); } - friend class ASTContext; // ASTContext creates these - public: ~ElaboratedType(); @@ -4640,6 +4849,7 @@ public: /// mode, this type is used with non-dependent names to delay name lookup until /// instantiation. class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these /// \brief The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; @@ -4649,13 +4859,11 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) - : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - NNS->containsUnexpandedParameterPack()), - NNS(NNS), Name(Name) {} - - friend class ASTContext; // ASTContext creates these + : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + NNS->containsUnexpandedParameterPack()), + NNS(NNS), Name(Name) {} public: /// Retrieve the qualification on this type. @@ -4695,6 +4903,7 @@ public: class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; @@ -4706,20 +4915,19 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentTemplateSpecializationType /// specialization. unsigned NumArgs; - const TemplateArgument *getArgBuffer() const { - return reinterpret_cast<const TemplateArgument*>(this+1); - } - TemplateArgument *getArgBuffer() { - return reinterpret_cast<TemplateArgument*>(this+1); - } - DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args, QualType Canon); - friend class ASTContext; // ASTContext creates these + const TemplateArgument *getArgBuffer() const { + return reinterpret_cast<const TemplateArgument*>(this+1); + } + + TemplateArgument *getArgBuffer() { + return reinterpret_cast<TemplateArgument*>(this+1); + } public: NestedNameSpecifier *getQualifier() const { return NNS; } @@ -4739,7 +4947,8 @@ public: return {getArgs(), NumArgs}; } - typedef const TemplateArgument * iterator; + using iterator = const TemplateArgument *; + iterator begin() const { return getArgs(); } iterator end() const; // inline in TemplateBase.h @@ -4785,6 +4994,8 @@ public: /// Here, the pack expansion \c Types&... is represented via a /// PackExpansionType whose pattern is Types&. class PackExpansionType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these + /// \brief The pattern of the pack expansion. QualType Pattern; @@ -4798,14 +5009,12 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode { PackExpansionType(QualType Pattern, QualType Canon, Optional<unsigned> NumExpansions) - : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), - /*InstantiationDependent=*/true, - /*VariablyModified=*/Pattern->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), - Pattern(Pattern), - NumExpansions(NumExpansions? *NumExpansions + 1: 0) { } - - friend class ASTContext; // ASTContext creates these + : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), + /*InstantiationDependent=*/true, + /*VariablyModified=*/Pattern->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Pattern(Pattern), + NumExpansions(NumExpansions ? *NumExpansions + 1 : 0) {} public: /// \brief Retrieve the pattern of this pack expansion, which is the @@ -4847,7 +5056,8 @@ public: template <class T> class ObjCProtocolQualifiers { protected: - ObjCProtocolQualifiers() {} + ObjCProtocolQualifiers() = default; + ObjCProtocolDecl * const *getProtocolStorage() const { return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage(); } @@ -4855,9 +5065,11 @@ protected: ObjCProtocolDecl **getProtocolStorage() { return static_cast<T*>(this)->getProtocolStorageImpl(); } + void setNumProtocols(unsigned N) { static_cast<T*>(this)->setNumProtocolsImpl(N); } + void initialize(ArrayRef<ObjCProtocolDecl *> protocols) { setNumProtocols(protocols.size()); assert(getNumProtocols() == protocols.size() && @@ -4868,8 +5080,8 @@ protected: } public: - typedef ObjCProtocolDecl * const *qual_iterator; - typedef llvm::iterator_range<qual_iterator> qual_range; + using qual_iterator = ObjCProtocolDecl * const *; + using qual_range = llvm::iterator_range<qual_iterator>; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getProtocolStorage(); } @@ -4907,21 +5119,26 @@ class ObjCTypeParamType : public Type, unsigned NumProtocols : 6; ObjCTypeParamDecl *OTPDecl; + /// The protocols are stored after the ObjCTypeParamType node. In the /// canonical type, the list of protocols are sorted alphabetically /// and uniqued. ObjCProtocolDecl **getProtocolStorageImpl(); + /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return NumProtocols; } + void setNumProtocolsImpl(unsigned N) { NumProtocols = N; } + ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef<ObjCProtocolDecl *> protocols); + public: bool isSugared() const { return true; } QualType desugar() const { return getCanonicalTypeInternal(); } @@ -4969,6 +5186,7 @@ public: class ObjCObjectType : public Type, public ObjCProtocolQualifiers<ObjCObjectType> { friend class ObjCProtocolQualifiers<ObjCObjectType>; + // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. // ObjCObjectType.NumProtocols - the number of protocols stored @@ -5004,15 +5222,16 @@ class ObjCObjectType : public Type, } protected: + enum Nonce_ObjCInterface { Nonce_ObjCInterface }; + ObjCObjectType(QualType Canonical, QualType Base, ArrayRef<QualType> typeArgs, ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf); - enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), - BaseType(QualType(this_(), 0)) { + BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; ObjCObjectTypeBits.NumTypeArgs = 0; ObjCObjectTypeBits.IsKindOf = 0; @@ -5032,9 +5251,11 @@ public: bool isObjCId() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); } + bool isObjCClass() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); } + bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } bool isObjCUnqualifiedIdOrClass() const { @@ -5125,7 +5346,7 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { ArrayRef<QualType> typeArgs, ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf) - : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} + : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} public: void Profile(llvm::FoldingSetNodeID &ID); @@ -5163,14 +5384,15 @@ inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { /// - It is its own base type. That is, if T is an ObjCInterfaceType*, /// T->getBaseType() == QualType(T, 0). class ObjCInterfaceType : public ObjCObjectType { + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; + friend class ObjCInterfaceDecl; + mutable ObjCInterfaceDecl *Decl; ObjCInterfaceType(const ObjCInterfaceDecl *D) - : ObjCObjectType(Nonce_ObjCInterface), - Decl(const_cast<ObjCInterfaceDecl*>(D)) {} - friend class ASTContext; // ASTContext creates these. - friend class ASTReader; - friend class ObjCInterfaceDecl; + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast<ObjCInterfaceDecl*>(D)) {} public: /// Get the declaration of this interface. @@ -5218,16 +5440,17 @@ inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { /// Pointers to pointers to Objective C objects are still PointerTypes; /// only the first level of pointer gets it own type implementation. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, - Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), - PointeeType(Pointee) {} - friend class ASTContext; // ASTContext creates these. + : Type(ObjCObjectPointer, Canonical, + Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) {} public: /// Gets the type pointed to by this ObjC pointer. @@ -5336,16 +5559,19 @@ public: /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. - typedef ObjCObjectType::qual_iterator qual_iterator; - typedef llvm::iterator_range<qual_iterator> qual_range; + using qual_iterator = ObjCObjectType::qual_iterator; + using qual_range = llvm::iterator_range<qual_iterator>; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } + qual_iterator qual_begin() const { return getObjectType()->qual_begin(); } + qual_iterator qual_end() const { return getObjectType()->qual_end(); } + bool qual_empty() const { return getObjectType()->qual_empty(); } /// Return the number of qualifying protocols on the object type. @@ -5377,26 +5603,29 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } + static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } }; class AtomicType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType ValueType; AtomicType(QualType ValTy, QualType Canonical) - : Type(Atomic, Canonical, ValTy->isDependentType(), - ValTy->isInstantiationDependentType(), - ValTy->isVariablyModifiedType(), - ValTy->containsUnexpandedParameterPack()), - ValueType(ValTy) {} - friend class ASTContext; // ASTContext creates these. + : Type(Atomic, Canonical, ValTy->isDependentType(), + ValTy->isInstantiationDependentType(), + ValTy->isVariablyModifiedType(), + ValTy->containsUnexpandedParameterPack()), + ValueType(ValTy) {} - public: +public: /// Gets the type contained by this atomic type, i.e. /// the type returned by performing an atomic load of this atomic type. QualType getValueType() const { return ValueType; } @@ -5407,9 +5636,11 @@ class AtomicType : public Type, public llvm::FoldingSetNode { void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getValueType()); } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } + static bool classof(const Type *T) { return T->getTypeClass() == Atomic; } @@ -5417,16 +5648,17 @@ class AtomicType : public Type, public llvm::FoldingSetNode { /// PipeType - OpenCL20. class PipeType : public Type, public llvm::FoldingSetNode { + friend class ASTContext; // ASTContext creates these. + QualType ElementType; bool isRead; - PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) : - Type(Pipe, CanonicalPtr, elemType->isDependentType(), - elemType->isInstantiationDependentType(), - elemType->isVariablyModifiedType(), - elemType->containsUnexpandedParameterPack()), - ElementType(elemType), isRead(isRead) {} - friend class ASTContext; // ASTContext creates these. + PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) + : Type(Pipe, CanonicalPtr, elemType->isDependentType(), + elemType->isInstantiationDependentType(), + elemType->isVariablyModifiedType(), + elemType->containsUnexpandedParameterPack()), + ElementType(elemType), isRead(isRead) {} public: QualType getElementType() const { return ElementType; } @@ -5476,7 +5708,6 @@ public: QualType apply(const ASTContext &Context, const Type* T) const; }; - // Inline function definitions. inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { @@ -5602,7 +5833,7 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { } /// Return the address space of this type. -inline unsigned QualType::getAddressSpace() const { +inline LangAS QualType::getAddressSpace() const { return getQualifiers().getAddressSpace(); } @@ -5709,88 +5940,117 @@ inline bool Type::isCompoundType() const { inline bool Type::isFunctionType() const { return isa<FunctionType>(CanonicalType); } + inline bool Type::isPointerType() const { return isa<PointerType>(CanonicalType); } + inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } + inline bool Type::isBlockPointerType() const { return isa<BlockPointerType>(CanonicalType); } + inline bool Type::isReferenceType() const { return isa<ReferenceType>(CanonicalType); } + inline bool Type::isLValueReferenceType() const { return isa<LValueReferenceType>(CanonicalType); } + inline bool Type::isRValueReferenceType() const { return isa<RValueReferenceType>(CanonicalType); } + inline bool Type::isFunctionPointerType() const { if (const PointerType *T = getAs<PointerType>()) return T->getPointeeType()->isFunctionType(); else return false; } + inline bool Type::isMemberPointerType() const { return isa<MemberPointerType>(CanonicalType); } + inline bool Type::isMemberFunctionPointerType() const { if (const MemberPointerType* T = getAs<MemberPointerType>()) return T->isMemberFunctionPointer(); else return false; } + inline bool Type::isMemberDataPointerType() const { if (const MemberPointerType* T = getAs<MemberPointerType>()) return T->isMemberDataPointer(); else return false; } + inline bool Type::isArrayType() const { return isa<ArrayType>(CanonicalType); } + inline bool Type::isConstantArrayType() const { return isa<ConstantArrayType>(CanonicalType); } + inline bool Type::isIncompleteArrayType() const { return isa<IncompleteArrayType>(CanonicalType); } + inline bool Type::isVariableArrayType() const { return isa<VariableArrayType>(CanonicalType); } + inline bool Type::isDependentSizedArrayType() const { return isa<DependentSizedArrayType>(CanonicalType); } + inline bool Type::isBuiltinType() const { return isa<BuiltinType>(CanonicalType); } + inline bool Type::isRecordType() const { return isa<RecordType>(CanonicalType); } + inline bool Type::isEnumeralType() const { return isa<EnumType>(CanonicalType); } + inline bool Type::isAnyComplexType() const { return isa<ComplexType>(CanonicalType); } + inline bool Type::isVectorType() const { return isa<VectorType>(CanonicalType); } + inline bool Type::isExtVectorType() const { return isa<ExtVectorType>(CanonicalType); } + +inline bool Type::isDependentAddressSpaceType() const { + return isa<DependentAddressSpaceType>(CanonicalType); +} + inline bool Type::isObjCObjectPointerType() const { return isa<ObjCObjectPointerType>(CanonicalType); } + inline bool Type::isObjCObjectType() const { return isa<ObjCObjectType>(CanonicalType); } + inline bool Type::isObjCObjectOrInterfaceType() const { return isa<ObjCInterfaceType>(CanonicalType) || isa<ObjCObjectType>(CanonicalType); } + inline bool Type::isAtomicType() const { return isa<AtomicType>(CanonicalType); } @@ -5800,26 +6060,31 @@ inline bool Type::isObjCQualifiedIdType() const { return OPT->isObjCQualifiedIdType(); return false; } + inline bool Type::isObjCQualifiedClassType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) return OPT->isObjCQualifiedClassType(); return false; } + inline bool Type::isObjCIdType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) return OPT->isObjCIdType(); return false; } + inline bool Type::isObjCClassType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) return OPT->isObjCClassType(); return false; } + inline bool Type::isObjCSelType() const { if (const PointerType *OPT = getAs<PointerType>()) return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); return false; } + inline bool Type::isObjCBuiltinType() const { return isObjCIdType() || isObjCClassType() || isObjCSelType(); } @@ -5854,7 +6119,7 @@ inline bool Type::isImageType() const { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || return #include "clang/Basic/OpenCLImageTypes.def" - 0; // end boolean or operation + false; // end boolean or operation } inline bool Type::isPipeType() const { @@ -6133,7 +6398,6 @@ QualType DecayedType::getPointeeType() const { return cast<PointerType>(Decayed)->getPointeeType(); } +} // namespace clang -} // end namespace clang - -#endif +#endif // LLVM_CLANG_AST_TYPE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h index ad95f6f8effaa..b805160a27807 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h @@ -1,4 +1,4 @@ -//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- C++ -*-===// +//===- TypeLoc.h - Type Source Info Wrapper ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,26 +6,42 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::TypeLoc interface and its subclasses. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPELOC_H #define LLVM_CLANG_AST_TYPELOC_H #include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> namespace clang { - class ASTContext; - class ParmVarDecl; - class TypeSourceInfo; - class UnqualTypeLoc; + +class ASTContext; +class CXXRecordDecl; +class Expr; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class ObjCTypeParamDecl; +class TemplateTypeParmDecl; +class UnqualTypeLoc; +class UnresolvedUsingTypenameDecl; // Predeclare all the type nodes. #define ABSTRACT_TYPELOC(Class, Base) @@ -41,10 +57,16 @@ class TypeLoc { protected: // The correctness of this relies on the property that, for Type *Ty, // QualType(Ty, 0).getAsOpaquePtr() == (void*) Ty - const void *Ty; - void *Data; + const void *Ty = nullptr; + void *Data = nullptr; public: + TypeLoc() = default; + TypeLoc(QualType ty, void *opaqueData) + : Ty(ty.getAsOpaquePtr()), Data(opaqueData) {} + TypeLoc(const Type *ty, void *opaqueData) + : Ty(ty), Data(opaqueData) {} + /// \brief Convert to the specified TypeLoc type, asserting that this TypeLoc /// is of the desired type. /// @@ -88,12 +110,6 @@ public: Qualified }; - TypeLoc() : Ty(nullptr), Data(nullptr) { } - TypeLoc(QualType ty, void *opaqueData) - : Ty(ty.getAsOpaquePtr()), Data(opaqueData) { } - TypeLoc(const Type *ty, void *opaqueData) - : Ty(ty), Data(opaqueData) { } - TypeLocClass getTypeLocClass() const { if (getType().hasLocalQualifiers()) return Qualified; return (TypeLocClass) getType()->getTypeClass(); @@ -134,6 +150,7 @@ public: SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getBeginLoc(), getEndLoc()); } + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } @@ -228,7 +245,7 @@ inline TypeLoc TypeSourceInfo::getTypeLoc() const { /// no direct qualifiers. class UnqualTypeLoc : public TypeLoc { public: - UnqualTypeLoc() {} + UnqualTypeLoc() = default; UnqualTypeLoc(const Type *Ty, void *Data) : TypeLoc(Ty, Data) {} const Type *getTypePtr() const { @@ -241,6 +258,7 @@ public: private: friend class TypeLoc; + static bool isKind(const TypeLoc &TL) { return !TL.getType().hasLocalQualifiers(); } @@ -253,9 +271,7 @@ private: /// type qualifiers. class QualifiedTypeLoc : public TypeLoc { public: - SourceRange getLocalSourceRange() const { - return SourceRange(); - } + SourceRange getLocalSourceRange() const { return {}; } UnqualTypeLoc getUnqualifiedLoc() const { unsigned align = @@ -296,6 +312,7 @@ public: private: friend class TypeLoc; + static bool isKind(const TypeLoc &TL) { return TL.getType().hasLocalQualifiers(); } @@ -337,12 +354,12 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const { /// InheritingConcreteTypeLoc instead. template <class Base, class Derived, class TypeClass, class LocalData> class ConcreteTypeLoc : public Base { + friend class TypeLoc; const Derived *asDerived() const { return static_cast<const Derived*>(this); } - friend class TypeLoc; static bool isKind(const TypeLoc &TL) { return !TL.getType().hasLocalQualifiers() && Derived::classofType(TL.getTypePtr()); @@ -357,6 +374,7 @@ public: return std::max(unsigned(alignof(LocalData)), asDerived()->getExtraLocalDataAlignment()); } + unsigned getLocalDataSize() const { unsigned size = sizeof(LocalData); unsigned extraAlign = asDerived()->getExtraLocalDataAlignment(); @@ -449,9 +467,7 @@ private: return TypeLoc::getLocalAlignmentForType(T); } - TypeLoc getNextTypeLoc(HasNoInnerType _) const { - return TypeLoc(); - } + TypeLoc getNextTypeLoc(HasNoInnerType _) const { return {}; } TypeLoc getNextTypeLoc(QualType T) const { return TypeLoc(T, getNonLocalData()); @@ -464,6 +480,7 @@ private: template <class Base, class Derived, class TypeClass> class InheritingConcreteTypeLoc : public Base { friend class TypeLoc; + static bool classofType(const Type *Ty) { return TypeClass::classof(Ty); } @@ -482,7 +499,6 @@ public: } }; - struct TypeSpecLocInfo { SourceLocation NameLoc; }; @@ -502,22 +518,25 @@ public: SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } + void setNameLoc(SourceLocation Loc) { this->getLocalData()->NameLoc = Loc; } + SourceRange getLocalSourceRange() const { return SourceRange(getNameLoc(), getNameLoc()); } + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); } private: friend class TypeLoc; + static bool isKind(const TypeLoc &TL); }; - struct BuiltinLocInfo { SourceRange BuiltinRange; }; @@ -531,9 +550,11 @@ public: SourceLocation getBuiltinLoc() const { return getLocalData()->BuiltinRange.getBegin(); } + void setBuiltinLoc(SourceLocation Loc) { getLocalData()->BuiltinRange = Loc; } + void expandBuiltinRange(SourceRange Range) { SourceRange &BuiltinRange = getLocalData()->BuiltinRange; if (!BuiltinRange.getBegin().isValid()) { @@ -579,9 +600,11 @@ public: else return TSS_unspecified; } + bool hasWrittenSignSpec() const { return getWrittenSignSpec() != TSS_unspecified; } + void setWrittenSignSpec(TypeSpecifierSign written) { if (needsExtraLocalData()) getWrittenBuiltinSpecs().Sign = written; @@ -593,18 +616,22 @@ public: else return TSW_unspecified; } + bool hasWrittenWidthSpec() const { return getWrittenWidthSpec() != TSW_unspecified; } + void setWrittenWidthSpec(TypeSpecifierWidth written) { if (needsExtraLocalData()) getWrittenBuiltinSpecs().Width = written; } TypeSpecifierType getWrittenTypeSpec() const; + bool hasWrittenTypeSpec() const { return getWrittenTypeSpec() != TST_unspecified; } + void setWrittenTypeSpec(TypeSpecifierType written) { if (needsExtraLocalData()) getWrittenBuiltinSpecs().Type = written; @@ -616,6 +643,7 @@ public: else return false; } + void setModeAttr(bool written) { if (needsExtraLocalData()) getWrittenBuiltinSpecs().ModeAttr = written; @@ -633,7 +661,6 @@ public: } }; - /// \brief Wrapper for source info for typedefs. class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, TypedefTypeLoc, @@ -742,6 +769,7 @@ public: *((SourceLocation*)this->getExtraLocalData()) : SourceLocation(); } + void setProtocolLAngleLoc(SourceLocation Loc) { *((SourceLocation*)this->getExtraLocalData()) = Loc; } @@ -751,6 +779,7 @@ public: *((SourceLocation*)this->getExtraLocalData() + 1) : SourceLocation(); } + void setProtocolRAngleLoc(SourceLocation Loc) { *((SourceLocation*)this->getExtraLocalData() + 1) = Loc; } @@ -763,6 +792,7 @@ public: assert(i < getNumProtocols() && "Index is out of bounds!"); return getProtocolLocArray()[i]; } + void setProtocolLoc(unsigned i, SourceLocation Loc) { assert(i < getNumProtocols() && "Index is out of bounds!"); getProtocolLocArray()[i] = Loc; @@ -785,9 +815,11 @@ public: // as well. return (this->getNumProtocols() + 2) * sizeof(SourceLocation) ; } + unsigned getExtraLocalDataAlignment() const { return alignof(SourceLocation); } + SourceRange getLocalSourceRange() const { SourceLocation start = getNameLoc(); SourceLocation end = getProtocolRAngleLoc(); @@ -938,7 +970,6 @@ public: } }; - struct ObjCObjectTypeLocInfo { SourceLocation TypeArgsLAngleLoc; SourceLocation TypeArgsRAngleLoc; @@ -971,6 +1002,7 @@ public: SourceLocation getTypeArgsLAngleLoc() const { return this->getLocalData()->TypeArgsLAngleLoc; } + void setTypeArgsLAngleLoc(SourceLocation Loc) { this->getLocalData()->TypeArgsLAngleLoc = Loc; } @@ -978,6 +1010,7 @@ public: SourceLocation getTypeArgsRAngleLoc() const { return this->getLocalData()->TypeArgsRAngleLoc; } + void setTypeArgsRAngleLoc(SourceLocation Loc) { this->getLocalData()->TypeArgsRAngleLoc = Loc; } @@ -999,6 +1032,7 @@ public: SourceLocation getProtocolLAngleLoc() const { return this->getLocalData()->ProtocolLAngleLoc; } + void setProtocolLAngleLoc(SourceLocation Loc) { this->getLocalData()->ProtocolLAngleLoc = Loc; } @@ -1006,6 +1040,7 @@ public: SourceLocation getProtocolRAngleLoc() const { return this->getLocalData()->ProtocolRAngleLoc; } + void setProtocolRAngleLoc(SourceLocation Loc) { this->getLocalData()->ProtocolRAngleLoc = Loc; } @@ -1018,6 +1053,7 @@ public: assert(i < getNumProtocols() && "Index is out of bounds!"); return getProtocolLocArray()[i]; } + void setProtocolLoc(unsigned i, SourceLocation Loc) { assert(i < getNumProtocols() && "Index is out of bounds!"); getProtocolLocArray()[i] = Loc; @@ -1073,7 +1109,6 @@ public: } }; - struct ObjCInterfaceLocInfo { SourceLocation NameLoc; SourceLocation NameEndLoc; @@ -1127,12 +1162,15 @@ public: SourceLocation getLParenLoc() const { return this->getLocalData()->LParenLoc; } + SourceLocation getRParenLoc() const { return this->getLocalData()->RParenLoc; } + void setLParenLoc(SourceLocation Loc) { this->getLocalData()->LParenLoc = Loc; } + void setRParenLoc(SourceLocation Loc) { this->getLocalData()->RParenLoc = Loc; } @@ -1161,8 +1199,7 @@ inline TypeLoc TypeLoc::IgnoreParens() const { return *this; } - -struct AdjustedLocInfo { }; // Nothing. +struct AdjustedLocInfo {}; // Nothing. class AdjustedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AdjustedTypeLoc, AdjustedType, AdjustedLocInfo> { @@ -1181,9 +1218,7 @@ public: return getTypePtr()->getOriginalType(); } - SourceRange getLocalSourceRange() const { - return SourceRange(); - } + SourceRange getLocalSourceRange() const { return {}; } unsigned getLocalDataSize() const { // sizeof(AdjustedLocInfo) is 1, but we don't need its address to be unique @@ -1210,6 +1245,7 @@ public: SourceLocation getSigilLoc() const { return this->getLocalData()->StarLoc; } + void setSigilLoc(SourceLocation Loc) { this->getLocalData()->StarLoc = Loc; } @@ -1231,7 +1267,6 @@ public: } }; - /// \brief Wrapper for source info for pointers. class PointerTypeLoc : public PointerLikeTypeLoc<PointerTypeLoc, PointerType> { @@ -1239,12 +1274,12 @@ public: SourceLocation getStarLoc() const { return getSigilLoc(); } + void setStarLoc(SourceLocation Loc) { setSigilLoc(Loc); } }; - /// \brief Wrapper for source info for block pointers. class BlockPointerTypeLoc : public PointerLikeTypeLoc<BlockPointerTypeLoc, BlockPointerType> { @@ -1252,6 +1287,7 @@ public: SourceLocation getCaretLoc() const { return getSigilLoc(); } + void setCaretLoc(SourceLocation Loc) { setSigilLoc(Loc); } @@ -1269,6 +1305,7 @@ public: SourceLocation getStarLoc() const { return getSigilLoc(); } + void setStarLoc(SourceLocation Loc) { setSigilLoc(Loc); } @@ -1276,9 +1313,11 @@ public: const Type *getClass() const { return getTypePtr()->getClass(); } + TypeSourceInfo *getClassTInfo() const { return getLocalData()->ClassTInfo; } + void setClassTInfo(TypeSourceInfo* TI) { getLocalData()->ClassTInfo = TI; } @@ -1310,7 +1349,6 @@ public: } }; - class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc, ReferenceType> { public: @@ -1327,6 +1365,7 @@ public: SourceLocation getAmpLoc() const { return getSigilLoc(); } + void setAmpLoc(SourceLocation Loc) { setSigilLoc(Loc); } @@ -1340,12 +1379,12 @@ public: SourceLocation getAmpAmpLoc() const { return getSigilLoc(); } + void setAmpAmpLoc(SourceLocation Loc) { setSigilLoc(Loc); } }; - struct FunctionLocInfo { SourceLocation LocalRangeBegin; SourceLocation LParenLoc; @@ -1371,10 +1410,12 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, // exception specification information. return (SourceRange *)(getParmArray() + getNumParams()); } + public: SourceLocation getLocalRangeBegin() const { return getLocalData()->LocalRangeBegin; } + void setLocalRangeBegin(SourceLocation L) { getLocalData()->LocalRangeBegin = L; } @@ -1382,6 +1423,7 @@ public: SourceLocation getLocalRangeEnd() const { return getLocalData()->LocalRangeEnd; } + void setLocalRangeEnd(SourceLocation L) { getLocalData()->LocalRangeEnd = L; } @@ -1389,6 +1431,7 @@ public: SourceLocation getLParenLoc() const { return this->getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { this->getLocalData()->LParenLoc = Loc; } @@ -1396,6 +1439,7 @@ public: SourceLocation getRParenLoc() const { return this->getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { this->getLocalData()->RParenLoc = Loc; } @@ -1407,8 +1451,9 @@ public: SourceRange getExceptionSpecRange() const { if (hasExceptionSpec()) return *getExceptionSpecRangePtr(); - return SourceRange(); + return {}; } + void setExceptionSpecRange(SourceRange R) { if (hasExceptionSpec()) *getExceptionSpecRangePtr() = R; @@ -1428,6 +1473,7 @@ public: return 0; return cast<FunctionProtoType>(getTypePtr())->getNumParams(); } + ParmVarDecl *getParam(unsigned i) const { return getParmArray()[i]; } void setParam(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; } @@ -1474,7 +1520,6 @@ class FunctionNoProtoTypeLoc : FunctionNoProtoType> { }; - struct ArrayLocInfo { SourceLocation LBracketLoc, RBracketLoc; Expr *Size; @@ -1489,6 +1534,7 @@ public: SourceLocation getLBracketLoc() const { return getLocalData()->LBracketLoc; } + void setLBracketLoc(SourceLocation Loc) { getLocalData()->LBracketLoc = Loc; } @@ -1496,6 +1542,7 @@ public: SourceLocation getRBracketLoc() const { return getLocalData()->RBracketLoc; } + void setRBracketLoc(SourceLocation Loc) { getLocalData()->RBracketLoc = Loc; } @@ -1507,6 +1554,7 @@ public: Expr *getSizeExpr() const { return getLocalData()->Size; } + void setSizeExpr(Expr *Size) { getLocalData()->Size = Size; } @@ -1557,7 +1605,6 @@ class VariableArrayTypeLoc : VariableArrayType> { }; - // Location information for a TemplateName. Rudimentary for now. struct TemplateNameLocInfo { SourceLocation NameLoc; @@ -1578,6 +1625,7 @@ public: SourceLocation getTemplateKeywordLoc() const { return getLocalData()->TemplateKWLoc; } + void setTemplateKeywordLoc(SourceLocation Loc) { getLocalData()->TemplateKWLoc = Loc; } @@ -1585,6 +1633,7 @@ public: SourceLocation getLAngleLoc() const { return getLocalData()->LAngleLoc; } + void setLAngleLoc(SourceLocation Loc) { getLocalData()->LAngleLoc = Loc; } @@ -1592,6 +1641,7 @@ public: SourceLocation getRAngleLoc() const { return getLocalData()->RAngleLoc; } + void setRAngleLoc(SourceLocation Loc) { getLocalData()->RAngleLoc = Loc; } @@ -1599,9 +1649,11 @@ public: unsigned getNumArgs() const { return getTypePtr()->getNumArgs(); } + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { getArgInfos()[i] = AI; } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { return getArgInfos()[i]; } @@ -1613,6 +1665,7 @@ public: SourceLocation getTemplateNameLoc() const { return getLocalData()->NameLoc; } + void setTemplateNameLoc(SourceLocation Loc) { getLocalData()->NameLoc = Loc; } @@ -1664,6 +1717,74 @@ private: } }; +struct DependentAddressSpaceLocInfo { + Expr *ExprOperand; + SourceRange OperandParens; + SourceLocation AttrLoc; +}; + +class DependentAddressSpaceTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, + DependentAddressSpaceTypeLoc, + DependentAddressSpaceType, + DependentAddressSpaceLocInfo> { +public: + /// The location of the attribute name, i.e. + /// int * __attribute__((address_space(11))) + /// ^~~~~~~~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// int * __attribute__((address_space(11))) + /// ^~ + Expr *getAttrExprOperand() const { + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + getLocalData()->ExprOperand = e; + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// int * __attribute__((address_space(11))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + SourceRange range(getAttrNameLoc()); + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + /// Returns the type before the address space attribute application + /// area. + /// int * __attribute__((address_space(11))) * + /// ^ ^ + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } + + TypeLoc getPointeeTypeLoc() const { + return this->getInnerTypeLoc(); + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(getTypePtr()->getAddrSpaceExpr()); + } +}; + //===----------------------------------------------------------------------===// // // All of these need proper implementations. @@ -1717,6 +1838,7 @@ public: SourceLocation getTypeofLoc() const { return this->getLocalData()->TypeofLoc; } + void setTypeofLoc(SourceLocation Loc) { this->getLocalData()->TypeofLoc = Loc; } @@ -1724,6 +1846,7 @@ public: SourceLocation getLParenLoc() const { return this->getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { this->getLocalData()->LParenLoc = Loc; } @@ -1731,6 +1854,7 @@ public: SourceLocation getRParenLoc() const { return this->getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { this->getLocalData()->RParenLoc = Loc; } @@ -1738,6 +1862,7 @@ public: SourceRange getParensRange() const { return SourceRange(getLParenLoc(), getRParenLoc()); } + void setParensRange(SourceRange range) { setLParenLoc(range.getBegin()); setRParenLoc(range.getEnd()); @@ -1761,6 +1886,7 @@ public: Expr* getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); } + // Reimplemented to account for GNU/C++ extension // typeof unary-expression // where there are no parentheses. @@ -1773,9 +1899,11 @@ public: QualType getUnderlyingType() const { return this->getTypePtr()->getUnderlyingType(); } + TypeSourceInfo* getUnderlyingTInfo() const { return this->getLocalData()->UnderlyingTInfo; } + void setUnderlyingTInfo(TypeSourceInfo* TI) const { this->getLocalData()->UnderlyingTInfo = TI; } @@ -1815,6 +1943,7 @@ public: TypeSourceInfo* getUnderlyingTInfo() const { return getLocalData()->UnderlyingTInfo; } + void setUnderlyingTInfo(TypeSourceInfo *TInfo) { getLocalData()->UnderlyingTInfo = TInfo; } @@ -1826,16 +1955,13 @@ public: SourceRange getParensRange() const { return SourceRange(getLParenLoc(), getRParenLoc()); } + void setParensRange(SourceRange Range) { setLParenLoc(Range.getBegin()); setRParenLoc(Range.getEnd()); } - void initializeLocal(ASTContext &Context, SourceLocation Loc) { - setKWLoc(Loc); - setRParenLoc(Loc); - setLParenLoc(Loc); - } + void initializeLocal(ASTContext &Context, SourceLocation Loc); }; class DeducedTypeLoc @@ -1854,6 +1980,7 @@ public: SourceLocation getTemplateNameLoc() const { return getNameLoc(); } + void setTemplateNameLoc(SourceLocation Loc) { setNameLoc(Loc); } @@ -1861,6 +1988,7 @@ public: struct ElaboratedLocInfo { SourceLocation ElaboratedKWLoc; + /// \brief Data associated with the nested-name-specifier location. void *QualifierData; }; @@ -1873,6 +2001,7 @@ public: SourceLocation getElaboratedKeywordLoc() const { return this->getLocalData()->ElaboratedKWLoc; } + void setElaboratedKeywordLoc(SourceLocation Loc) { this->getLocalData()->ElaboratedKWLoc = Loc; } @@ -1931,6 +2060,7 @@ public: SourceLocation getElaboratedKeywordLoc() const { return this->getLocalData()->ElaboratedKWLoc; } + void setElaboratedKeywordLoc(SourceLocation Loc) { this->getLocalData()->ElaboratedKWLoc = Loc; } @@ -1950,6 +2080,7 @@ public: SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } + void setNameLoc(SourceLocation Loc) { this->getLocalData()->NameLoc = Loc; } @@ -1986,6 +2117,7 @@ public: SourceLocation getElaboratedKeywordLoc() const { return this->getLocalData()->ElaboratedKWLoc; } + void setElaboratedKeywordLoc(SourceLocation Loc) { this->getLocalData()->ElaboratedKWLoc = Loc; } @@ -2017,6 +2149,7 @@ public: SourceLocation getTemplateKeywordLoc() const { return getLocalData()->TemplateKWLoc; } + void setTemplateKeywordLoc(SourceLocation Loc) { getLocalData()->TemplateKWLoc = Loc; } @@ -2024,6 +2157,7 @@ public: SourceLocation getTemplateNameLoc() const { return this->getLocalData()->NameLoc; } + void setTemplateNameLoc(SourceLocation Loc) { this->getLocalData()->NameLoc = Loc; } @@ -2031,6 +2165,7 @@ public: SourceLocation getLAngleLoc() const { return this->getLocalData()->LAngleLoc; } + void setLAngleLoc(SourceLocation Loc) { this->getLocalData()->LAngleLoc = Loc; } @@ -2038,6 +2173,7 @@ public: SourceLocation getRAngleLoc() const { return this->getLocalData()->RAngleLoc; } + void setRAngleLoc(SourceLocation Loc) { this->getLocalData()->RAngleLoc = Loc; } @@ -2049,6 +2185,7 @@ public: void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { getArgInfos()[i] = AI; } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { return getArgInfos()[i]; } @@ -2090,7 +2227,6 @@ private: } }; - struct PackExpansionTypeLocInfo { SourceLocation EllipsisLoc; }; @@ -2142,6 +2278,7 @@ public: SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; } @@ -2149,6 +2286,7 @@ public: SourceLocation getLParenLoc() const { return this->getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { this->getLocalData()->LParenLoc = Loc; } @@ -2156,6 +2294,7 @@ public: SourceLocation getRParenLoc() const { return this->getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { this->getLocalData()->RParenLoc = Loc; } @@ -2163,6 +2302,7 @@ public: SourceRange getParensRange() const { return SourceRange(getLParenLoc(), getRParenLoc()); } + void setParensRange(SourceRange Range) { setLParenLoc(Range.getBegin()); setRParenLoc(Range.getEnd()); @@ -2217,6 +2357,7 @@ inline T TypeLoc::getAsAdjusted() const { } return Cur.getAs<T>(); } -} -#endif +} // namespace clang + +#endif // LLVM_CLANG_AST_TYPELOC_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def index 9d1d09e2cc661..66697fa0d0faf 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def +++ b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def @@ -23,7 +23,7 @@ // NON_CANONICAL_TYPE(Class, Base) - A type that can show up // anywhere in the AST but will never be a part of a canonical // type. Clients that only need to deal with canonical types -// (ignoring, e.g., typedefs and other type alises used for +// (ignoring, e.g., typedefs and other type aliases used for // pretty-printing) can ignore these types. // // DEPENDENT_TYPE(Class, Base) - A type that will only show up @@ -73,6 +73,7 @@ TYPE(IncompleteArray, ArrayType) TYPE(VariableArray, ArrayType) DEPENDENT_TYPE(DependentSizedArray, ArrayType) DEPENDENT_TYPE(DependentSizedExtVector, Type) +DEPENDENT_TYPE(DependentAddressSpace, Type) TYPE(Vector, Type) TYPE(ExtVector, VectorType) ABSTRACT_TYPE(Function, Type) diff --git a/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h b/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h index b63c6eb217697..614ff9bf2efda 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h +++ b/contrib/llvm/tools/clang/include/clang/AST/UnresolvedSet.h @@ -1,4 +1,4 @@ -//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +//===- UnresolvedSet.h - Unresolved sets of declarations --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,20 +17,25 @@ #include "clang/AST/DeclAccessPair.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/Specifiers.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator.h" +#include <cstddef> +#include <iterator> namespace clang { +class NamedDecl; + /// The iterator over UnresolvedSets. Serves as both the const and /// non-const iterator. class UnresolvedSetIterator : public llvm::iterator_adaptor_base< UnresolvedSetIterator, DeclAccessPair *, std::random_access_iterator_tag, NamedDecl *, std::ptrdiff_t, NamedDecl *, NamedDecl *> { - friend class UnresolvedSetImpl; friend class ASTUnresolvedSet; friend class OverloadExpr; + friend class UnresolvedSetImpl; explicit UnresolvedSetIterator(DeclAccessPair *Iter) : iterator_adaptor_base(Iter) {} @@ -54,12 +59,13 @@ public: /// \brief A set of unresolved declarations. class UnresolvedSetImpl { - typedef SmallVectorImpl<DeclAccessPair> DeclsTy; + using DeclsTy = SmallVectorImpl<DeclAccessPair>; // Don't allow direct construction, and only permit subclassing by // UnresolvedSet. private: template <unsigned N> friend class UnresolvedSet; + UnresolvedSetImpl() = default; UnresolvedSetImpl(const UnresolvedSetImpl &) = default; UnresolvedSetImpl &operator=(const UnresolvedSetImpl &) = default; @@ -71,8 +77,8 @@ private: public: // We don't currently support assignment through this iterator, so we might // as well use the same implementation twice. - typedef UnresolvedSetIterator iterator; - typedef UnresolvedSetIterator const_iterator; + using iterator = UnresolvedSetIterator; + using const_iterator = UnresolvedSetIterator; iterator begin() { return iterator(decls().begin()); } iterator end() { return iterator(decls().end()); } @@ -140,7 +146,7 @@ template <unsigned InlineCapacity> class UnresolvedSet : SmallVector<DeclAccessPair, InlineCapacity> Decls; }; - + } // namespace clang -#endif +#endif // LLVM_CLANG_AST_UNRESOLVEDSET_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h b/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h index b4a6fe3bdb942..178139477d001 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h +++ b/contrib/llvm/tools/clang/include/clang/AST/VTTBuilder.h @@ -1,4 +1,4 @@ -//===--- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-=// +//===- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,25 +16,31 @@ #define LLVM_CLANG_AST_VTTBUILDER_H #include "clang/AST/BaseSubobject.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/GlobalDecl.h" -#include "clang/AST/RecordLayout.h" -#include "clang/Basic/ABI.h" -#include <utility> +#include "clang/AST/CharUnits.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include <cstdint> namespace clang { +class ASTContext; +class ASTRecordLayout; +class CXXRecordDecl; + class VTTVTable { llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> BaseAndIsVirtual; CharUnits BaseOffset; public: - VTTVTable() {} + VTTVTable() = default; VTTVTable(const CXXRecordDecl *Base, CharUnits BaseOffset, bool BaseIsVirtual) - : BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {} + : BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {} VTTVTable(BaseSubobject Base, bool BaseIsVirtual) - : BaseAndIsVirtual(Base.getBase(), BaseIsVirtual), - BaseOffset(Base.getBaseOffset()) {} + : BaseAndIsVirtual(Base.getBase(), BaseIsVirtual), + BaseOffset(Base.getBaseOffset()) {} const CXXRecordDecl *getBase() const { return BaseAndIsVirtual.getPointer(); @@ -57,25 +63,24 @@ struct VTTComponent { uint64_t VTableIndex; BaseSubobject VTableBase; - VTTComponent() {} + VTTComponent() = default; VTTComponent(uint64_t VTableIndex, BaseSubobject VTableBase) - : VTableIndex(VTableIndex), VTableBase(VTableBase) {} + : VTableIndex(VTableIndex), VTableBase(VTableBase) {} }; /// \brief Class for building VTT layout information. class VTTBuilder { - ASTContext &Ctx; /// \brief The most derived class for which we're building this vtable. const CXXRecordDecl *MostDerivedClass; - typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy; + using VTTVTablesVectorTy = SmallVector<VTTVTable, 64>; /// \brief The VTT vtables. VTTVTablesVectorTy VTTVTables; - typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy; + using VTTComponentsVectorTy = SmallVector<VTTComponent, 64>; /// \brief The VTT components. VTTComponentsVectorTy VTTComponents; @@ -83,9 +88,9 @@ class VTTBuilder { /// \brief The AST record layout of the most derived class. const ASTRecordLayout &MostDerivedClassLayout; - typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + using VisitedVirtualBasesSetTy = llvm::SmallPtrSet<const CXXRecordDecl *, 4>; - typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + using AddressPointsMapTy = llvm::DenseMap<BaseSubobject, uint64_t>; /// \brief The sub-VTT indices for the bases of the most derived class. llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; @@ -153,9 +158,8 @@ public: getSecondaryVirtualPointerIndices() const { return SecondaryVirtualPointerIndices; } - }; -} +} // namespace clang -#endif +#endif // LLVM_CLANG_AST_VTTBUILDER_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h index c9b496df33f7c..64e7e908d51ed 100644 --- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1,4 +1,4 @@ -//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===// +//===- ASTMatchers.h - Structural query framework ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,7 +25,7 @@ // // For example, when we're interested in child classes of a certain class, we // would write: -// cxxRecordDecl(hasName("MyClass"), hasChild(id("child", recordDecl()))) +// cxxRecordDecl(hasName("MyClass"), has(id("child", recordDecl()))) // When the match is found via the MatchFinder, a user provided callback will // be called with a BoundNodes instance that contains a mapping from the // strings that we provided for the id(...) calls to the nodes that were @@ -46,13 +46,48 @@ #define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" +#include <cassert> +#include <cstddef> #include <iterator> +#include <limits> +#include <string> +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { @@ -78,7 +113,7 @@ public: /// \brief Type of mapping from binding identifiers to bound nodes. This type /// is an associative container with a key type of \c std::string and a value /// type of \c clang::ast_type_traits::DynTypedNode - typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap; + using IDToNodeMap = internal::BoundNodesMap::IDToNodeMap; /// \brief Retrieve mapping from binding identifiers to bound nodes. const IDToNodeMap &getMap() const { @@ -86,13 +121,13 @@ public: } private: + friend class internal::BoundNodesTreeBuilder; + /// \brief Create BoundNodes from a pre-filled map of bindings. BoundNodes(internal::BoundNodesMap &MyBoundNodes) : MyBoundNodes(MyBoundNodes) {} internal::BoundNodesMap MyBoundNodes; - - friend class internal::BoundNodesTreeBuilder; }; /// \brief If the provided matcher matches a node, binds the node to \c ID. @@ -107,13 +142,13 @@ internal::Matcher<T> id(StringRef ID, /// \brief Types of matchers for the top-level classes in the AST class /// hierarchy. /// @{ -typedef internal::Matcher<Decl> DeclarationMatcher; -typedef internal::Matcher<Stmt> StatementMatcher; -typedef internal::Matcher<QualType> TypeMatcher; -typedef internal::Matcher<TypeLoc> TypeLocMatcher; -typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher; -typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher; -typedef internal::Matcher<CXXCtorInitializer> CXXCtorInitializerMatcher; +using DeclarationMatcher = internal::Matcher<Decl>; +using StatementMatcher = internal::Matcher<Stmt>; +using TypeMatcher = internal::Matcher<QualType>; +using TypeLocMatcher = internal::Matcher<TypeLoc>; +using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>; +using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>; +using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>; /// @} /// \brief Matches any node. @@ -143,7 +178,7 @@ inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } /// \endcode /// decl(hasDeclContext(translationUnitDecl())) /// matches "int X", but not "int Y". -const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl> translationUnitDecl; /// \brief Matches typedef declarations. @@ -155,7 +190,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl> /// \endcode /// typedefDecl() /// matches "typedef int X", but not "using Y = int" -const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> + typedefDecl; /// \brief Matches typedef name declarations. /// @@ -166,7 +202,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; /// \endcode /// typedefNameDecl() /// matches "typedef int X" and "using Y = int" -const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> typedefNameDecl; /// \brief Matches type alias declarations. @@ -178,7 +214,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> /// \endcode /// typeAliasDecl() /// matches "using Y = int", but not "typedef int X" -const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> + typeAliasDecl; /// \brief Matches type alias template declarations. /// @@ -187,7 +224,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl; /// template <typename T> /// using Y = X<T>; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl> typeAliasTemplateDecl; /// \brief Matches AST nodes that were expanded within the main-file. @@ -278,7 +315,7 @@ AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching, /// friend X; /// }; /// \endcode -const internal::VariadicAllOfMatcher<Decl> decl; +extern const internal::VariadicAllOfMatcher<Decl> decl; /// \brief Matches a declaration of a linkage specification. /// @@ -288,7 +325,7 @@ const internal::VariadicAllOfMatcher<Decl> decl; /// \endcode /// linkageSpecDecl() /// matches "extern "C" {}" -const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> linkageSpecDecl; /// \brief Matches a declaration of anything that could have a name. @@ -302,7 +339,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> /// } U; /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl; /// \brief Matches a declaration of label. /// @@ -313,7 +350,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl; /// \endcode /// labelDecl() /// matches 'FOO:' -const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl; /// \brief Matches a declaration of a namespace. /// @@ -324,7 +361,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl; /// \endcode /// namespaceDecl() /// matches "namespace {}" and "namespace test {}" -const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl> namespaceDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl> + namespaceDecl; /// \brief Matches a declaration of a namespace alias. /// @@ -335,7 +373,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl> namespaceDecl; /// \endcode /// namespaceAliasDecl() /// matches "namespace alias" but not "namespace test" -const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl> namespaceAliasDecl; /// \brief Matches class, struct, and union declarations. @@ -347,9 +385,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl> /// struct S {}; /// union U {}; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - RecordDecl> recordDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, RecordDecl> recordDecl; /// \brief Matches C++ class declarations. /// @@ -358,9 +394,8 @@ const internal::VariadicDynCastAllOfMatcher< /// class X; /// template<class T> class Z {}; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - CXXRecordDecl> cxxRecordDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXRecordDecl> + cxxRecordDecl; /// \brief Matches C++ class template declarations. /// @@ -368,9 +403,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// template<class T> class Z {}; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ClassTemplateDecl> classTemplateDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ClassTemplateDecl> + classTemplateDecl; /// \brief Matches C++ class template specializations. /// @@ -382,9 +416,9 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// classTemplateSpecializationDecl() /// matches the specializations \c A<int> and \c A<double> -const internal::VariadicDynCastAllOfMatcher< - Decl, - ClassTemplateSpecializationDecl> classTemplateSpecializationDecl; +extern const internal::VariadicDynCastAllOfMatcher< + Decl, ClassTemplateSpecializationDecl> + classTemplateSpecializationDecl; /// \brief Matches declarator declarations (field, variable, function /// and non-type template parameter declarations). @@ -395,7 +429,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// declaratorDecl() /// matches \c int y. -const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> declaratorDecl; /// \brief Matches parameter variable declarations. @@ -406,7 +440,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> /// \endcode /// parmVarDecl() /// matches \c int x. -const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> + parmVarDecl; /// \brief Matches C++ access specifier declarations. /// @@ -419,9 +454,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; /// \endcode /// accessSpecDecl() /// matches 'public:' -const internal::VariadicDynCastAllOfMatcher< - Decl, - AccessSpecDecl> accessSpecDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl> + accessSpecDecl; /// \brief Matches constructor initializers. /// @@ -432,7 +466,8 @@ const internal::VariadicDynCastAllOfMatcher< /// int i; /// }; /// \endcode -const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; +extern const internal::VariadicAllOfMatcher<CXXCtorInitializer> + cxxCtorInitializer; /// \brief Matches template arguments. /// @@ -443,7 +478,7 @@ const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; /// \endcode /// templateArgument() /// matches 'int' in C<int>. -const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; +extern const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; /// \brief Matches template name. /// @@ -454,7 +489,7 @@ const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; /// \endcode /// templateName() /// matches 'X' in X<int>. -const internal::VariadicAllOfMatcher<TemplateName> templateName; +extern const internal::VariadicAllOfMatcher<TemplateName> templateName; /// \brief Matches non-type template parameter declarations. /// @@ -464,9 +499,9 @@ const internal::VariadicAllOfMatcher<TemplateName> templateName; /// \endcode /// nonTypeTemplateParmDecl() /// matches 'N', but not 'T'. -const internal::VariadicDynCastAllOfMatcher< - Decl, - NonTypeTemplateParmDecl> nonTypeTemplateParmDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, + NonTypeTemplateParmDecl> + nonTypeTemplateParmDecl; /// \brief Matches template type parameter declarations. /// @@ -476,9 +511,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// templateTypeParmDecl() /// matches 'T', but not 'N'. -const internal::VariadicDynCastAllOfMatcher< - Decl, - TemplateTypeParmDecl> templateTypeParmDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTypeParmDecl> + templateTypeParmDecl; /// \brief Matches public C++ declarations. /// @@ -582,6 +616,23 @@ AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>, InnerMatcher.matches(*Initializer, Finder, Builder)); } +/// \brief Matches the specialized template of a specialization declaration. +/// +/// Given +/// \code +/// tempalate<typename T> class A {}; +/// typedef A<int> B; +/// \endcode +/// classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl())) +/// matches 'B' with classTemplateDecl() matching the class template +/// declaration of 'A'. +AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate, + internal::Matcher<ClassTemplateDecl>, InnerMatcher) { + const ClassTemplateDecl* Decl = Node.getSpecializedTemplate(); + return (Decl != nullptr && + InnerMatcher.matches(*Decl, Finder, Builder)); +} + /// \brief Matches a declaration that has been implicitly added /// by the compiler (eg. implicit default/copy constructors). AST_MATCHER(Decl, isImplicit) { @@ -922,7 +973,7 @@ AST_MATCHER_P(TemplateArgument, equalsIntegralValue, /// enum X { A, B, C }; /// void F(); /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; /// \brief Matches C++ constructor declarations. /// @@ -935,9 +986,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; /// int DoSomething(); /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - CXXConstructorDecl> cxxConstructorDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl> + cxxConstructorDecl; /// \brief Matches explicit C++ destructor declarations. /// @@ -948,9 +998,8 @@ const internal::VariadicDynCastAllOfMatcher< /// virtual ~Foo(); /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - CXXDestructorDecl> cxxDestructorDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl> + cxxDestructorDecl; /// \brief Matches enum declarations. /// @@ -960,7 +1009,7 @@ const internal::VariadicDynCastAllOfMatcher< /// A, B, C /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; /// \brief Matches enum constants. /// @@ -970,9 +1019,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; /// A, B, C /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - EnumConstantDecl> enumConstantDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, EnumConstantDecl> + enumConstantDecl; /// \brief Matches method declarations. /// @@ -980,7 +1028,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// class X { void y(); }; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> + cxxMethodDecl; /// \brief Matches conversion operator declarations. /// @@ -988,7 +1037,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; /// \code /// class X { operator int() const; }; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> +extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> cxxConversionDecl; /// \brief Matches variable declarations. @@ -1000,7 +1049,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> /// \code /// int a; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; /// \brief Matches field declarations. /// @@ -1010,7 +1059,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; /// \endcode /// fieldDecl() /// matches 'm'. -const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; /// \brief Matches function declarations. /// @@ -1018,7 +1067,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; /// \code /// void f(); /// \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> functionDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> + functionDecl; /// \brief Matches C++ function template declarations. /// @@ -1026,9 +1076,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> functionDecl; /// \code /// template<class T> void f(T t) {} /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - FunctionTemplateDecl> functionTemplateDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, FunctionTemplateDecl> + functionTemplateDecl; /// \brief Matches friend declarations. /// @@ -1038,7 +1087,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// friendDecl() /// matches 'friend void foo()'. -const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; /// \brief Matches statements. /// @@ -1048,7 +1097,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; /// \endcode /// stmt() /// matches both the compound statement '{ ++a; }' and '++a'. -const internal::VariadicAllOfMatcher<Stmt> stmt; +extern const internal::VariadicAllOfMatcher<Stmt> stmt; /// \brief Matches declaration statements. /// @@ -1058,9 +1107,7 @@ const internal::VariadicAllOfMatcher<Stmt> stmt; /// \endcode /// declStmt() /// matches 'int a'. -const internal::VariadicDynCastAllOfMatcher< - Stmt, - DeclStmt> declStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclStmt> declStmt; /// \brief Matches member expressions. /// @@ -1073,7 +1120,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// memberExpr() /// matches this->x, x, y.x, a, this->b -const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr; /// \brief Matches call expressions. /// @@ -1083,7 +1130,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr; /// x.y(); /// y(); /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; /// \brief Matches lambda expressions. /// @@ -1091,7 +1138,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; /// \code /// [&](){return 5;} /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr; /// \brief Matches member call expressions. /// @@ -1100,9 +1147,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr; /// X x; /// x.y(); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXMemberCallExpr> cxxMemberCallExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr> + cxxMemberCallExpr; /// \brief Matches ObjectiveC Message invocation expressions. /// @@ -1113,9 +1159,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// [[NSString alloc] initWithString:@"Hello"] /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ObjCMessageExpr> objcMessageExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCMessageExpr> + objcMessageExpr; /// \brief Matches Objective-C interface declarations. /// @@ -1124,9 +1169,18 @@ const internal::VariadicDynCastAllOfMatcher< /// @interface Foo /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCInterfaceDecl> objcInterfaceDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCInterfaceDecl> + objcInterfaceDecl; + +/// \brief Matches Objective-C implementation declarations. +/// +/// Example matches Foo +/// \code +/// @implementation Foo +/// @end +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCImplementationDecl> + objcImplementationDecl; /// \brief Matches Objective-C protocol declarations. /// @@ -1135,9 +1189,8 @@ const internal::VariadicDynCastAllOfMatcher< /// @protocol FooDelegate /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCProtocolDecl> objcProtocolDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCProtocolDecl> + objcProtocolDecl; /// \brief Matches Objective-C category declarations. /// @@ -1146,9 +1199,18 @@ const internal::VariadicDynCastAllOfMatcher< /// @interface Foo (Additions) /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCCategoryDecl> objcCategoryDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryDecl> + objcCategoryDecl; + +/// \brief Matches Objective-C category definitions. +/// +/// Example matches Foo (Additions) +/// \code +/// @implementation Foo (Additions) +/// @end +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryImplDecl> + objcCategoryImplDecl; /// \brief Matches Objective-C method declarations. /// @@ -1162,9 +1224,8 @@ const internal::VariadicDynCastAllOfMatcher< /// - (void)method {} /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCMethodDecl> objcMethodDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCMethodDecl> + objcMethodDecl; /// \brief Matches Objective-C instance variable declarations. /// @@ -1175,9 +1236,8 @@ const internal::VariadicDynCastAllOfMatcher< /// } /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCIvarDecl> objcIvarDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCIvarDecl> + objcIvarDecl; /// \brief Matches Objective-C property declarations. /// @@ -1187,9 +1247,47 @@ const internal::VariadicDynCastAllOfMatcher< /// @property BOOL enabled; /// @end /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - ObjCPropertyDecl> objcPropertyDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, ObjCPropertyDecl> + objcPropertyDecl; + +/// \brief Matches Objective-C \@throw statements. +/// +/// Example matches \@throw +/// \code +/// @throw obj; +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtThrowStmt> + objcThrowStmt; + +/// \brief Matches Objective-C @try statements. +/// +/// Example matches @try +/// \code +/// @try {} +/// @catch (...) {} +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtTryStmt> + objcTryStmt; + +/// \brief Matches Objective-C @catch statements. +/// +/// Example matches @catch +/// \code +/// @try {} +/// @catch (...) {} +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtCatchStmt> + objcCatchStmt; + +/// \brief Matches Objective-C @finally statements. +/// +/// Example matches @finally +/// \code +/// @try {} +/// @finally {} +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtFinallyStmt> + objcFinallyStmt; /// \brief Matches expressions that introduce cleanups to be run at the end /// of the sub-expression's evaluation. @@ -1198,9 +1296,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// const std::string str = std::string(); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ExprWithCleanups> exprWithCleanups; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExprWithCleanups> + exprWithCleanups; /// \brief Matches init list expressions. /// @@ -1212,7 +1309,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// initListExpr() /// matches "{ 1, 2 }" and "{ 5, 6 }" -const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> + initListExpr; /// \brief Matches the syntactic form of init list expressions /// (if expression have it). @@ -1234,8 +1332,9 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm, /// \endcode /// cxxStdInitializerListExpr() /// matches "{ 1, 2, 3 }" and "{ 4, 5 }" -const internal::VariadicDynCastAllOfMatcher<Stmt, - CXXStdInitializerListExpr> cxxStdInitializerListExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + CXXStdInitializerListExpr> + cxxStdInitializerListExpr; /// \brief Matches implicit initializers of init list expressions. /// @@ -1245,8 +1344,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, /// \endcode /// implicitValueInitExpr() /// matches "[0].y" (implicitly) -const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr> -implicitValueInitExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr> + implicitValueInitExpr; /// \brief Matches paren list expressions. /// ParenListExprs don't have a predefined type and are used for late parsing. @@ -1263,7 +1362,8 @@ implicitValueInitExpr; /// \endcode /// parenListExpr() matches "*this" but NOT matches (a, b) because (a, b) /// has a predefined type and is a ParenExpr, not a ParenListExpr. -const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> parenListExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> + parenListExpr; /// \brief Matches substitutions of non-type template parameters. /// @@ -1275,9 +1375,9 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> parenListExpr; /// \endcode /// substNonTypeTemplateParmExpr() /// matches "N" in the right-hand side of "static const int n = N;" -const internal::VariadicDynCastAllOfMatcher< - Stmt, - SubstNonTypeTemplateParmExpr> substNonTypeTemplateParmExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + SubstNonTypeTemplateParmExpr> + substNonTypeTemplateParmExpr; /// \brief Matches using declarations. /// @@ -1288,7 +1388,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// usingDecl() /// matches \code using X::x \endcode -const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; /// \brief Matches using namespace declarations. /// @@ -1299,9 +1399,8 @@ const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; /// \endcode /// usingDirectiveDecl() /// matches \code using namespace X \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - UsingDirectiveDecl> usingDirectiveDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDirectiveDecl> + usingDirectiveDecl; /// \brief Matches reference to a name that can be looked up during parsing /// but could not be resolved to a specific declaration. @@ -1317,9 +1416,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// unresolvedLookupExpr() /// matches \code foo<T>() \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - UnresolvedLookupExpr> unresolvedLookupExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedLookupExpr> + unresolvedLookupExpr; /// \brief Matches unresolved using value declarations. /// @@ -1332,9 +1430,9 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// unresolvedUsingValueDecl() /// matches \code using X::x \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - UnresolvedUsingValueDecl> unresolvedUsingValueDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, + UnresolvedUsingValueDecl> + unresolvedUsingValueDecl; /// \brief Matches unresolved using value declarations that involve the /// typename. @@ -1351,9 +1449,9 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// unresolvedUsingTypenameDecl() /// matches \code using Base<T>::Foo \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - UnresolvedUsingTypenameDecl> unresolvedUsingTypenameDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, + UnresolvedUsingTypenameDecl> + unresolvedUsingTypenameDecl; /// \brief Matches parentheses used in expressions. /// @@ -1362,9 +1460,7 @@ const internal::VariadicDynCastAllOfMatcher< /// int foo() { return 1; } /// int a = (foo() + 1); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ParenExpr> parenExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ParenExpr> parenExpr; /// \brief Matches constructor call expressions (including implicit ones). /// @@ -1376,9 +1472,8 @@ const internal::VariadicDynCastAllOfMatcher< /// int n; /// f(string(ptr, n), ptr); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXConstructExpr> cxxConstructExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstructExpr> + cxxConstructExpr; /// \brief Matches unresolved constructor call expressions. /// @@ -1388,9 +1483,9 @@ const internal::VariadicDynCastAllOfMatcher< /// template <typename T> /// void f(const T& t) { return T(t); } /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXUnresolvedConstructExpr> cxxUnresolvedConstructExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + CXXUnresolvedConstructExpr> + cxxUnresolvedConstructExpr; /// \brief Matches implicit and explicit this expressions. /// @@ -1402,7 +1497,8 @@ const internal::VariadicDynCastAllOfMatcher< /// int f() { return i; } /// }; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> cxxThisExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> + cxxThisExpr; /// \brief Matches nodes where temporaries are created. /// @@ -1412,9 +1508,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> cxxThisExpr; /// FunctionTakesString(GetStringByValue()); /// FunctionTakesStringByPointer(GetStringPointer()); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXBindTemporaryExpr> cxxBindTemporaryExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBindTemporaryExpr> + cxxBindTemporaryExpr; /// \brief Matches nodes where temporaries are materialized. /// @@ -1434,9 +1529,9 @@ const internal::VariadicDynCastAllOfMatcher< /// f(); /// f().func(); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - MaterializeTemporaryExpr> materializeTemporaryExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + MaterializeTemporaryExpr> + materializeTemporaryExpr; /// \brief Matches new expressions. /// @@ -1446,7 +1541,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode /// cxxNewExpr() /// matches 'new X'. -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; /// \brief Matches delete expressions. /// @@ -1456,7 +1551,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; /// \endcode /// cxxDeleteExpr() /// matches 'delete X'. -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> + cxxDeleteExpr; /// \brief Matches array subscript expressions. /// @@ -1466,9 +1562,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr; /// \endcode /// arraySubscriptExpr() /// matches "a[1]" -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ArraySubscriptExpr> arraySubscriptExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArraySubscriptExpr> + arraySubscriptExpr; /// \brief Matches the value of a default argument at the call site. /// @@ -1479,9 +1574,8 @@ const internal::VariadicDynCastAllOfMatcher< /// void f(int x, int y = 0); /// f(42); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXDefaultArgExpr> cxxDefaultArgExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr> + cxxDefaultArgExpr; /// \brief Matches overloaded operator calls. /// @@ -1497,9 +1591,8 @@ const internal::VariadicDynCastAllOfMatcher< /// ostream &o; int b = 1, c = 1; /// o << b << c; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXOperatorCallExpr> cxxOperatorCallExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr> + cxxOperatorCallExpr; /// \brief Matches expressions. /// @@ -1507,7 +1600,7 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// void f() { x(); } /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; /// \brief Matches expressions that refer to declarations. /// @@ -1516,7 +1609,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; /// bool x; /// if (x) {} /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> + declRefExpr; /// \brief Matches if statements. /// @@ -1524,7 +1618,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr; /// \code /// if (x) {} /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt; /// \brief Matches for statements. /// @@ -1533,7 +1627,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt; /// for (;;) {} /// int i[] = {1, 2, 3}; for (auto a : i); /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt; /// \brief Matches the increment statement of a for loop. /// @@ -1571,9 +1665,8 @@ AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>, /// int i[] = {1, 2, 3}; for (auto a : i); /// for(int j = 0; j < 5; ++j); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXForRangeStmt> cxxForRangeStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXForRangeStmt> + cxxForRangeStmt; /// \brief Matches the initialization statement of a for loop. /// @@ -1611,7 +1704,7 @@ AST_MATCHER_P(CXXForRangeStmt, hasRangeInit, internal::Matcher<Expr>, /// \endcode /// whileStmt() /// matches 'while (true) {}'. -const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt; /// \brief Matches do statements. /// @@ -1621,7 +1714,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt; /// \endcode /// doStmt() /// matches 'do {} while(true)' -const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt; /// \brief Matches break statements. /// @@ -1631,7 +1724,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt; /// \endcode /// breakStmt() /// matches 'break' -const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt; /// \brief Matches continue statements. /// @@ -1641,7 +1734,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt; /// \endcode /// continueStmt() /// matches 'continue' -const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> continueStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> + continueStmt; /// \brief Matches return statements. /// @@ -1651,7 +1745,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> continueStmt; /// \endcode /// returnStmt() /// matches 'return 1' -const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt; /// \brief Matches goto statements. /// @@ -1662,7 +1756,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt; /// \endcode /// gotoStmt() /// matches 'goto FOO' -const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt; /// \brief Matches label statements. /// @@ -1673,7 +1767,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt; /// \endcode /// labelStmt() /// matches 'FOO:' -const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt; /// \brief Matches address of label statements (GNU extension). /// @@ -1685,7 +1779,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt; /// \endcode /// addrLabelExpr() /// matches '&&FOO' -const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr> addrLabelExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr> + addrLabelExpr; /// \brief Matches switch statements. /// @@ -1695,7 +1790,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr> addrLabelExpr; /// \endcode /// switchStmt() /// matches 'switch(a)'. -const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; /// \brief Matches case and default statements inside switch statements. /// @@ -1705,7 +1800,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; /// \endcode /// switchCase() /// matches 'case 42: break;' and 'default: break;'. -const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; /// \brief Matches case statements inside switch statements. /// @@ -1715,7 +1810,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; /// \endcode /// caseStmt() /// matches 'case 42: break;'. -const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; /// \brief Matches default statements inside switch statements. /// @@ -1725,7 +1820,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; /// \endcode /// defaultStmt() /// matches 'default: break;'. -const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> + defaultStmt; /// \brief Matches compound statements. /// @@ -1733,7 +1829,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt; /// \code /// for (;;) {{}} /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> compoundStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> + compoundStmt; /// \brief Matches catch statements. /// @@ -1742,7 +1839,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> compoundStmt; /// \endcode /// cxxCatchStmt() /// matches 'catch(int i)' -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> cxxCatchStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> + cxxCatchStmt; /// \brief Matches try statements. /// @@ -1751,7 +1849,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> cxxCatchStmt; /// \endcode /// cxxTryStmt() /// matches 'try {}' -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; /// \brief Matches throw expressions. /// @@ -1760,7 +1858,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; /// \endcode /// cxxThrowExpr() /// matches 'throw 5' -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> + cxxThrowExpr; /// \brief Matches null statements. /// @@ -1769,7 +1868,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; /// \endcode /// nullStmt() /// matches the second ';' -const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; /// \brief Matches asm statements. /// @@ -1779,7 +1878,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; /// \endcode /// asmStmt() /// matches '__asm("mov al, 2")' -const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; /// \brief Matches bool literals. /// @@ -1787,9 +1886,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; /// \code /// true /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXBoolLiteralExpr> cxxBoolLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBoolLiteralExpr> + cxxBoolLiteral; /// \brief Matches string literals (also matches wide string literals). /// @@ -1798,9 +1896,8 @@ const internal::VariadicDynCastAllOfMatcher< /// char *s = "abcd"; /// wchar_t *ws = L"abcd"; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - StringLiteral> stringLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral> + stringLiteral; /// \brief Matches character literals (also matches wchar_t). /// @@ -1812,17 +1909,15 @@ const internal::VariadicDynCastAllOfMatcher< /// char ch = 'a'; /// wchar_t chw = L'a'; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CharacterLiteral> characterLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CharacterLiteral> + characterLiteral; /// \brief Matches integer literals of all sizes / encodings, e.g. /// 1, 1L, 0x1 and 1U. /// /// Does not match character-encoded integers such as L'a'. -const internal::VariadicDynCastAllOfMatcher< - Stmt, - IntegerLiteral> integerLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, IntegerLiteral> + integerLiteral; /// \brief Matches float literals of all sizes / encodings, e.g. /// 1.0, 1.0f, 1.0L and 1e10. @@ -1831,16 +1926,14 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// float a = 10; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - FloatingLiteral> floatLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, FloatingLiteral> + floatLiteral; /// \brief Matches user defined literal operator call. /// /// Example match: "foo"_suffix -const internal::VariadicDynCastAllOfMatcher< - Stmt, - UserDefinedLiteral> userDefinedLiteral; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral> + userDefinedLiteral; /// \brief Matches compound (i.e. non-scalar) literals /// @@ -1849,24 +1942,23 @@ const internal::VariadicDynCastAllOfMatcher< /// int array[4] = {1}; /// vector int myvec = (vector int)(1, 2); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CompoundLiteralExpr> compoundLiteralExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr> + compoundLiteralExpr; /// \brief Matches nullptr literal. -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXNullPtrLiteralExpr> cxxNullPtrLiteralExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr> + cxxNullPtrLiteralExpr; /// \brief Matches GNU __null expression. -const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> gnuNullExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> + gnuNullExpr; /// \brief Matches atomic builtins. /// Example matches __atomic_load_n(ptr, 1) /// \code /// void foo() { int *ptr; __atomic_load_n(ptr, 1); } /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr; /// \brief Matches statement expression (GNU extension). /// @@ -1874,7 +1966,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr; /// \code /// int C = ({ int X = 4; X; }); /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr; /// \brief Matches binary operator expressions. /// @@ -1882,9 +1974,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr; /// \code /// !(a || b) /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - BinaryOperator> binaryOperator; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryOperator> + binaryOperator; /// \brief Matches unary operator expressions. /// @@ -1892,9 +1983,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// !a || b /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - UnaryOperator> unaryOperator; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryOperator> + unaryOperator; /// \brief Matches conditional operator expressions. /// @@ -1902,9 +1992,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// (a ? b : c) + 42 /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ConditionalOperator> conditionalOperator; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ConditionalOperator> + conditionalOperator; /// \brief Matches binary conditional operator expressions (GNU extension). /// @@ -1912,9 +2001,9 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// (a ?: b) + 42; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - BinaryConditionalOperator> binaryConditionalOperator; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + BinaryConditionalOperator> + binaryConditionalOperator; /// \brief Matches opaque value expressions. They are used as helpers /// to reference another expressions and can be met @@ -1924,9 +2013,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// (a ?: c) + 42; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - OpaqueValueExpr> opaqueValueExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, OpaqueValueExpr> + opaqueValueExpr; /// \brief Matches a C++ static_assert declaration. /// @@ -1941,9 +2029,8 @@ const internal::VariadicDynCastAllOfMatcher< /// }; /// static_assert(sizeof(S) == sizeof(int)); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Decl, - StaticAssertDecl> staticAssertDecl; +extern const internal::VariadicDynCastAllOfMatcher<Decl, StaticAssertDecl> + staticAssertDecl; /// \brief Matches a reinterpret_cast expression. /// @@ -1955,9 +2042,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// void* p = reinterpret_cast<char*>(&p); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXReinterpretCastExpr> cxxReinterpretCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXReinterpretCastExpr> + cxxReinterpretCastExpr; /// \brief Matches a C++ static_cast expression. /// @@ -1972,9 +2058,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// long eight(static_cast<long>(8)); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXStaticCastExpr> cxxStaticCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXStaticCastExpr> + cxxStaticCastExpr; /// \brief Matches a dynamic_cast expression. /// @@ -1988,9 +2073,8 @@ const internal::VariadicDynCastAllOfMatcher< /// B b; /// D* p = dynamic_cast<D*>(&b); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXDynamicCastExpr> cxxDynamicCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDynamicCastExpr> + cxxDynamicCastExpr; /// \brief Matches a const_cast expression. /// @@ -2000,9 +2084,8 @@ const internal::VariadicDynCastAllOfMatcher< /// const int &r(n); /// int* p = const_cast<int*>(&r); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXConstCastExpr> cxxConstCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr> + cxxConstCastExpr; /// \brief Matches a C-style cast expression. /// @@ -2010,9 +2093,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// int i = (int) 2.2f; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CStyleCastExpr> cStyleCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr> + cStyleCastExpr; /// \brief Matches explicit cast expressions. /// @@ -2035,17 +2117,15 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// long ell = 42; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ExplicitCastExpr> explicitCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr> + explicitCastExpr; /// \brief Matches the implicit cast nodes of Clang's AST. /// /// This matches many different places, including function call return value /// eliding, as well as any type conversions. -const internal::VariadicDynCastAllOfMatcher< - Stmt, - ImplicitCastExpr> implicitCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitCastExpr> + implicitCastExpr; /// \brief Matches any cast nodes of Clang's AST. /// @@ -2060,7 +2140,7 @@ const internal::VariadicDynCastAllOfMatcher< /// int i = (0); /// int k = 0; /// \endcode -const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; /// \brief Matches functional cast expressions /// @@ -2070,9 +2150,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; /// Foo g = (Foo) bar; /// Foo h = Foo(bar); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXFunctionalCastExpr> cxxFunctionalCastExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFunctionalCastExpr> + cxxFunctionalCastExpr; /// \brief Matches functional cast expressions having N != 1 arguments /// @@ -2080,9 +2159,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// Foo h = Foo(bar, bar); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CXXTemporaryObjectExpr> cxxTemporaryObjectExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTemporaryObjectExpr> + cxxTemporaryObjectExpr; /// \brief Matches predefined identifier expressions [C99 6.4.2.2]. /// @@ -2090,9 +2168,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// printf("%s", __func__); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - PredefinedExpr> predefinedExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, PredefinedExpr> + predefinedExpr; /// \brief Matches C99 designated initializer expressions [C99 6.7.8]. /// @@ -2100,9 +2177,8 @@ const internal::VariadicDynCastAllOfMatcher< /// \code /// point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 }; /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - DesignatedInitExpr> designatedInitExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, DesignatedInitExpr> + designatedInitExpr; /// \brief Matches designated initializer expressions that contain /// a specific number of designators. @@ -2120,13 +2196,13 @@ AST_MATCHER_P(DesignatedInitExpr, designatorCountIs, unsigned, N) { } /// \brief Matches \c QualTypes in the clang AST. -const internal::VariadicAllOfMatcher<QualType> qualType; +extern const internal::VariadicAllOfMatcher<QualType> qualType; /// \brief Matches \c Types in the clang AST. -const internal::VariadicAllOfMatcher<Type> type; +extern const internal::VariadicAllOfMatcher<Type> type; /// \brief Matches \c TypeLocs in the clang AST. -const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; +extern const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// \brief Matches if any of the given matchers matches. /// @@ -2147,23 +2223,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// \c b. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { - internal::DynTypedMatcher::VO_EachOf -}; +extern const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + eachOf; /// \brief Matches if any of the given matchers matches. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = { - internal::DynTypedMatcher::VO_AnyOf -}; +extern const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + anyOf; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { - internal::DynTypedMatcher::VO_AllOf -}; +extern const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + allOf; /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) /// @@ -2174,9 +2250,9 @@ const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { /// \endcode /// unaryExprOrTypeTraitExpr() /// matches \c sizeof(x) and \c alignof(x) -const internal::VariadicDynCastAllOfMatcher< - Stmt, - UnaryExprOrTypeTraitExpr> unaryExprOrTypeTraitExpr; +extern const internal::VariadicDynCastAllOfMatcher<Stmt, + UnaryExprOrTypeTraitExpr> + unaryExprOrTypeTraitExpr; /// \brief Matches unary expressions that have a specific type of argument. /// @@ -2252,9 +2328,9 @@ inline internal::Matcher<NamedDecl> hasName(const std::string &Name) { /// \code /// anyOf(hasName(a), hasName(b), hasName(c)) /// \endcode -const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, - internal::hasAnyNameFunc> - hasAnyName = {}; +extern const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, + internal::hasAnyNameFunc> + hasAnyName; /// \brief Matches NamedDecl nodes whose fully qualified names contain /// a substring matched by the given RegExp. @@ -2403,8 +2479,7 @@ AST_MATCHER(CXXRecordDecl, isLambda) { /// casts and paren casts. If you are matching with expr then you should /// probably consider using ignoringParenImpCasts like: /// has(ignoringParenImpCasts(expr())). -const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> -LLVM_ATTRIBUTE_UNUSED has = {}; +extern const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> has; /// \brief Matches AST nodes that have descendant AST nodes that match the /// provided matcher. @@ -2420,8 +2495,9 @@ LLVM_ATTRIBUTE_UNUSED has = {}; /// DescendantT must be an AST base type. /// /// Usable as: Any Matcher -const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher> -LLVM_ATTRIBUTE_UNUSED hasDescendant = {}; +extern const internal::ArgumentAdaptingMatcherFunc< + internal::HasDescendantMatcher> + hasDescendant; /// \brief Matches AST nodes that have child AST nodes that match the /// provided matcher. @@ -2440,8 +2516,8 @@ LLVM_ATTRIBUTE_UNUSED hasDescendant = {}; /// matches instead of only on the first one. /// /// Usable as: Any Matcher -const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher> -LLVM_ATTRIBUTE_UNUSED forEach = {}; +extern const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher> + forEach; /// \brief Matches AST nodes that have descendant AST nodes that match the /// provided matcher. @@ -2469,8 +2545,9 @@ LLVM_ATTRIBUTE_UNUSED forEach = {}; /// \endcode /// /// Usable as: Any Matcher -const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher> -LLVM_ATTRIBUTE_UNUSED forEachDescendant = {}; +extern const internal::ArgumentAdaptingMatcherFunc< + internal::ForEachDescendantMatcher> + forEachDescendant; /// \brief Matches if the node or any descendant matches. /// @@ -2503,11 +2580,11 @@ internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) { /// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }". /// /// Usable as: Any Matcher -const internal::ArgumentAdaptingMatcherFunc< +extern const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> - LLVM_ATTRIBUTE_UNUSED hasParent = {}; + hasParent; /// \brief Matches AST nodes that have an ancestor that matches the provided /// matcher. @@ -2520,11 +2597,11 @@ const internal::ArgumentAdaptingMatcherFunc< /// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43. /// /// Usable as: Any Matcher -const internal::ArgumentAdaptingMatcherFunc< +extern const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> - LLVM_ATTRIBUTE_UNUSED hasAncestor = {}; + hasAncestor; /// \brief Matches if the provided matcher does not match. /// @@ -2535,9 +2612,7 @@ const internal::ArgumentAdaptingMatcherFunc< /// \endcode /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc<1, 1> unless = { - internal::DynTypedMatcher::VO_UnaryNot -}; +extern const internal::VariadicOperatorMatcherFunc<1, 1> unless; /// \brief Matches a node if the declaration associated with that node /// matches the given matcher. @@ -2549,8 +2624,21 @@ const internal::VariadicOperatorMatcherFunc<1, 1> unless = { /// - for CXXConstructExpr, the declaration of the constructor /// - for CXXNewExpr, the declaration of the operator new /// -/// Also usable as Matcher<T> for any T supporting the getDecl() member -/// function. e.g. various subtypes of clang::Type and various expressions. +/// For type nodes, hasDeclaration will generally match the declaration of the +/// sugared type. Given +/// \code +/// class X {}; +/// typedef X Y; +/// Y y; +/// \endcode +/// in varDecl(hasType(hasDeclaration(decl()))) the decl will match the +/// typedefDecl. A common use case is to match the underlying, desugared type. +/// This can be achieved by using the hasUnqualifiedDesugaredType matcher: +/// \code +/// varDecl(hasType(hasUnqualifiedDesugaredType( +/// recordType(hasDeclaration(decl()))))) +/// \endcode +/// In this matcher, the decl will match the CXXRecordDecl of class X. /// /// Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, /// Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -2843,7 +2931,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, /// class A {}; /// using B = A; /// \endcode -/// The matcher type(hasUniqualifeidDesugaredType(recordType())) matches +/// The matcher type(hasUnqualifeidDesugaredType(recordType())) matches /// both B and A. AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>, InnerMatcher) { @@ -3237,7 +3325,7 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, /// with forField matching foo_ AST_MATCHER_P(CXXCtorInitializer, forField, internal::Matcher<FieldDecl>, InnerMatcher) { - const FieldDecl *NodeAsDecl = Node.getMember(); + const FieldDecl *NodeAsDecl = Node.getAnyMember(); return (NodeAsDecl != nullptr && InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); } @@ -3492,16 +3580,21 @@ AST_MATCHER_P(FunctionDecl, returns, return InnerMatcher.matches(Node.getReturnType(), Finder, Builder); } -/// \brief Matches extern "C" function declarations. +/// \brief Matches extern "C" function or variable declarations. /// /// Given: /// \code /// extern "C" void f() {} /// extern "C" { void g() {} } /// void h() {} +/// extern "C" int x = 1; +/// extern "C" int y = 2; +/// int z = 3; /// \endcode /// functionDecl(isExternC()) -/// matches the declaration of f and g, but not the declaration h +/// matches the declaration of f and g, but not the declaration of h. +/// varDecl(isExternC()) +/// matches the declaration of x and y, but not the declaration of z. AST_POLYMORPHIC_MATCHER(isExternC, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl)) { return Node.isExternC(); @@ -3947,7 +4040,6 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand, /// \code /// int a = b ?: 1; /// \endcode - AST_POLYMORPHIC_MATCHER_P(hasSourceExpression, AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr, OpaqueValueExpr), @@ -4067,11 +4159,19 @@ AST_MATCHER_P(AbstractConditionalOperator, hasFalseExpression, /// extern int vb; // Doesn't match, as it doesn't define the variable. /// void fa() {} /// void fb(); // Doesn't match, as it has no body. +/// @interface X +/// - (void)ma; // Doesn't match, interface is declaration. +/// @end +/// @implementation X +/// - (void)ma {} +/// @end /// \endcode /// -/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl> +/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, +/// Matcher<ObjCMethodDecl> AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES(TagDecl, VarDecl, + ObjCMethodDecl, FunctionDecl)) { return Node.isThisDeclarationADefinition(); } @@ -4638,6 +4738,9 @@ AST_MATCHER(Type, voidType) { return Node.isVoidType(); } +template <typename NodeType> +using AstTypeMatcher = internal::VariadicDynCastAllOfMatcher<Type, NodeType>; + /// \brief Matches builtin Types. /// /// Given @@ -4650,7 +4753,7 @@ AST_MATCHER(Type, voidType) { /// \endcode /// builtinType() /// matches "int b", "float c" and "bool d" -AST_TYPE_MATCHER(BuiltinType, builtinType); +extern const AstTypeMatcher<BuiltinType> builtinType; /// \brief Matches all kinds of arrays. /// @@ -4662,7 +4765,7 @@ AST_TYPE_MATCHER(BuiltinType, builtinType); /// \endcode /// arrayType() /// matches "int a[]", "int b[4]" and "int c[a[0]]"; -AST_TYPE_MATCHER(ArrayType, arrayType); +extern const AstTypeMatcher<ArrayType> arrayType; /// \brief Matches C99 complex types. /// @@ -4672,7 +4775,7 @@ AST_TYPE_MATCHER(ArrayType, arrayType); /// \endcode /// complexType() /// matches "_Complex float f" -AST_TYPE_MATCHER(ComplexType, complexType); +extern const AstTypeMatcher<ComplexType> complexType; /// \brief Matches any real floating-point type (float, double, long double). /// @@ -4700,9 +4803,9 @@ AST_MATCHER(Type, realFloatingPointType) { /// matches "int b[7]" /// /// Usable as: Matcher<ArrayType>, Matcher<ComplexType> -AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement, - AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, - ComplexType)); +AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasElementType, getElement, + AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, + ComplexType)); /// \brief Matches C arrays with a specified constant size. /// @@ -4716,7 +4819,7 @@ AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement, /// \endcode /// constantArrayType() /// matches "int a[2]" -AST_TYPE_MATCHER(ConstantArrayType, constantArrayType); +extern const AstTypeMatcher<ConstantArrayType> constantArrayType; /// \brief Matches nodes that have the specified size. /// @@ -4751,7 +4854,7 @@ AST_POLYMORPHIC_MATCHER_P(hasSize, /// \endcode /// dependentSizedArrayType /// matches "T data[Size]" -AST_TYPE_MATCHER(DependentSizedArrayType, dependentSizedArrayType); +extern const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType; /// \brief Matches C arrays with unspecified size. /// @@ -4763,7 +4866,7 @@ AST_TYPE_MATCHER(DependentSizedArrayType, dependentSizedArrayType); /// \endcode /// incompleteArrayType() /// matches "int a[]" and "int c[]" -AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType); +extern const AstTypeMatcher<IncompleteArrayType> incompleteArrayType; /// \brief Matches C arrays with a specified size that is not an /// integer-constant-expression. @@ -4778,7 +4881,7 @@ AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType); /// \endcode /// variableArrayType() /// matches "int c[a[0]]" -AST_TYPE_MATCHER(VariableArrayType, variableArrayType); +extern const AstTypeMatcher<VariableArrayType> variableArrayType; /// \brief Matches \c VariableArrayType nodes that have a specific size /// expression. @@ -4805,7 +4908,7 @@ AST_MATCHER_P(VariableArrayType, hasSizeExpr, /// \endcode /// atomicType() /// matches "_Atomic(int) i" -AST_TYPE_MATCHER(AtomicType, atomicType); +extern const AstTypeMatcher<AtomicType> atomicType; /// \brief Matches atomic types with a specific value type. /// @@ -4818,8 +4921,8 @@ AST_TYPE_MATCHER(AtomicType, atomicType); /// matches "_Atomic(int) i" /// /// Usable as: Matcher<AtomicType> -AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue, - AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType)); +AST_TYPELOC_TRAVERSE_MATCHER_DECL(hasValueType, getValue, + AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType)); /// \brief Matches types nodes representing C++11 auto types. /// @@ -4831,7 +4934,7 @@ AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue, /// \endcode /// autoType() /// matches "auto n" and "auto i" -AST_TYPE_MATCHER(AutoType, autoType); +extern const AstTypeMatcher<AutoType> autoType; /// \brief Matches \c AutoType nodes where the deduced type is a specific type. /// @@ -4859,7 +4962,7 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, /// \endcode /// functionType() /// matches "int (*f)(int)" and the type of "g". -AST_TYPE_MATCHER(FunctionType, functionType); +extern const AstTypeMatcher<FunctionType> functionType; /// \brief Matches \c FunctionProtoType nodes. /// @@ -4871,7 +4974,7 @@ AST_TYPE_MATCHER(FunctionType, functionType); /// functionProtoType() /// matches "int (*f)(int)" and the type of "g" in C++ mode. /// In C mode, "g" is not matched because it does not contain a prototype. -AST_TYPE_MATCHER(FunctionProtoType, functionProtoType); +extern const AstTypeMatcher<FunctionProtoType> functionProtoType; /// \brief Matches \c ParenType nodes. /// @@ -4883,7 +4986,7 @@ AST_TYPE_MATCHER(FunctionProtoType, functionProtoType); /// /// \c varDecl(hasType(pointsTo(parenType()))) matches \c ptr_to_array but not /// \c array_of_ptrs. -AST_TYPE_MATCHER(ParenType, parenType); +extern const AstTypeMatcher<ParenType> parenType; /// \brief Matches \c ParenType nodes where the inner type is a specific type. /// @@ -4904,7 +5007,7 @@ AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType, /// "void (^)(int)". /// /// The \c pointee is always required to be a \c FunctionType. -AST_TYPE_MATCHER(BlockPointerType, blockPointerType); +extern const AstTypeMatcher<BlockPointerType> blockPointerType; /// \brief Matches member pointer types. /// Given @@ -4914,7 +5017,7 @@ AST_TYPE_MATCHER(BlockPointerType, blockPointerType); /// \endcode /// memberPointerType() /// matches "A::* ptr" -AST_TYPE_MATCHER(MemberPointerType, memberPointerType); +extern const AstTypeMatcher<MemberPointerType> memberPointerType; /// \brief Matches pointer types, but does not match Objective-C object pointer /// types. @@ -4931,7 +5034,7 @@ AST_TYPE_MATCHER(MemberPointerType, memberPointerType); /// \endcode /// pointerType() /// matches "int *a", but does not match "Foo *f". -AST_TYPE_MATCHER(PointerType, pointerType); +extern const AstTypeMatcher<PointerType> pointerType; /// \brief Matches an Objective-C object pointer type, which is different from /// a pointer type, despite being syntactically similar. @@ -4946,7 +5049,7 @@ AST_TYPE_MATCHER(PointerType, pointerType); /// \endcode /// pointerType() /// matches "Foo *f", but does not match "int *a". -AST_TYPE_MATCHER(ObjCObjectPointerType, objcObjectPointerType); +extern const AstTypeMatcher<ObjCObjectPointerType> objcObjectPointerType; /// \brief Matches both lvalue and rvalue reference types. /// @@ -4962,7 +5065,7 @@ AST_TYPE_MATCHER(ObjCObjectPointerType, objcObjectPointerType); /// \endcode /// /// \c referenceType() matches the types of \c b, \c c, \c d, \c e, and \c f. -AST_TYPE_MATCHER(ReferenceType, referenceType); +extern const AstTypeMatcher<ReferenceType> referenceType; /// \brief Matches lvalue reference types. /// @@ -4979,7 +5082,7 @@ AST_TYPE_MATCHER(ReferenceType, referenceType); /// /// \c lValueReferenceType() matches the types of \c b, \c d, and \c e. \c e is /// matched since the type is deduced as int& by reference collapsing rules. -AST_TYPE_MATCHER(LValueReferenceType, lValueReferenceType); +extern const AstTypeMatcher<LValueReferenceType> lValueReferenceType; /// \brief Matches rvalue reference types. /// @@ -4996,7 +5099,7 @@ AST_TYPE_MATCHER(LValueReferenceType, lValueReferenceType); /// /// \c rValueReferenceType() matches the types of \c c and \c f. \c e is not /// matched as it is deduced to int& by reference collapsing rules. -AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType); +extern const AstTypeMatcher<RValueReferenceType> rValueReferenceType; /// \brief Narrows PointerType (and similar) matchers to those where the /// \c pointee matches a given matcher. @@ -5012,11 +5115,10 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType); /// /// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, /// Matcher<PointerType>, Matcher<ReferenceType> -AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee, - AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, - MemberPointerType, - PointerType, - ReferenceType)); +AST_TYPELOC_TRAVERSE_MATCHER_DECL( + pointee, getPointee, + AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType, + PointerType, ReferenceType)); /// \brief Matches typedef types. /// @@ -5026,7 +5128,7 @@ AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee, /// \endcode /// typedefType() /// matches "typedef int X" -AST_TYPE_MATCHER(TypedefType, typedefType); +extern const AstTypeMatcher<TypedefType> typedefType; /// \brief Matches enum types. /// @@ -5041,7 +5143,7 @@ AST_TYPE_MATCHER(TypedefType, typedefType); // /// \c enumType() matches the type of the variable declarations of both \c c and /// \c s. -AST_TYPE_MATCHER(EnumType, enumType); +extern const AstTypeMatcher<EnumType> enumType; /// \brief Matches template specialization types. /// @@ -5056,7 +5158,8 @@ AST_TYPE_MATCHER(EnumType, enumType); /// /// \c templateSpecializationType() matches the type of the explicit /// instantiation in \c A and the type of the variable declaration in \c B. -AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType); +extern const AstTypeMatcher<TemplateSpecializationType> + templateSpecializationType; /// \brief Matches types nodes representing unary type transformations. /// @@ -5066,7 +5169,7 @@ AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType); /// \endcode /// unaryTransformType() /// matches "__underlying_type(T)" -AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType); +extern const AstTypeMatcher<UnaryTransformType> unaryTransformType; /// \brief Matches record types (e.g. structs, classes). /// @@ -5081,7 +5184,22 @@ AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType); /// /// \c recordType() matches the type of the variable declarations of both \c c /// and \c s. -AST_TYPE_MATCHER(RecordType, recordType); +extern const AstTypeMatcher<RecordType> recordType; + +/// \brief Matches tag types (record and enum types). +/// +/// Given +/// \code +/// enum E {}; +/// class C {}; +/// +/// E e; +/// C c; +/// \endcode +/// +/// \c tagType() matches the type of the variable declarations of both \c e +/// and \c c. +extern const AstTypeMatcher<TagType> tagType; /// \brief Matches types specified with an elaborated type keyword or with a /// qualified name. @@ -5101,7 +5219,7 @@ AST_TYPE_MATCHER(RecordType, recordType); /// /// \c elaboratedType() matches the type of the variable declarations of both /// \c c and \c d. -AST_TYPE_MATCHER(ElaboratedType, elaboratedType); +extern const AstTypeMatcher<ElaboratedType> elaboratedType; /// \brief Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier, /// matches \c InnerMatcher if the qualifier exists. @@ -5158,7 +5276,8 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, /// \endcode /// /// \c substTemplateTypeParmType() matches the type of 't' but not '1' -AST_TYPE_MATCHER(SubstTemplateTypeParmType, substTemplateTypeParmType); +extern const AstTypeMatcher<SubstTemplateTypeParmType> + substTemplateTypeParmType; /// \brief Matches template type parameter substitutions that have a replacement /// type that matches the provided matcher. @@ -5183,7 +5302,7 @@ AST_TYPE_TRAVERSE_MATCHER( /// \code /// template <typename T> void f(int i); /// \endcode -AST_TYPE_MATCHER(TemplateTypeParmType, templateTypeParmType); +extern const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType; /// \brief Matches injected class name types. /// @@ -5195,7 +5314,7 @@ AST_TYPE_MATCHER(TemplateTypeParmType, templateTypeParmType); /// void g(S<T> s); /// }; /// \endcode -AST_TYPE_MATCHER(InjectedClassNameType, injectedClassNameType); +extern const AstTypeMatcher<InjectedClassNameType> injectedClassNameType; /// \brief Matches decayed type /// Example matches i[] in declaration of f. @@ -5207,7 +5326,7 @@ AST_TYPE_MATCHER(InjectedClassNameType, injectedClassNameType); /// i[1] = 0; /// } /// \endcode -AST_TYPE_MATCHER(DecayedType, decayedType); +extern const AstTypeMatcher<DecayedType> decayedType; /// \brief Matches the decayed type, whos decayed type matches \c InnerMatcher AST_MATCHER_P(DecayedType, hasDecayedType, internal::Matcher<QualType>, @@ -5248,11 +5367,12 @@ AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) { /// \endcode /// nestedNameSpecifier() /// matches "ns::" and both "A::" -const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; +extern const internal::VariadicAllOfMatcher<NestedNameSpecifier> + nestedNameSpecifier; /// \brief Same as \c nestedNameSpecifier but matches \c NestedNameSpecifierLoc. -const internal::VariadicAllOfMatcher< - NestedNameSpecifierLoc> nestedNameSpecifierLoc; +extern const internal::VariadicAllOfMatcher<NestedNameSpecifierLoc> + nestedNameSpecifierLoc; /// \brief Matches \c NestedNameSpecifierLocs for which the given inner /// NestedNameSpecifier-matcher matches. @@ -5605,17 +5725,14 @@ AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>, return false; } - /// \brief Matches CUDA kernel call expression. /// /// Example matches, /// \code /// kernel<<<i,j>>>(); /// \endcode -const internal::VariadicDynCastAllOfMatcher< - Stmt, - CUDAKernelCallExpr> cudaKernelCallExpr; - +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr> + cudaKernelCallExpr; /// \brief Matches expressions that resolve to a null pointer constant, such as /// GNU's __null, C++11's nullptr, or C's NULL macro. @@ -5700,7 +5817,54 @@ AST_MATCHER(NamedDecl, hasExternalFormalLinkage) { return Node.hasExternalFormalLinkage(); } -} // end namespace ast_matchers -} // end namespace clang +/// \brief Matches a declaration that has default arguments. +/// +/// Example matches y (matcher = parmVarDecl(hasDefaultArgument())) +/// \code +/// void x(int val) {} +/// void y(int val = 0) {} +/// \endcode +AST_MATCHER(ParmVarDecl, hasDefaultArgument) { + return Node.hasDefaultArg(); +} + +/// \brief Matches array new expressions. +/// +/// Given: +/// \code +/// MyClass *p1 = new MyClass[10]; +/// \endcode +/// cxxNewExpr(isArray()) +/// matches the expression 'new MyClass[10]'. +AST_MATCHER(CXXNewExpr, isArray) { + return Node.isArray(); +} + +/// \brief Matches array new expressions with a given array size. +/// +/// Given: +/// \code +/// MyClass *p1 = new MyClass[10]; +/// \endcode +/// cxxNewExpr(hasArraySize(intgerLiteral(equals(10)))) +/// matches the expression 'new MyClass[10]'. +AST_MATCHER_P(CXXNewExpr, hasArraySize, internal::Matcher<Expr>, InnerMatcher) { + return Node.isArray() && + InnerMatcher.matches(*Node.getArraySize(), Finder, Builder); +} + +/// \brief Matches a class declaration that is defined. +/// +/// Example matches x (matcher = cxxRecordDecl(hasDefinition())) +/// \code +/// class x {}; +/// class y; +/// \endcode +AST_MATCHER(CXXRecordDecl, hasDefinition) { + return Node.hasDefinition(); +} + +} // namespace ast_matchers +} // namespace clang -#endif +#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index bc75e807ced98..8bd61a76e1852 100644 --- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1,4 +1,4 @@ -//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===// +//===- ASTMatchersInternal.h - Structural query framework -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -38,23 +38,42 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ManagedStatic.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> #include <map> #include <string> +#include <tuple> +#include <type_traits> +#include <utility> #include <vector> namespace clang { + +class ASTContext; + namespace ast_matchers { class BoundNodes; @@ -158,7 +177,7 @@ public: /// Note that we're using std::map here, as for memoization: /// - we need a comparison operator /// - we need an assignment operator - typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap; + using IDToNodeMap = std::map<std::string, ast_type_traits::DynTypedNode>; const IDToNodeMap &getMap() const { return NodeMap; @@ -188,7 +207,7 @@ public: /// BoundNodesTree. class Visitor { public: - virtual ~Visitor() {} + virtual ~Visitor() = default; /// \brief Called multiple times during a single call to VisitMatches(...). /// @@ -248,7 +267,7 @@ class ASTMatchFinder; class DynMatcherInterface : public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> { public: - virtual ~DynMatcherInterface() {} + virtual ~DynMatcherInterface() = default; /// \brief Returns true if \p DynNode can be matched. /// @@ -317,26 +336,29 @@ public: /// \brief Takes ownership of the provided implementation pointer. template <typename T> DynTypedMatcher(MatcherInterface<T> *Implementation) - : AllowBind(false), - SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), + : SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()), RestrictKind(SupportedKind), Implementation(Implementation) {} /// \brief Construct from a variadic function. enum VariadicOperator { /// \brief Matches nodes for which all provided matchers match. VO_AllOf, + /// \brief Matches nodes for which at least one of the provided matchers /// matches. VO_AnyOf, + /// \brief Matches nodes for which at least one of the provided matchers /// matches, but doesn't stop at the first match. VO_EachOf, + /// \brief Matches nodes that do not match the provided matcher. /// /// Uses the variadic matcher interface, but fails if /// InnerMatchers.size() != 1. VO_UnaryNot }; + static DynTypedMatcher constructVariadic(VariadicOperator Op, ast_type_traits::ASTNodeKind SupportedKind, @@ -382,7 +404,7 @@ public: /// include both in the ID to make it unique. /// /// \c MatcherIDType supports operator< and provides strict weak ordering. - typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType; + using MatcherIDType = std::pair<ast_type_traits::ASTNodeKind, uint64_t>; MatcherIDType getID() const { /// FIXME: Document the requirements this imposes on matcher /// implementations (no new() implementation_ during a Matches()). @@ -428,13 +450,12 @@ private: DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind, ast_type_traits::ASTNodeKind RestrictKind, IntrusiveRefCntPtr<DynMatcherInterface> Implementation) - : AllowBind(false), - SupportedKind(SupportedKind), - RestrictKind(RestrictKind), + : SupportedKind(SupportedKind), RestrictKind(RestrictKind), Implementation(std::move(Implementation)) {} - bool AllowBind; + bool AllowBind = false; ast_type_traits::ASTNodeKind SupportedKind; + /// \brief A potentially stricter node kind. /// /// It allows to perform implicit and dynamic cast of matchers without @@ -545,6 +566,7 @@ public: private: // For Matcher<T> <=> Matcher<U> conversions. template <typename U> friend class Matcher; + // For DynTypedMatcher::unconditionalConvertTo<T>. friend class DynTypedMatcher; @@ -618,8 +640,8 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, // Metafunction to determine if type T has a member called getDecl. template <typename Ty> class has_getDecl { - typedef char yes[1]; - typedef char no[2]; + using yes = char[1]; + using no = char[2]; template <typename Inner> static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr); @@ -728,48 +750,94 @@ public: } private: - /// \brief If getDecl exists as a member of U, returns whether the inner - /// matcher matches Node.getDecl(). - template <typename U> - bool matchesSpecialized( - const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, - typename std::enable_if<has_getDecl<U>::value, int>::type = 0) const { - return matchesDecl(Node.getDecl(), Finder, Builder); - } - - /// \brief Extracts the TagDecl of a QualType and returns whether the inner - /// matcher matches on it. + /// \brief Forwards to matching on the underlying type of the QualType. bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { if (Node.isNull()) return false; - if (auto *TD = Node->getAsTagDecl()) - return matchesDecl(TD, Finder, Builder); - else if (auto *TT = Node->getAs<TypedefType>()) - return matchesDecl(TT->getDecl(), Finder, Builder); - // Do not use getAs<TemplateTypeParmType> instead of the direct dyn_cast. - // Calling getAs will return the canonical type, but that type does not - // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is - // available, and using dyn_cast ensures that. - else if (auto *TTP = dyn_cast<TemplateTypeParmType>(Node.getTypePtr())) - return matchesDecl(TTP->getDecl(), Finder, Builder); - else if (auto *OCIT = Node->getAs<ObjCInterfaceType>()) - return matchesDecl(OCIT->getDecl(), Finder, Builder); - else if (auto *UUT = Node->getAs<UnresolvedUsingType>()) - return matchesDecl(UUT->getDecl(), Finder, Builder); - else if (auto *ICNT = Node->getAs<InjectedClassNameType>()) - return matchesDecl(ICNT->getDecl(), Finder, Builder); + return matchesSpecialized(*Node, Finder, Builder); + } + + /// \brief Finds the best declaration for a type and returns whether the inner + /// matcher matches on it. + bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + // DeducedType does not have declarations of its own, so + // match the deduced type instead. + const Type *EffectiveType = &Node; + if (const auto *S = dyn_cast<DeducedType>(&Node)) { + EffectiveType = S->getDeducedType().getTypePtrOrNull(); + if (!EffectiveType) + return false; + } + + // First, for any types that have a declaration, extract the declaration and + // match on it. + if (const auto *S = dyn_cast<TagType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) { + return matchesDecl(S->getDecl(), Finder, Builder); + } + if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) { + return matchesDecl(S->getInterface(), Finder, Builder); + } + + // A SubstTemplateTypeParmType exists solely to mark a type substitution + // on the instantiated template. As users usually want to match the + // template parameter on the uninitialized template, we can always desugar + // one level without loss of expressivness. + // For example, given: + // template<typename T> struct X { T t; } class A {}; X<A> a; + // The following matcher will match, which otherwise would not: + // fieldDecl(hasType(pointerType())). + if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) { + return matchesSpecialized(S->getReplacementType(), Finder, Builder); + } + + // For template specialization types, we want to match the template + // declaration, as long as the type is still dependent, and otherwise the + // declaration of the instantiated tag type. + if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) { + if (!S->isTypeAlias() && S->isSugared()) { + // If the template is non-dependent, we want to match the instantiated + // tag type. + // For example, given: + // template<typename T> struct X {}; X<int> a; + // The following matcher will match, which otherwise would not: + // templateSpecializationType(hasDeclaration(cxxRecordDecl())). + return matchesSpecialized(*S->desugar(), Finder, Builder); + } + // If the template is dependent or an alias, match the template + // declaration. + return matchesDecl(S->getTemplateName().getAsTemplateDecl(), Finder, + Builder); + } + + // FIXME: We desugar elaborated types. This makes the assumption that users + // do never want to match on whether a type is elaborated - there are + // arguments for both sides; for now, continue desugaring. + if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) { + return matchesSpecialized(S->desugar(), Finder, Builder); + } return false; } - /// \brief Gets the TemplateDecl from a TemplateSpecializationType - /// and returns whether the inner matches on it. - bool matchesSpecialized(const TemplateSpecializationType &Node, - ASTMatchFinder *Finder, + /// \brief Extracts the Decl the DeclRefExpr references and returns whether + /// the inner matcher matches on it. + bool matchesSpecialized(const DeclRefExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return matchesDecl(Node.getTemplateName().getAsTemplateDecl(), - Finder, Builder); + return matchesDecl(Node.getDecl(), Finder, Builder); } /// \brief Extracts the Decl of the callee of a CallExpr and returns whether @@ -811,6 +879,13 @@ private: return matchesDecl(Node.getLabel(), Finder, Builder); } + /// \brief Extracts the declaration of a LabelStmt and returns whether the + /// inner matcher matches on it. + bool matchesSpecialized(const LabelStmt &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesDecl(Node.getDecl(), Finder, Builder); + } + /// \brief Returns whether the inner matcher \c Node. Returns false if \c Node /// is \c NULL. bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder, @@ -863,6 +938,7 @@ public: enum TraversalKind { /// Will traverse any child nodes. TK_AsIs, + /// Will not traverse implicit casts and parentheses. TK_IgnoreImplicitCastsAndParentheses }; @@ -871,6 +947,7 @@ public: enum BindKind { /// Stop at the first match and only bind the first match. BK_First, + /// Create results for all combinations of bindings that match. BK_All }; @@ -879,11 +956,12 @@ public: enum AncestorMatchMode { /// All ancestors. AMM_All, + /// Direct parent only. AMM_ParentOnly }; - virtual ~ASTMatchFinder() {} + virtual ~ASTMatchFinder() = default; /// \brief Returns true if the given class is directly or indirectly derived /// from a base type matching \c base. @@ -906,7 +984,7 @@ public: std::is_base_of<TypeLoc, T>::value || std::is_base_of<QualType, T>::value, "unsupported type for recursive matching"); - return matchesChildOf(ast_type_traits::DynTypedNode::create(Node), + return matchesChildOf(ast_type_traits::DynTypedNode::create(Node), Matcher, Builder, Traverse, Bind); } @@ -969,17 +1047,17 @@ template <typename... Ts> struct TypeList {}; // Empty sentinel type list. template <typename T1, typename... Ts> struct TypeList<T1, Ts...> { /// \brief The first type on the list. - typedef T1 head; + using head = T1; /// \brief A sublist with the tail. ie everything but the head. /// /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the /// end of the list. - typedef TypeList<Ts...> tail; + using tail = TypeList<Ts...>; }; /// \brief The empty type list. -typedef TypeList<> EmptyTypeList; +using EmptyTypeList = TypeList<>; /// \brief Helper meta-function to determine if some type \c T is present or /// a parent type in the list. @@ -997,8 +1075,9 @@ struct TypeListContainsSuperOf<EmptyTypeList, T> { /// \brief A "type list" that contains all types. /// /// Useful for matchers like \c anything and \c unless. -typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, - QualType, Type, TypeLoc, CXXCtorInitializer> AllNodeBaseTypes; +using AllNodeBaseTypes = + TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, QualType, + Type, TypeLoc, CXXCtorInitializer>; /// \brief Helper meta-function to extract the argument out of a function of /// type void(Arg). @@ -1006,20 +1085,22 @@ typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, /// See AST_POLYMORPHIC_SUPPORTED_TYPES for details. template <class T> struct ExtractFunctionArgMeta; template <class T> struct ExtractFunctionArgMeta<void(T)> { - typedef T type; + using type = T; }; /// \brief Default type lists for ArgumentAdaptingMatcher matchers. -typedef AllNodeBaseTypes AdaptativeDefaultFromTypes; -typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, - TypeLoc, QualType> AdaptativeDefaultToTypes; +using AdaptativeDefaultFromTypes = AllNodeBaseTypes; +using AdaptativeDefaultToTypes = + TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, TypeLoc, + QualType>; /// \brief All types that are supported by HasDeclarationMatcher above. -typedef TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType, - InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr, - QualType, RecordType, TagType, TemplateSpecializationType, - TemplateTypeParmType, TypedefType, UnresolvedUsingType> - HasDeclarationSupportedTypes; +using HasDeclarationSupportedTypes = + TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType, + ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr, + MemberExpr, QualType, RecordType, TagType, + TemplateSpecializationType, TemplateTypeParmType, TypedefType, + UnresolvedUsingType>; /// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by /// "adapting" a \c To into a \c T. @@ -1043,7 +1124,7 @@ struct ArgumentAdaptingMatcherFunc { explicit Adaptor(const Matcher<T> &InnerMatcher) : InnerMatcher(InnerMatcher) {} - typedef ToTypes ReturnTypes; + using ReturnTypes = ToTypes; template <typename To> operator Matcher<To>() const { return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); @@ -1080,7 +1161,8 @@ template <template <typename T> class MatcherT, typename ReturnTypesF = void(AllNodeBaseTypes)> class PolymorphicMatcherWithParam0 { public: - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; + template <typename T> operator Matcher<T>() const { static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value, @@ -1097,7 +1179,7 @@ public: explicit PolymorphicMatcherWithParam1(const P1 &Param1) : Param1(Param1) {} - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; template <typename T> operator Matcher<T>() const { @@ -1118,7 +1200,7 @@ public: PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2) : Param1(Param1), Param2(Param2) {} - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; template <typename T> operator Matcher<T>() const { @@ -1137,8 +1219,8 @@ private: /// This is useful when a matcher syntactically requires a child matcher, /// but the context doesn't care. See for example: anything(). class TrueMatcher { - public: - typedef AllNodeBaseTypes ReturnTypes; +public: + using ReturnTypes = AllNodeBaseTypes; template <typename T> operator Matcher<T>() const { @@ -1184,7 +1266,6 @@ public: /// ChildT must be an AST base type. template <typename T, typename ChildT> class HasMatcher : public WrapperMatcherInterface<T> { - public: explicit HasMatcher(const Matcher<ChildT> &ChildMatcher) : HasMatcher::WrapperMatcherInterface(ChildMatcher) {} @@ -1278,7 +1359,7 @@ template<typename T> BindableMatcher<T> makeAllOfComposite( ArrayRef<const Matcher<T> *> InnerMatchers) { // For the size() == 0 case, we return a "true" matcher. - if (InnerMatchers.size() == 0) { + if (InnerMatchers.empty()) { return BindableMatcher<T>(TrueMatcher()); } // For the size() == 1 case, we simply return that one matcher. @@ -1287,7 +1368,8 @@ BindableMatcher<T> makeAllOfComposite( return BindableMatcher<T>(*InnerMatchers[0]); } - typedef llvm::pointee_iterator<const Matcher<T> *const *> PI; + using PI = llvm::pointee_iterator<const Matcher<T> *const *>; + std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()), PI(InnerMatchers.end())); return BindableMatcher<T>( @@ -1580,12 +1662,13 @@ template <typename InnerTBase, typename ReturnTypesF> class TypeTraversePolymorphicMatcher { private: - typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, - ReturnTypesF> Self; + using Self = TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, + ReturnTypesF>; + static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers); public: - typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type; explicit TypeTraversePolymorphicMatcher( ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) @@ -1612,6 +1695,7 @@ private: template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher { struct Wrapper { Wrapper() : M(Func()) {} + Matcher M; }; @@ -1657,6 +1741,7 @@ struct NotEqualsBoundNodePredicate { bool operator()(const internal::BoundNodesMap &Nodes) const { return Nodes.getNode(ID) != Node; } + std::string ID; ast_type_traits::DynTypedNode Node; }; @@ -1712,9 +1797,10 @@ CompoundStmtMatcher<StmtExpr>::get(const StmtExpr &Node) { return Node.getSubStmt(); } +} // namespace internal + +} // namespace ast_matchers -} // end namespace internal -} // end namespace ast_matchers -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h index ddc48378e714a..6a48da821a53e 100644 --- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -367,6 +367,27 @@ // FIXME: add a matcher for TypeLoc derived classes using its custom casting // API (no longer dyn_cast) if/when we need such matching +#define AST_TYPE_TRAVERSE_MATCHER_DECL(MatcherName, FunctionName, \ + ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeMatcher##MatcherName##Getter { \ + static QualType (T::*value())() const { return &T::FunctionName; } \ + }; \ + } \ + extern const ::clang::ast_matchers::internal:: \ + TypeTraversePolymorphicMatcher< \ + QualType, \ + ::clang::ast_matchers::internal::TypeMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeTraverseMatcher, \ + ReturnTypesF>::Func MatcherName + +#define AST_TYPE_TRAVERSE_MATCHER_DEF(MatcherName, ReturnTypesF) \ + const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \ + QualType, \ + ::clang::ast_matchers::internal::TypeMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeTraverseMatcher, \ + ReturnTypesF>::Func MatcherName + /// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines /// the matcher \c MatcherName that can be used to traverse from one \c Type /// to another. @@ -386,6 +407,30 @@ ::clang::ast_matchers::internal::TypeTraverseMatcher, \ ReturnTypesF>::Func MatcherName +#define AST_TYPELOC_TRAVERSE_MATCHER_DECL(MatcherName, FunctionName, \ + ReturnTypesF) \ + namespace internal { \ + template <typename T> struct TypeLocMatcher##MatcherName##Getter { \ + static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \ + }; \ + } \ + extern const ::clang::ast_matchers::internal:: \ + TypeTraversePolymorphicMatcher< \ + TypeLoc, \ + ::clang::ast_matchers::internal:: \ + TypeLocMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeLocTraverseMatcher, \ + ReturnTypesF>::Func MatcherName##Loc; \ + AST_TYPE_TRAVERSE_MATCHER_DECL(MatcherName, FunctionName##Type, ReturnTypesF) + +#define AST_TYPELOC_TRAVERSE_MATCHER_DEF(MatcherName, ReturnTypesF) \ + const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \ + TypeLoc, \ + ::clang::ast_matchers::internal::TypeLocMatcher##MatcherName##Getter, \ + ::clang::ast_matchers::internal::TypeLocTraverseMatcher, \ + ReturnTypesF>::Func MatcherName##Loc; \ + AST_TYPE_TRAVERSE_MATCHER_DEF(MatcherName, ReturnTypesF) + /// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works /// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs. #define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h index 5ec4a9abf4bff..e8fcf0a9d6ccd 100644 --- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h @@ -1,4 +1,4 @@ -//===--- Parser.h - Matcher expression parser -----*- C++ -*-===// +//===- Parser.h - Matcher expression parser ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,7 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Simple matcher expression parser. /// @@ -30,24 +30,28 @@ /// <Identifier> := [a-zA-Z]+ /// <ArgumentList> := <Expression> | <Expression>,<ArgumentList> /// \endcode -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H #define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H -#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/Dynamic/Registry.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" -#include "clang/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { namespace dynamic { +class Diagnostics; + /// \brief Matcher expression parser. class Parser { public: @@ -124,8 +128,8 @@ public: /// \brief Sema implementation that uses the matcher registry to process the /// tokens. class RegistrySema : public Parser::Sema { - public: - ~RegistrySema() override; + public: + ~RegistrySema() override; llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) override; @@ -143,7 +147,7 @@ public: getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; }; - typedef llvm::StringMap<VariantValue> NamedValueMap; + using NamedValueMap = llvm::StringMap<VariantValue>; /// \brief Parse a matcher expression. /// @@ -247,13 +251,14 @@ private: const NamedValueMap *const NamedValues; Diagnostics *const Error; - typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy; + using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>; + ContextStackTy ContextStack; std::vector<MatcherCompletion> Completions; }; -} // namespace dynamic -} // namespace ast_matchers -} // namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h index 7bba95dbffeab..277491250db8f 100644 --- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Registry.h @@ -1,4 +1,4 @@ -//===--- Registry.h - Matcher registry --------------------------*- C++ -*-===// +//===- Registry.h - Matcher registry ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,12 +6,12 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Registry of all known matchers. /// /// The registry provides a generic interface to construct any matcher by name. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H @@ -34,9 +34,9 @@ namespace internal { class MatcherDescriptor; -} // end namespace internal +} // namespace internal -typedef const internal::MatcherDescriptor *MatcherCtor; +using MatcherCtor = const internal::MatcherDescriptor *; struct MatcherCompletion { MatcherCompletion() = default; @@ -129,8 +129,8 @@ public: Diagnostics *Error); }; -} // end namespace dynamic -} // end namespace ast_matchers -} // end namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang #endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h index c0fc02724f099..5ba42b475c830 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Consumed.h @@ -19,7 +19,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceLocation.h" namespace clang { diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h index 38010e1ee1d8e..6cb161ab37c8a 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H #define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/Support/GenericDomTree.h" diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h index 8db4b0a58f86e..6a1222386bae1 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H #include "clang/AST/Decl.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "llvm/ADT/ImmutableSet.h" namespace clang { diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h index a1c6504275889..c0a93528373e2 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -21,7 +21,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/BitVector.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" namespace clang { diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h index 22694a7a225ab..7e403b1f40906 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h @@ -19,7 +19,7 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringRef.h" diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 8c1d1da554bd7..414645b7231bd 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -25,7 +25,7 @@ #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/OperatorKinds.h" #include <memory> #include <ostream> diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index be8a7105d7835..0a58d2a80250a 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -92,6 +92,7 @@ enum TIL_BinaryOpcode : unsigned char { BOP_Neq, // != BOP_Lt, // < BOP_Leq, // <= + BOP_Cmp, // <=> BOP_LogicAnd, // && (no short-circuit) BOP_LogicOr // || (no short-circuit) }; @@ -909,15 +910,10 @@ class Project : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } - Project(SExpr *R, StringRef SName) - : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr) - { } Project(SExpr *R, const clang::ValueDecl *Cvd) - : SExpr(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd) - { } - Project(const Project &P, SExpr *R) - : SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl) - { } + : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) { + assert(Cvd && "ValueDecl must not be null"); + } SExpr *record() { return Rec; } const SExpr *record() const { return Rec; } @@ -931,10 +927,14 @@ public: } StringRef slotName() const { - if (Cvdecl) + if (Cvdecl->getDeclName().isIdentifier()) return Cvdecl->getName(); - else - return SlotName; + if (!SlotName) { + SlotName = ""; + llvm::raw_string_ostream OS(*SlotName); + Cvdecl->printName(OS); + } + return *SlotName; } template <class V> @@ -953,7 +953,7 @@ public: private: SExpr* Rec; - StringRef SlotName; + mutable llvm::Optional<std::string> SlotName; const clang::ValueDecl *Cvdecl; }; diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDeclContext.h index ec7549d4535cc..03ff4a9516da0 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -1,4 +1,4 @@ -//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// +//=== AnalysisDeclContext.h - Analysis context for Path Sens analysis --*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -12,10 +12,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H -#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H #include "clang/AST/Decl.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CodeInjector.h" #include "llvm/ADT/DenseMap.h" @@ -416,23 +417,25 @@ class AnalysisDeclContextManager { /// Pointer to an interface that can provide function bodies for /// declarations from external source. std::unique_ptr<CodeInjector> Injector; - + + /// A factory for creating and caching implementations for common + /// methods during the analysis. + BodyFarm FunctionBodyFarm; + /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. bool SynthesizeBodies; public: - AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, bool addImplicitDtors = false, bool addInitializers = false, bool addTemporaryDtors = false, - bool addLifetime = false, + bool addLifetime = false, bool addLoopExit = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, - CodeInjector* injector = nullptr); - - ~AnalysisDeclContextManager(); + CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); @@ -471,6 +474,9 @@ public: return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); } + /// Get a reference to {@code BodyFarm} instance. + BodyFarm &getBodyFarm(); + /// Discard all previously created AnalysisDeclContexts. void clear(); diff --git a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.h b/contrib/llvm/tools/clang/include/clang/Analysis/BodyFarm.h index edbe996246515..ff0859bc662da 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/BodyFarm.h @@ -28,24 +28,27 @@ class ObjCMethodDecl; class ObjCPropertyDecl; class Stmt; class CodeInjector; - + class BodyFarm { public: BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {} - + /// Factory method for creating bodies for ordinary functions. Stmt *getBody(const FunctionDecl *D); /// Factory method for creating bodies for Objective-C properties. Stmt *getBody(const ObjCMethodDecl *D); + /// Remove copy constructor to avoid accidental copying. + BodyFarm(const BodyFarm &other) = delete; + private: - typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap; + typedef llvm::DenseMap<const Decl *, Optional<Stmt *>> BodyMap; ASTContext &C; BodyMap Bodies; CodeInjector *Injector; }; -} +} // namespace clang #endif diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h index 97639bbfade20..cfedb2aa8ed5d 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h @@ -1,4 +1,4 @@ -//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===// +//===- CFG.h - Classes for representing and building CFGs -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,38 +17,38 @@ #include "clang/AST/Stmt.h" #include "clang/Analysis/Support/BumpVector.h" -#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include <bitset> #include <cassert> +#include <cstddef> #include <iterator> #include <memory> +#include <vector> namespace clang { - class CXXDestructorDecl; - class Decl; - class Stmt; - class Expr; - class FieldDecl; - class VarDecl; - class CXXCtorInitializer; - class CXXBaseSpecifier; - class CXXBindTemporaryExpr; - class CFG; - class PrinterHelper; - class LangOptions; - class ASTContext; - class CXXRecordDecl; - class CXXDeleteExpr; - class CXXNewExpr; - class BinaryOperator; + +class ASTContext; +class BinaryOperator; +class CFG; +class CXXBaseSpecifier; +class CXXBindTemporaryExpr; +class CXXCtorInitializer; +class CXXDeleteExpr; +class CXXDestructorDecl; +class CXXNewExpr; +class CXXRecordDecl; +class Decl; +class FieldDecl; +class LangOptions; +class VarDecl; /// CFGElement - Represents a top-level expression in a basic block. class CFGElement { @@ -59,6 +59,7 @@ public: Initializer, NewAllocator, LifetimeEnds, + LoopExit, // dtor kind AutomaticObjectDtor, DeleteDtor, @@ -75,14 +76,14 @@ protected: llvm::PointerIntPair<void *, 2> Data2; CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr) - : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3), - Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) { + : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3), + Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) { assert(getKind() == kind); } - CFGElement() {} -public: + CFGElement() = default; +public: /// \brief Convert to the specified CFGElement type, asserting that this /// CFGElement is of the desired type. template<typename T> @@ -124,7 +125,9 @@ public: private: friend class CFGElement; - CFGStmt() {} + + CFGStmt() = default; + static bool isKind(const CFGElement &E) { return E.getKind() == Statement; } @@ -143,7 +146,9 @@ public: private: friend class CFGElement; - CFGInitializer() {} + + CFGInitializer() = default; + static bool isKind(const CFGElement &E) { return E.getKind() == Initializer; } @@ -162,12 +167,38 @@ public: private: friend class CFGElement; - CFGNewAllocator() {} + + CFGNewAllocator() = default; + static bool isKind(const CFGElement &elem) { return elem.getKind() == NewAllocator; } }; +/// Represents the point where a loop ends. +/// This element is is only produced when building the CFG for the static +/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag. +/// +/// Note: a loop exit element can be reached even when the loop body was never +/// entered. +class CFGLoopExit : public CFGElement { +public: + explicit CFGLoopExit(const Stmt *stmt) : CFGElement(LoopExit, stmt) {} + + const Stmt *getLoopStmt() const { + return static_cast<Stmt *>(Data1.getPointer()); + } + +private: + friend class CFGElement; + + CFGLoopExit() = default; + + static bool isKind(const CFGElement &elem) { + return elem.getKind() == LoopExit; + } +}; + /// Represents the point where the lifetime of an automatic object ends class CFGLifetimeEnds : public CFGElement { public: @@ -184,7 +215,9 @@ public: private: friend class CFGElement; - CFGLifetimeEnds() {} + + CFGLifetimeEnds() = default; + static bool isKind(const CFGElement &elem) { return elem.getKind() == LifetimeEnds; } @@ -194,7 +227,8 @@ private: /// by compiler on various occasions. class CFGImplicitDtor : public CFGElement { protected: - CFGImplicitDtor() {} + CFGImplicitDtor() = default; + CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr) : CFGElement(kind, data1, data2) { assert(kind >= DTOR_BEGIN && kind <= DTOR_END); @@ -206,6 +240,7 @@ public: private: friend class CFGElement; + static bool isKind(const CFGElement &E) { Kind kind = E.getKind(); return kind >= DTOR_BEGIN && kind <= DTOR_END; @@ -231,7 +266,9 @@ public: private: friend class CFGElement; - CFGAutomaticObjDtor() {} + + CFGAutomaticObjDtor() = default; + static bool isKind(const CFGElement &elem) { return elem.getKind() == AutomaticObjectDtor; } @@ -255,7 +292,9 @@ public: private: friend class CFGElement; - CFGDeleteDtor() {} + + CFGDeleteDtor() = default; + static bool isKind(const CFGElement &elem) { return elem.getKind() == DeleteDtor; } @@ -274,7 +313,9 @@ public: private: friend class CFGElement; - CFGBaseDtor() {} + + CFGBaseDtor() = default; + static bool isKind(const CFGElement &E) { return E.getKind() == BaseDtor; } @@ -293,7 +334,9 @@ public: private: friend class CFGElement; - CFGMemberDtor() {} + + CFGMemberDtor() = default; + static bool isKind(const CFGElement &E) { return E.getKind() == MemberDtor; } @@ -312,7 +355,9 @@ public: private: friend class CFGElement; - CFGTemporaryDtor() {} + + CFGTemporaryDtor() = default; + static bool isKind(const CFGElement &E) { return E.getKind() == TemporaryDtor; } @@ -326,8 +371,9 @@ private: /// of matching full expression. class CFGTerminator { llvm::PointerIntPair<Stmt *, 1> Data; + public: - CFGTerminator() {} + CFGTerminator() = default; CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false) : Data(S, TemporaryDtorsBranch) {} @@ -373,21 +419,23 @@ public: /// &&, || expression that uses result of && or ||, RHS /// /// But note that any of that may be NULL in case of optimized-out edges. -/// class CFGBlock { class ElementList { - typedef BumpVector<CFGElement> ImplTy; + using ImplTy = BumpVector<CFGElement>; + ImplTy Impl; + public: ElementList(BumpVectorContext &C) : Impl(C, 4) {} - typedef std::reverse_iterator<ImplTy::iterator> iterator; - typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; - typedef ImplTy::iterator reverse_iterator; - typedef ImplTy::const_iterator const_reverse_iterator; - typedef ImplTy::const_reference const_reference; + using iterator = std::reverse_iterator<ImplTy::iterator>; + using const_iterator = std::reverse_iterator<ImplTy::const_iterator>; + using reverse_iterator = ImplTy::iterator; + using const_reverse_iterator = ImplTy::const_iterator; + using const_reference = ImplTy::const_reference; void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } + reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, BumpVectorContext &C) { return Impl.insert(I, Cnt, E, C); @@ -405,10 +453,10 @@ class CFGBlock { const_reverse_iterator rbegin() const { return Impl.begin(); } const_reverse_iterator rend() const { return Impl.end(); } - CFGElement operator[](size_t i) const { - assert(i < Impl.size()); - return Impl[Impl.size() - 1 - i]; - } + CFGElement operator[](size_t i) const { + assert(i < Impl.size()); + return Impl[Impl.size() - 1 - i]; + } size_t size() const { return Impl.size(); } bool empty() const { return Impl.empty(); } @@ -420,7 +468,7 @@ class CFGBlock { /// Label - An (optional) label that prefixes the executable /// statements in the block. When this variable is non-NULL, it is /// either an instance of LabelStmt, SwitchCase or CXXCatchStmt. - Stmt *Label; + Stmt *Label = nullptr; /// Terminator - The terminator for a basic block that /// indicates the type of control-flow that occurs between a block @@ -430,7 +478,7 @@ class CFGBlock { /// LoopTarget - Some blocks are used to represent the "loop edge" to /// the start of a loop from within the loop body. This Stmt* will be /// refer to the loop statement for such blocks (and be null otherwise). - const Stmt *LoopTarget; + const Stmt *LoopTarget = nullptr; /// BlockID - A numerical ID assigned to a CFGBlock during construction /// of the CFG. @@ -450,7 +498,7 @@ public: }; CFGBlock *ReachableBlock; - llvm::PointerIntPair<CFGBlock*, 2> UnreachableBlock; + llvm::PointerIntPair<CFGBlock *, 2> UnreachableBlock; public: /// Construct an AdjacentBlock with a possibly unreachable block. @@ -493,7 +541,7 @@ public: private: /// Predecessors/Successors - Keep track of the predecessor / successor /// CFG blocks. - typedef BumpVector<AdjacentBlock> AdjacentBlocks; + using AdjacentBlocks = BumpVector<AdjacentBlock>; AdjacentBlocks Preds; AdjacentBlocks Succs; @@ -513,15 +561,14 @@ private: public: explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent) - : Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr), - BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false), - Parent(parent) {} + : Elements(C), Terminator(nullptr), BlockID(blockid), Preds(C, 1), + Succs(C, 1), HasNoReturnElement(false), Parent(parent) {} // Statement iterators - typedef ElementList::iterator iterator; - typedef ElementList::const_iterator const_iterator; - typedef ElementList::reverse_iterator reverse_iterator; - typedef ElementList::const_reverse_iterator const_reverse_iterator; + using iterator = ElementList::iterator; + using const_iterator = ElementList::const_iterator; + using reverse_iterator = ElementList::reverse_iterator; + using const_reverse_iterator = ElementList::const_reverse_iterator; CFGElement front() const { return Elements.front(); } CFGElement back() const { return Elements.back(); } @@ -542,19 +589,19 @@ public: CFGElement operator[](size_t i) const { return Elements[i]; } // CFG iterators - typedef AdjacentBlocks::iterator pred_iterator; - typedef AdjacentBlocks::const_iterator const_pred_iterator; - typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; - typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; - typedef llvm::iterator_range<pred_iterator> pred_range; - typedef llvm::iterator_range<const_pred_iterator> pred_const_range; + using pred_iterator = AdjacentBlocks::iterator; + using const_pred_iterator = AdjacentBlocks::const_iterator; + using pred_reverse_iterator = AdjacentBlocks::reverse_iterator; + using const_pred_reverse_iterator = AdjacentBlocks::const_reverse_iterator; + using pred_range = llvm::iterator_range<pred_iterator>; + using pred_const_range = llvm::iterator_range<const_pred_iterator>; - typedef AdjacentBlocks::iterator succ_iterator; - typedef AdjacentBlocks::const_iterator const_succ_iterator; - typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; - typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; - typedef llvm::iterator_range<succ_iterator> succ_range; - typedef llvm::iterator_range<const_succ_iterator> succ_const_range; + using succ_iterator = AdjacentBlocks::iterator; + using const_succ_iterator = AdjacentBlocks::const_iterator; + using succ_reverse_iterator = AdjacentBlocks::reverse_iterator; + using const_succ_reverse_iterator = AdjacentBlocks::const_reverse_iterator; + using succ_range = llvm::iterator_range<succ_iterator>; + using succ_const_range = llvm::iterator_range<const_succ_iterator>; pred_iterator pred_begin() { return Preds.begin(); } pred_iterator pred_end() { return Preds.end(); } @@ -566,10 +613,11 @@ public: const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } - pred_range preds() { + pred_range preds() { return pred_range(pred_begin(), pred_end()); } - pred_const_range preds() const { + + pred_const_range preds() const { return pred_const_range(pred_begin(), pred_end()); } @@ -583,10 +631,11 @@ public: const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } - succ_range succs() { + succ_range succs() { return succ_range(succ_begin(), succ_end()); } - succ_const_range succs() const { + + succ_const_range succs() const { return succ_const_range(succ_begin(), succ_end()); } @@ -599,13 +648,11 @@ public: class FilterOptions { public: - FilterOptions() { - IgnoreNullPredecessors = 1; - IgnoreDefaultsWithCoveredEnums = 0; - } - unsigned IgnoreNullPredecessors : 1; unsigned IgnoreDefaultsWithCoveredEnums : 1; + + FilterOptions() + : IgnoreNullPredecessors(1), IgnoreDefaultsWithCoveredEnums(0) {} }; static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, @@ -617,6 +664,7 @@ public: IMPL I, E; const FilterOptions F; const CFGBlock *From; + public: explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e, const CFGBlock *from, @@ -634,17 +682,18 @@ public: } const CFGBlock *operator*() const { return *I; } + private: bool Filter(const CFGBlock *To) { return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To); } }; - typedef FilteredCFGBlockIterator<const_pred_iterator, true> - filtered_pred_iterator; + using filtered_pred_iterator = + FilteredCFGBlockIterator<const_pred_iterator, true>; - typedef FilteredCFGBlockIterator<const_succ_iterator, false> - filtered_succ_iterator; + using filtered_succ_iterator = + FilteredCFGBlockIterator<const_succ_iterator, false>; filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const { return filtered_pred_iterator(pred_begin(), pred_end(), this, f); @@ -728,6 +777,10 @@ public: Elements.push_back(CFGLifetimeEnds(VD, S), C); } + void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) { + Elements.push_back(CFGLoopExit(LoopStmt), C); + } + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { Elements.push_back(CFGDeleteDtor(RD, DE), C); } @@ -763,11 +816,12 @@ public: /// operator error is found when building the CFG. class CFGCallback { public: - CFGCallback() {} + CFGCallback() = default; + virtual ~CFGCallback() = default; + virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {} virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue) {} - virtual ~CFGCallback() {} }; /// CFG - Represents a source-level, intra-procedural CFG that represents the @@ -785,19 +839,24 @@ public: class BuildOptions { std::bitset<Stmt::lastStmtConstant> alwaysAddMask; + public: - typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; - ForcedBlkExprs **forcedBlkExprs; - CFGCallback *Observer; - bool PruneTriviallyFalseEdges; - bool AddEHEdges; - bool AddInitializers; - bool AddImplicitDtors; - bool AddLifetime; - bool AddTemporaryDtors; - bool AddStaticInitBranches; - bool AddCXXNewAllocator; - bool AddCXXDefaultInitExprInCtors; + using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>; + + ForcedBlkExprs **forcedBlkExprs = nullptr; + CFGCallback *Observer = nullptr; + bool PruneTriviallyFalseEdges = true; + bool AddEHEdges = false; + bool AddInitializers = false; + bool AddImplicitDtors = false; + bool AddLifetime = false; + bool AddLoopExit = false; + bool AddTemporaryDtors = false; + bool AddStaticInitBranches = false; + bool AddCXXNewAllocator = false; + bool AddCXXDefaultInitExprInCtors = false; + + BuildOptions() = default; bool alwaysAdd(const Stmt *stmt) const { return alwaysAddMask[stmt->getStmtClass()]; @@ -812,15 +871,6 @@ public: alwaysAddMask.set(); return *this; } - - BuildOptions() - : forcedBlkExprs(nullptr), Observer(nullptr), - PruneTriviallyFalseEdges(true), - AddEHEdges(false), - AddInitializers(false), AddImplicitDtors(false), - AddLifetime(false), - AddTemporaryDtors(false), AddStaticInitBranches(false), - AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} }; /// buildCFG - Builds a CFG from an AST. @@ -844,11 +894,11 @@ public: // Block Iterators //===--------------------------------------------------------------------===// - typedef BumpVector<CFGBlock*> CFGBlockListTy; - typedef CFGBlockListTy::iterator iterator; - typedef CFGBlockListTy::const_iterator const_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + using CFGBlockListTy = BumpVector<CFGBlock *>; + using iterator = CFGBlockListTy::iterator; + using const_iterator = CFGBlockListTy::const_iterator; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; CFGBlock & front() { return *Blocks.front(); } CFGBlock & back() { return *Blocks.back(); } @@ -876,10 +926,12 @@ public: CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; } const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; } - typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator; + using try_block_iterator = std::vector<const CFGBlock *>::const_iterator; + try_block_iterator try_blocks_begin() const { return TryDispatchBlocks.begin(); } + try_block_iterator try_blocks_end() const { return TryDispatchBlocks.end(); } @@ -900,9 +952,9 @@ public: SyntheticDeclStmts[Synthetic] = Source; } - typedef llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator - synthetic_stmt_iterator; - typedef llvm::iterator_range<synthetic_stmt_iterator> synthetic_stmt_range; + using synthetic_stmt_iterator = + llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator; + using synthetic_stmt_range = llvm::iterator_range<synthetic_stmt_iterator>; /// Iterates over synthetic DeclStmts in the CFG. /// @@ -962,9 +1014,7 @@ public: // Internal: constructors and data. //===--------------------------------------------------------------------===// - CFG() - : Entry(nullptr), Exit(nullptr), IndirectGotoBlock(nullptr), NumBlockIDs(0), - Blocks(BlkBVC, 10) {} + CFG() : Blocks(BlkBVC, 10) {} llvm::BumpPtrAllocator& getAllocator() { return BlkBVC.getAllocator(); @@ -975,11 +1025,13 @@ public: } private: - CFGBlock *Entry; - CFGBlock *Exit; - CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch - // for indirect gotos - unsigned NumBlockIDs; + CFGBlock *Entry = nullptr; + CFGBlock *Exit = nullptr; + + // Special block to contain collective dispatch for indirect gotos + CFGBlock* IndirectGotoBlock = nullptr; + + unsigned NumBlockIDs = 0; BumpVectorContext BlkBVC; @@ -993,7 +1045,8 @@ private: /// source DeclStmt. llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts; }; -} // end namespace clang + +} // namespace clang //===----------------------------------------------------------------------===// // GraphTraits specializations for CFG basic block graphs (source-level CFGs) @@ -1004,7 +1057,8 @@ namespace llvm { /// Implement simplify_type for CFGTerminator, so that we can dyn_cast from /// CFGTerminator to a specific Stmt class. template <> struct simplify_type< ::clang::CFGTerminator> { - typedef ::clang::Stmt *SimpleType; + using SimpleType = ::clang::Stmt *; + static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) { return Val.getStmt(); } @@ -1013,50 +1067,44 @@ template <> struct simplify_type< ::clang::CFGTerminator> { // Traits for: CFGBlock template <> struct GraphTraits< ::clang::CFGBlock *> { - typedef ::clang::CFGBlock *NodeRef; - typedef ::clang::CFGBlock::succ_iterator ChildIteratorType; + using NodeRef = ::clang::CFGBlock *; + using ChildIteratorType = ::clang::CFGBlock::succ_iterator; static NodeRef getEntryNode(::clang::CFGBlock *BB) { return BB; } - static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); } }; template <> struct GraphTraits< const ::clang::CFGBlock *> { - typedef const ::clang::CFGBlock *NodeRef; - typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType; + using NodeRef = const ::clang::CFGBlock *; + using ChildIteratorType = ::clang::CFGBlock::const_succ_iterator; static NodeRef getEntryNode(const clang::CFGBlock *BB) { return BB; } - static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); } }; -template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > { - typedef ::clang::CFGBlock *NodeRef; - typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; +template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> { + using NodeRef = ::clang::CFGBlock *; + using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator; static NodeRef getEntryNode(Inverse<::clang::CFGBlock *> G) { return G.Graph; } static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); } }; -template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { - typedef const ::clang::CFGBlock *NodeRef; - typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; +template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> { + using NodeRef = const ::clang::CFGBlock *; + using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator; static NodeRef getEntryNode(Inverse<const ::clang::CFGBlock *> G) { return G.Graph; } static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); } }; @@ -1064,8 +1112,7 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { template <> struct GraphTraits< ::clang::CFG* > : public GraphTraits< ::clang::CFGBlock *> { - - typedef ::clang::CFG::iterator nodes_iterator; + using nodes_iterator = ::clang::CFG::iterator; static NodeRef getEntryNode(::clang::CFG *F) { return &F->getEntry(); } static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();} @@ -1075,44 +1122,47 @@ template <> struct GraphTraits< ::clang::CFG* > template <> struct GraphTraits<const ::clang::CFG* > : public GraphTraits<const ::clang::CFGBlock *> { - - typedef ::clang::CFG::const_iterator nodes_iterator; + using nodes_iterator = ::clang::CFG::const_iterator; static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getEntry(); } + static nodes_iterator nodes_begin( const ::clang::CFG* F) { return F->nodes_begin(); } + static nodes_iterator nodes_end( const ::clang::CFG* F) { return F->nodes_end(); } + static unsigned size(const ::clang::CFG* F) { return F->size(); } }; -template <> struct GraphTraits<Inverse< ::clang::CFG*> > - : public GraphTraits<Inverse< ::clang::CFGBlock*> > { - - typedef ::clang::CFG::iterator nodes_iterator; +template <> struct GraphTraits<Inverse< ::clang::CFG *>> + : public GraphTraits<Inverse< ::clang::CFGBlock *>> { + using nodes_iterator = ::clang::CFG::iterator; static NodeRef getEntryNode(::clang::CFG *F) { return &F->getExit(); } static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();} static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); } }; -template <> struct GraphTraits<Inverse<const ::clang::CFG*> > - : public GraphTraits<Inverse<const ::clang::CFGBlock*> > { - - typedef ::clang::CFG::const_iterator nodes_iterator; +template <> struct GraphTraits<Inverse<const ::clang::CFG *>> + : public GraphTraits<Inverse<const ::clang::CFGBlock *>> { + using nodes_iterator = ::clang::CFG::const_iterator; static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->nodes_begin(); } + static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->nodes_end(); } }; -} // end llvm namespace + +} // namespace llvm #endif // LLVM_CLANG_ANALYSIS_CFG_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h index a2a27a8e47c75..bdcdfecddc3eb 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h @@ -1,4 +1,4 @@ -//== CallGraph.h - AST-based Call graph ------------------------*- C++ -*--==// +//===- CallGraph.h - AST-based Call graph -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,19 +12,27 @@ // A call graph for functions whose definitions/bodies are available in the // current translation unit. The graph has a "virtual" root node that contains // edges to all externally available functions. +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H #define LLVM_CLANG_ANALYSIS_CALLGRAPH_H -#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include <memory> namespace clang { + class CallGraphNode; +class Decl; +class DeclContext; +class Stmt; /// \brief The AST-based call graph. /// @@ -34,8 +42,8 @@ class CallGraphNode; class CallGraph : public RecursiveASTVisitor<CallGraph> { friend class CallGraphNode; - typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>> - FunctionMapTy; + using FunctionMapTy = + llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>; /// FunctionMap owns all CallGraphNodes. FunctionMapTy FunctionMap; @@ -65,10 +73,11 @@ public: /// one into the graph. CallGraphNode *getOrInsertNode(Decl *); + using iterator = FunctionMapTy::iterator; + using const_iterator = FunctionMapTy::const_iterator; + /// Iterators through all the elements in the graph. Note, this gives /// non-deterministic order. - typedef FunctionMapTy::iterator iterator; - typedef FunctionMapTy::const_iterator const_iterator; iterator begin() { return FunctionMap.begin(); } iterator end() { return FunctionMap.end(); } const_iterator begin() const { return FunctionMap.begin(); } @@ -84,8 +93,8 @@ public: /// Iterators through all the nodes of the graph that have no parent. These /// are the unreachable nodes, which are either unused or are due to us /// failing to add a call edge due to the analysis imprecision. - typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator; - typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator; + using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator; + using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator; void print(raw_ostream &os) const; void dump() const; @@ -133,7 +142,7 @@ private: class CallGraphNode { public: - typedef CallGraphNode* CallRecord; + using CallRecord = CallGraphNode *; private: /// \brief The function/method declaration. @@ -145,17 +154,17 @@ private: public: CallGraphNode(Decl *D) : FD(D) {} - typedef SmallVectorImpl<CallRecord>::iterator iterator; - typedef SmallVectorImpl<CallRecord>::const_iterator const_iterator; + using iterator = SmallVectorImpl<CallRecord>::iterator; + using const_iterator = SmallVectorImpl<CallRecord>::const_iterator; /// Iterators through all the callees/children of the node. - inline iterator begin() { return CalledFunctions.begin(); } - inline iterator end() { return CalledFunctions.end(); } - inline const_iterator begin() const { return CalledFunctions.begin(); } - inline const_iterator end() const { return CalledFunctions.end(); } + iterator begin() { return CalledFunctions.begin(); } + iterator end() { return CalledFunctions.end(); } + const_iterator begin() const { return CalledFunctions.begin(); } + const_iterator end() const { return CalledFunctions.end(); } - inline bool empty() const {return CalledFunctions.empty(); } - inline unsigned size() const {return CalledFunctions.size(); } + bool empty() const { return CalledFunctions.empty(); } + unsigned size() const { return CalledFunctions.size(); } void addCallee(CallGraphNode *N) { CalledFunctions.push_back(N); @@ -167,35 +176,33 @@ public: void dump() const; }; -} // end clang namespace +} // namespace clang // Graph traits for iteration, viewing. namespace llvm { + template <> struct GraphTraits<clang::CallGraphNode*> { - typedef clang::CallGraphNode NodeType; - typedef clang::CallGraphNode *NodeRef; - typedef NodeType::iterator ChildIteratorType; + using NodeType = clang::CallGraphNode; + using NodeRef = clang::CallGraphNode *; + using ChildIteratorType = NodeType::iterator; static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } - static inline ChildIteratorType child_begin(NodeType *N) { - return N->begin(); - } - static inline ChildIteratorType child_end(NodeType *N) { return N->end(); } + static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } + static ChildIteratorType child_end(NodeType *N) { return N->end(); } }; template <> struct GraphTraits<const clang::CallGraphNode*> { - typedef const clang::CallGraphNode NodeType; - typedef const clang::CallGraphNode *NodeRef; - typedef NodeType::const_iterator ChildIteratorType; + using NodeType = const clang::CallGraphNode; + using NodeRef = const clang::CallGraphNode *; + using ChildIteratorType = NodeType::const_iterator; static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } - static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();} - static inline ChildIteratorType child_end(NodeType *N) { return N->end(); } + static ChildIteratorType child_begin(NodeType *N) { return N->begin();} + static ChildIteratorType child_end(NodeType *N) { return N->end(); } }; template <> struct GraphTraits<clang::CallGraph*> : public GraphTraits<clang::CallGraphNode*> { - static NodeType *getEntryNode(clang::CallGraph *CGN) { return CGN->getRoot(); // Start at the external node! } @@ -206,19 +213,18 @@ template <> struct GraphTraits<clang::CallGraph*> } // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)> - nodes_iterator; + using nodes_iterator = + mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>; static nodes_iterator nodes_begin(clang::CallGraph *CG) { return nodes_iterator(CG->begin(), &CGGetValue); } + static nodes_iterator nodes_end (clang::CallGraph *CG) { return nodes_iterator(CG->end(), &CGGetValue); } - static unsigned size(clang::CallGraph *CG) { - return CG->size(); - } + static unsigned size(clang::CallGraph *CG) { return CG->size(); } }; template <> struct GraphTraits<const clang::CallGraph*> : @@ -233,21 +239,20 @@ template <> struct GraphTraits<const clang::CallGraph*> : } // nodes_iterator/begin/end - Allow iteration over all nodes in the graph - typedef mapped_iterator<clang::CallGraph::const_iterator, - decltype(&CGGetValue)> - nodes_iterator; + using nodes_iterator = + mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>; static nodes_iterator nodes_begin(const clang::CallGraph *CG) { return nodes_iterator(CG->begin(), &CGGetValue); } + static nodes_iterator nodes_end(const clang::CallGraph *CG) { return nodes_iterator(CG->end(), &CGGetValue); } - static unsigned size(const clang::CallGraph *CG) { - return CG->size(); - } + + static unsigned size(const clang::CallGraph *CG) { return CG->size(); } }; -} // end llvm namespace +} // namespace llvm -#endif +#endif // LLVM_CLANG_ANALYSIS_CALLGRAPH_H diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h index 6339deef41bde..051b9236658cf 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h @@ -7,19 +7,15 @@ // //===----------------------------------------------------------------------===// /// -/// /file -/// This file defines classes for searching and anlyzing source code clones. +/// \file +/// This file defines classes for searching and analyzing source code clones. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_CLONEDETECTION_H #define LLVM_CLANG_AST_CLONEDETECTION_H -#include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Regex.h" #include <vector> @@ -31,192 +27,6 @@ class VarDecl; class ASTContext; class CompoundStmt; -namespace clone_detection { - -/// Returns a string that represents all macro expansions that expanded into the -/// given SourceLocation. -/// -/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations -/// A and B are expanded from the same macros in the same order. -std::string getMacroStack(SourceLocation Loc, ASTContext &Context); - -/// Collects the data of a single Stmt. -/// -/// This class defines what a code clone is: If it collects for two statements -/// the same data, then those two statements are considered to be clones of each -/// other. -/// -/// All collected data is forwarded to the given data consumer of the type T. -/// The data consumer class needs to provide a member method with the signature: -/// update(StringRef Str) -template <typename T> -class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> { - - ASTContext &Context; - /// The data sink to which all data is forwarded. - T &DataConsumer; - -public: - /// Collects data of the given Stmt. - /// \param S The given statement. - /// \param Context The ASTContext of S. - /// \param DataConsumer The data sink to which all data is forwarded. - StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer) - : Context(Context), DataConsumer(DataConsumer) { - this->Visit(S); - } - - typedef unsigned DataPiece; - - // Below are utility methods for appending different data to the vector. - - void addData(DataPiece Integer) { - DataConsumer.update( - StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer))); - } - - void addData(llvm::StringRef Str) { DataConsumer.update(Str); } - - void addData(const QualType &QT) { addData(QT.getAsString()); } - -// The functions below collect the class specific data of each Stmt subclass. - -// Utility macro for defining a visit method for a given class. This method -// calls back to the ConstStmtVisitor to visit all parent classes. -#define DEF_ADD_DATA(CLASS, CODE) \ - void Visit##CLASS(const CLASS *S) { \ - CODE; \ - ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \ - } - - DEF_ADD_DATA(Stmt, { - addData(S->getStmtClass()); - // This ensures that macro generated code isn't identical to macro-generated - // code. - addData(getMacroStack(S->getLocStart(), Context)); - addData(getMacroStack(S->getLocEnd(), Context)); - }) - DEF_ADD_DATA(Expr, { addData(S->getType()); }) - - //--- Builtin functionality ----------------------------------------------// - DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); }) - DEF_ADD_DATA(TypeTraitExpr, { - addData(S->getTrait()); - for (unsigned i = 0; i < S->getNumArgs(); ++i) - addData(S->getArg(i)->getType()); - }) - - //--- Calls --------------------------------------------------------------// - DEF_ADD_DATA(CallExpr, { - // Function pointers don't have a callee and we just skip hashing it. - if (const FunctionDecl *D = S->getDirectCallee()) { - // If the function is a template specialization, we also need to handle - // the template arguments as they are not included in the qualified name. - if (auto Args = D->getTemplateSpecializationArgs()) { - std::string ArgString; - - // Print all template arguments into ArgString - llvm::raw_string_ostream OS(ArgString); - for (unsigned i = 0; i < Args->size(); ++i) { - Args->get(i).print(Context.getLangOpts(), OS); - // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. - OS << '\n'; - } - OS.flush(); - - addData(ArgString); - } - addData(D->getQualifiedNameAsString()); - } - }) - - //--- Exceptions ---------------------------------------------------------// - DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); }) - - //--- C++ OOP Stmts ------------------------------------------------------// - DEF_ADD_DATA(CXXDeleteExpr, { - addData(S->isArrayFormAsWritten()); - addData(S->isGlobalDelete()); - }) - - //--- Casts --------------------------------------------------------------// - DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); }) - - //--- Miscellaneous Exprs ------------------------------------------------// - DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); }) - DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); }) - - //--- Control flow -------------------------------------------------------// - DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); }) - DEF_ADD_DATA(IndirectGotoStmt, { - if (S->getConstantTarget()) - addData(S->getConstantTarget()->getName()); - }) - DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); }) - DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); }) - DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); }) - - //--- Objective-C --------------------------------------------------------// - DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); }) - DEF_ADD_DATA(ObjCPropertyRefExpr, { - addData(S->isSuperReceiver()); - addData(S->isImplicitProperty()); - }) - DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); }) - - //--- Miscellaneous Stmts ------------------------------------------------// - DEF_ADD_DATA(CXXFoldExpr, { - addData(S->isRightFold()); - addData(S->getOperator()); - }) - DEF_ADD_DATA(GenericSelectionExpr, { - for (unsigned i = 0; i < S->getNumAssocs(); ++i) { - addData(S->getAssocType(i)); - } - }) - DEF_ADD_DATA(LambdaExpr, { - for (const LambdaCapture &C : S->captures()) { - addData(C.isPackExpansion()); - addData(C.getCaptureKind()); - if (C.capturesVariable()) - addData(C.getCapturedVar()->getType()); - } - addData(S->isGenericLambda()); - addData(S->isMutable()); - }) - DEF_ADD_DATA(DeclStmt, { - auto numDecls = std::distance(S->decl_begin(), S->decl_end()); - addData(static_cast<DataPiece>(numDecls)); - for (const Decl *D : S->decls()) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - addData(VD->getType()); - } - } - }) - DEF_ADD_DATA(AsmStmt, { - addData(S->isSimple()); - addData(S->isVolatile()); - addData(S->generateAsmString(Context)); - for (unsigned i = 0; i < S->getNumInputs(); ++i) { - addData(S->getInputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumOutputs(); ++i) { - addData(S->getOutputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumClobbers(); ++i) { - addData(S->getClobber(i)); - } - }) - DEF_ADD_DATA(AttributedStmt, { - for (const Attr *A : S->getAttrs()) { - addData(std::string(A->getSpelling())); - } - }) -}; -} // namespace clone_detection - /// Identifies a list of statements. /// /// Can either identify a single arbitrary Stmt object, a continuous sequence of @@ -423,9 +233,9 @@ public: /// filtered. /// \param Filter The filter function that should return true for all groups /// that should be removed from the list. - static void - filterGroups(std::vector<CloneDetector::CloneGroup> &CloneGroups, - std::function<bool(const CloneDetector::CloneGroup &)> Filter) { + static void filterGroups( + std::vector<CloneDetector::CloneGroup> &CloneGroups, + llvm::function_ref<bool(const CloneDetector::CloneGroup &)> Filter) { CloneGroups.erase( std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter), CloneGroups.end()); @@ -439,25 +249,29 @@ public: /// to the same CloneGroup. static void splitCloneGroups( std::vector<CloneDetector::CloneGroup> &CloneGroups, - std::function<bool(const StmtSequence &, const StmtSequence &)> Compare); + llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)> + Compare); }; -/// Searches all children of the given clones for type II clones (i.e. they are -/// identical in every aspect beside the used variable names). -class RecursiveCloneTypeIIConstraint { - - /// Generates and saves a hash code for the given Stmt. - /// \param S The given Stmt. - /// \param D The Decl containing S. - /// \param StmtsByHash Output parameter that will contain the hash codes for - /// each StmtSequence in the given Stmt. - /// \return The hash code of the given Stmt. - /// - /// If the given Stmt is a CompoundStmt, this method will also generate - /// hashes for all possible StmtSequences in the children of this Stmt. - size_t saveHash(const Stmt *S, const Decl *D, - std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash); +/// This constraint moves clones into clone groups of type II via hashing. +/// +/// Clones with different hash values are moved into separate clone groups. +/// Collisions are possible, and this constraint does nothing to address this +/// them. Add the slower RecursiveCloneTypeIIVerifyConstraint later in the +/// constraint chain, not necessarily immediately, to eliminate hash collisions +/// through a more detailed analysis. +class RecursiveCloneTypeIIHashConstraint { +public: + void constrain(std::vector<CloneDetector::CloneGroup> &Sequences); +}; +/// This constraint moves clones into clone groups of type II by comparing them. +/// +/// Clones that aren't type II clones are moved into separate clone groups. +/// In contrast to the RecursiveCloneTypeIIHashConstraint, all clones in a clone +/// group are guaranteed to be be type II clones of each other, but it is too +/// slow to efficiently handle large amounts of clones. +class RecursiveCloneTypeIIVerifyConstraint { public: void constrain(std::vector<CloneDetector::CloneGroup> &Sequences); }; @@ -474,14 +288,19 @@ public: MinComplexityConstraint(unsigned MinComplexity) : MinComplexity(MinComplexity) {} - size_t calculateStmtComplexity(const StmtSequence &Seq, + /// Calculates the complexity of the given StmtSequence. + /// \param Limit The limit of complexity we probe for. After reaching + /// this limit during calculation, this method is exiting + /// early to improve performance and returns this limit. + size_t calculateStmtComplexity(const StmtSequence &Seq, std::size_t Limit, const std::string &ParentMacroStack = ""); void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) { CloneConstraint::filterGroups( CloneGroups, [this](const CloneDetector::CloneGroup &A) { if (!A.empty()) - return calculateStmtComplexity(A.front()) < MinComplexity; + return calculateStmtComplexity(A.front(), MinComplexity) < + MinComplexity; else return false; }); diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h b/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h index be5adfb29423c..2d59dec48a880 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H #define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -83,6 +83,7 @@ public: PostImplicitCallKind, MinImplicitCallKind = PreImplicitCallKind, MaxImplicitCallKind = PostImplicitCallKind, + LoopExitKind, EpsilonKind}; private: @@ -654,6 +655,29 @@ private: } }; +/// Represents a point when we exit a loop. +/// When this ProgramPoint is encountered we can be sure that the symbolic +/// execution of the corresponding LoopStmt is finished on the given path. +/// Note: It is possible to encounter a LoopExit element when we haven't even +/// encountered the loop itself. At the current state not all loop exits will +/// result in a LoopExit program point. +class LoopExit : public ProgramPoint { +public: + LoopExit(const Stmt *LoopStmt, const LocationContext *LC) + : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {} + + const Stmt *getLoopStmt() const { + return static_cast<const Stmt *>(getData1()); + } + +private: + friend class ProgramPoint; + LoopExit() {} + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == LoopExitKind; + } +}; + /// This is a meta program point, which should be skipped by all the diagnostic /// reasoning etc. class EpsilonPoint : public ProgramPoint { diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h b/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h index 591d17b9bc03c..5940520855ef2 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/Support/BumpVector.h @@ -1,4 +1,4 @@ -//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- C++ -*-=// +//===- BumpVector.h - Vector-like ADT that uses bump allocation -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -21,16 +21,18 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/type_traits.h" -#include <algorithm> +#include <cassert> +#include <cstddef> #include <cstring> #include <iterator> #include <memory> +#include <type_traits> namespace clang { class BumpVectorContext { llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc; + public: /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator /// and destroys it when the BumpVectorContext object is destroyed. @@ -56,11 +58,13 @@ public: template<typename T> class BumpVector { - T *Begin, *End, *Capacity; + T *Begin = nullptr; + T *End = nullptr; + T *Capacity = nullptr; + public: // Default ctor - Initialize to empty. - explicit BumpVector(BumpVectorContext &C, unsigned N) - : Begin(nullptr), End(nullptr), Capacity(nullptr) { + explicit BumpVector(BumpVectorContext &C, unsigned N) { reserve(C, N); } @@ -71,19 +75,19 @@ public: } } - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T* iterator; - typedef const T* const_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = T; + using iterator = T *; + using const_iterator = const T *; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = std::reverse_iterator<iterator>; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; // forward iterator creation methods. iterator begin() { return Begin; } @@ -92,10 +96,12 @@ public: const_iterator end() const { return End; } // reverse iterator creation methods. - reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } bool empty() const { return Begin == End; } size_type size() const { return End-Begin; } @@ -166,7 +172,7 @@ public: /// iterator to position after last inserted copy. iterator insert(iterator I, size_t Cnt, const_reference E, BumpVectorContext &C) { - assert (I >= Begin && I <= End && "Iterator out of bounds."); + assert(I >= Begin && I <= End && "Iterator out of bounds."); if (End + Cnt <= Capacity) { Retry: move_range_right(I, End, Cnt); @@ -246,5 +252,6 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { Capacity = Begin+NewCapacity; } -} // end: clang namespace -#endif +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h index 95b9b9c7d0b31..6b0090813e9b4 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h @@ -16,25 +16,26 @@ #ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H #define LLVM_CLANG_BASIC_ADDRESSSPACES_H -namespace clang { +#include <assert.h> -namespace LangAS { +namespace clang { /// \brief Defines the address space values used by the address space qualifier /// of QualType. /// -enum ID { +enum class LangAS : unsigned { // The default value 0 is the value used in QualType for the the situation - // where there is no address space qualifier. For most languages, this also - // corresponds to the situation where there is no address space qualifier in - // the source code, except for OpenCL, where the address space value 0 in - // QualType represents private address space in OpenCL source code. + // where there is no address space qualifier. Default = 0, // OpenCL specific address spaces. + // In OpenCL each l-value must have certain non-default address space, each + // r-value must have no address space (i.e. the default address space). The + // pointee of a pointer must have non-default address space. opencl_global, opencl_local, opencl_constant, + opencl_private, opencl_generic, // CUDA specific address spaces. @@ -50,9 +51,24 @@ enum ID { /// The type of a lookup table which maps from language-specific address spaces /// to target-specific ones. -typedef unsigned Map[FirstTargetAddressSpace]; +typedef unsigned LangASMap[(unsigned)LangAS::FirstTargetAddressSpace]; + +/// \return whether \p AS is a target-specific address space rather than a +/// clang AST address space +inline bool isTargetAddressSpace(LangAS AS) { + return (unsigned)AS >= (unsigned)LangAS::FirstTargetAddressSpace; } +inline unsigned toTargetAddressSpace(LangAS AS) { + assert(isTargetAddressSpace(AS)); + return (unsigned)AS - (unsigned)LangAS::FirstTargetAddressSpace; } +inline LangAS getLangASFromTargetAS(unsigned TargetAS) { + return static_cast<LangAS>((TargetAS) + + (unsigned)LangAS::FirstTargetAddressSpace); +} + +} // namespace clang + #endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AlignedAllocation.h b/contrib/llvm/tools/clang/include/clang/Basic/AlignedAllocation.h new file mode 100644 index 0000000000000..b3496949f39ac --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/AlignedAllocation.h @@ -0,0 +1,44 @@ +//===--- AlignedAllocation.h - Aligned Allocation ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a function that returns the minimum OS versions supporting +/// C++17's aligned allocation functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H +#define LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H + +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +inline VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { + switch (OS) { + default: + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.13. + return VersionTuple(10U, 13U); + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0. + return VersionTuple(11U); + case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0. + return VersionTuple(4U); + } + + llvm_unreachable("Unexpected OS"); +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h index fc861a1952a51..1c83e2d0f8a0b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h @@ -18,12 +18,14 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CommentDiagnostic.h" #include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/CrossTU/CrossTUDiagnostic.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Serialization/SerializationDiagnostic.h" +#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" namespace clang { template <size_t SizeOfStr, typename FieldType> diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td index 5c69635b94924..d926fdde4eeed 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td @@ -69,44 +69,47 @@ include "clang/Basic/StmtNodes.td" // // The code fragment is a boolean expression that will confirm that the subject // meets the requirements; the subject will have the name S, and will have the -// type specified by the base. It should be a simple boolean expression. -class SubsetSubject<AttrSubject base, code check> : AttrSubject { +// type specified by the base. It should be a simple boolean expression. The +// diagnostic string should be a comma-separated list of subject names. +class SubsetSubject<AttrSubject base, code check, string diag> : AttrSubject { AttrSubject Base = base; code CheckCode = check; + string DiagSpelling = diag; } -// This is the type of a variable which C++11 allows alignas(...) to appertain -// to. -def NormalVar : SubsetSubject<Var, - [{S->getStorageClass() != VarDecl::Register && - S->getKind() != Decl::ImplicitParam && - S->getKind() != Decl::ParmVar && - S->getKind() != Decl::NonTypeTemplateParm}]>; +def LocalVar : SubsetSubject<Var, + [{S->hasLocalStorage() && !isa<ParmVarDecl>(S)}], + "local variables">; def NonParmVar : SubsetSubject<Var, - [{S->getKind() != Decl::ParmVar}]>; + [{S->getKind() != Decl::ParmVar}], + "variables">; def NonBitField : SubsetSubject<Field, - [{!S->isBitField()}]>; + [{!S->isBitField()}], + "non-bit-field non-static data members">; def ObjCInstanceMethod : SubsetSubject<ObjCMethod, - [{S->isInstanceMethod()}]>; + [{S->isInstanceMethod()}], + "Objective-C instance methods">; def ObjCInterfaceDeclInitMethod : SubsetSubject<ObjCMethod, [{S->getMethodFamily() == OMF_init && (isa<ObjCInterfaceDecl>(S->getDeclContext()) || (isa<ObjCCategoryDecl>(S->getDeclContext()) && - cast<ObjCCategoryDecl>(S->getDeclContext())->IsClassExtension()))}]>; + cast<ObjCCategoryDecl>(S->getDeclContext())->IsClassExtension()))}], + "init methods of interface or class extension declarations">; def Struct : SubsetSubject<Record, - [{!S->isUnion()}]>; + [{!S->isUnion()}], "structs">; def TLSVar : SubsetSubject<Var, - [{S->getTLSKind() != 0}]>; + [{S->getTLSKind() != 0}], "thread-local variables">; def SharedVar : SubsetSubject<Var, - [{S->hasGlobalStorage() && !S->getTLSKind()}]>; + [{S->hasGlobalStorage() && !S->getTLSKind()}], + "global variables">; def GlobalVar : SubsetSubject<Var, - [{S->hasGlobalStorage()}]>; + [{S->hasGlobalStorage()}], "global variables">; // FIXME: this hack is needed because DeclNodes.td defines the base Decl node // type to be a class, not a definition. This makes it impossible to create an @@ -115,11 +118,12 @@ def GlobalVar : SubsetSubject<Var, // the case of a SubsetSubject, there's no way to express it without this hack. def DeclBase : AttrSubject; def FunctionLike : SubsetSubject<DeclBase, - [{S->getFunctionType(false) != nullptr}]>; + [{S->getFunctionType(false) != nullptr}], + "functions, function pointers">; -def OpenCLKernelFunction : SubsetSubject<Function, [{ - S->hasAttr<OpenCLKernelAttr>() -}]>; +def OpenCLKernelFunction + : SubsetSubject<Function, [{S->hasAttr<OpenCLKernelAttr>()}], + "kernel functions">; // HasFunctionProto is a more strict version of FunctionLike, so it should // never be specified in a Subjects list along with FunctionLike (due to the @@ -128,7 +132,8 @@ def HasFunctionProto : SubsetSubject<DeclBase, [{(S->getFunctionType(true) != nullptr && isa<FunctionProtoType>(S->getFunctionType())) || isa<ObjCMethodDecl>(S) || - isa<BlockDecl>(S)}]>; + isa<BlockDecl>(S)}], + "non-K&R-style functions">; // A single argument to an attribute class Argument<string name, bit optional, bit fake = 0> { @@ -210,18 +215,26 @@ class CXX11<string namespace, string name, int version = 1> string Namespace = namespace; int Version = version; } +class C2x<string namespace, string name> : Spelling<name, "C2x"> { + string Namespace = namespace; +} + class Keyword<string name> : Spelling<name, "Keyword">; class Pragma<string namespace, string name> : Spelling<name, "Pragma"> { string Namespace = namespace; } -// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also -// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible +// The GCC spelling implies GNU<name> and CXX11<"gnu", name> and also sets +// KnownToGCC to 1. This spelling should be used for any GCC-compatible // attributes. class GCC<string name> : Spelling<name, "GCC"> { let KnownToGCC = 1; } +// The Clang spelling implies GNU<name> and CXX11<"clang", name>. This spelling +// should be used for any Clang-specific attributes. +class Clang<string name> : Spelling<name, "Clang">; + class Accessor<string name, list<Spelling> spellings> { string Name = name; list<Spelling> Spellings = spellings; @@ -264,14 +277,15 @@ class TargetArch<list<string> arches> { } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; def TargetAVR : TargetArch<["avr"]>; -def TargetMips : TargetArch<["mips", "mipsel"]>; +def TargetMips32 : TargetArch<["mips", "mipsel"]>; +def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; def TargetX86 : TargetArch<["x86"]>; def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; -def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> { +def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let OSes = ["Win32"]; } -def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> { +def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let CXXABIs = ["Microsoft"]; } @@ -493,14 +507,13 @@ class IgnoredAttr : Attr { def AbiTag : Attr { let Spellings = [GCC<"abi_tag">]; let Args = [VariadicStringArgument<"Tags">]; - let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag, - "ExpectedStructClassVariableFunctionOrInlineNamespace">; + let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag>; let MeaningfulToClassTemplateDefinition = 1; let Documentation = [AbiTagsDocs]; } def AddressSpace : TypeAttr { - let Spellings = [GNU<"address_space">]; + let Spellings = [Clang<"address_space">]; let Args = [IntArgument<"AddressSpace">]; let Documentation = [Undocumented]; } @@ -508,15 +521,13 @@ def AddressSpace : TypeAttr { def Alias : Attr { let Spellings = [GCC<"alias">]; let Args = [StringArgument<"Aliasee">]; - let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag, - "ExpectedFunctionOrGlobalVar">; + let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>; let Documentation = [Undocumented]; } def Aligned : InheritableAttr { let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">, Keyword<"_Alignas">]; -// let Subjects = SubjectList<[NonBitField, NormalVar, Tag]>; let Args = [AlignedArgument<"Alignment", 1>]; let Accessors = [Accessor<"isGNU", [GCC<"aligned">]>, Accessor<"isC11", [Keyword<"_Alignas">]>, @@ -534,13 +545,15 @@ def AlignValue : Attr { // the future (and a corresponding C++ attribute), but this can be done // later once we decide if we also want them to have slightly-different // semantics than Intel's align_value. + // + // Does not get a [[]] spelling because the attribute is not exposed as such + // by Intel. GNU<"align_value"> // Intel's compiler on Windows also supports: // , Declspec<"align_value"> ]; let Args = [ExprArgument<"Alignment">]; - let Subjects = SubjectList<[Var, TypedefName], WarnDiag, - "ExpectedVariableOrTypedef">; + let Subjects = SubjectList<[Var, TypedefName]>; let Documentation = [AlignValueDocs]; } @@ -558,44 +571,40 @@ def AlwaysInline : InheritableAttr { } def XRayInstrument : InheritableAttr { - let Spellings = [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">, - GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]; - let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag, - "ExpectedFunctionOrMethod">; + let Spellings = [Clang<"xray_always_instrument">, + Clang<"xray_never_instrument">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; let Accessors = [Accessor<"alwaysXRayInstrument", - [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">]>, + [Clang<"xray_always_instrument">]>, Accessor<"neverXRayInstrument", - [GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]>]; + [Clang<"xray_never_instrument">]>]; let Documentation = [XRayDocs]; } def XRayLogArgs : InheritableAttr { - let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">]; - let Subjects = SubjectList< - [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod" - >; + let Spellings = [Clang<"xray_log_args">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; let Args = [UnsignedArgument<"ArgumentCount">]; let Documentation = [XRayDocs]; } def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; - let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">; + let Subjects = SubjectList<[TLSVar], ErrorDiag>; let Args = [StringArgument<"Model">]; let Documentation = [TLSModelDocs]; } def AnalyzerNoReturn : InheritableAttr { + // TODO: should this attribute be exposed with a [[]] spelling under the clang + // vendor namespace, or should it use a vendor namespace specific to the + // analyzer? let Spellings = [GNU<"analyzer_noreturn">]; let Documentation = [Undocumented]; } def Annotate : InheritableParamAttr { - let Spellings = [GNU<"annotate">]; + let Spellings = [Clang<"annotate">]; let Args = [StringArgument<"Annotation">]; // Ensure that the annotate attribute can be used with // '#pragma clang attribute' even though it has no subject list. @@ -606,7 +615,7 @@ def Annotate : InheritableParamAttr { def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { // NOTE: If you add any additional spellings, MSP430Interrupt's, // MipsInterrupt's and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Args = [EnumArgument<"Interrupt", "InterruptType", ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"], @@ -617,14 +626,14 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { } def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> { - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; let ParseKind = "Interrupt"; let Documentation = [AVRInterruptDocs]; } def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> { - let Spellings = [GNU<"signal">]; + let Spellings = [GCC<"signal">]; let Subjects = SubjectList<[Function]>; let Documentation = [AVRSignalDocs]; } @@ -637,6 +646,8 @@ def AsmLabel : InheritableAttr { } def Availability : InheritableAttr { + // TODO: does not have a [[]] spelling because it requires custom parsing + // support. let Spellings = [GNU<"availability">]; let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">, VersionArgument<"deprecated">, VersionArgument<"obsoleted">, @@ -687,8 +698,7 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { } def ExternalSourceSymbol : InheritableAttr { - let Spellings = [GNU<"external_source_symbol">, - CXX11<"clang", "external_source_symbol">]; + let Spellings = [Clang<"external_source_symbol">]; let Args = [StringArgument<"language", 1>, StringArgument<"definedIn", 1>, BoolArgument<"generatedDeclaration", 1>]; @@ -698,12 +708,13 @@ def ExternalSourceSymbol : InheritableAttr { } def Blocks : InheritableAttr { - let Spellings = [GNU<"blocks">]; + let Spellings = [Clang<"blocks">]; let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; let Documentation = [Undocumented]; } def Bounded : IgnoredAttr { + // Does not have a [[]] spelling because the attribute is ignored. let Spellings = [GNU<"bounded">]; } @@ -725,7 +736,7 @@ def CDecl : InheritableAttr { // cf_returns_retained attributes. It is generally applied by // '#pragma clang arc_cf_code_audited' rather than explicitly. def CFAuditedTransfer : InheritableAttr { - let Spellings = [GNU<"cf_audited_transfer">]; + let Spellings = [Clang<"cf_audited_transfer">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } @@ -734,25 +745,25 @@ def CFAuditedTransfer : InheritableAttr { // It indicates that the function has unknown or unautomatable // transfer semantics. def CFUnknownTransfer : InheritableAttr { - let Spellings = [GNU<"cf_unknown_transfer">]; + let Spellings = [Clang<"cf_unknown_transfer">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } def CFReturnsRetained : InheritableAttr { - let Spellings = [GNU<"cf_returns_retained">]; + let Spellings = [Clang<"cf_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; } def CFReturnsNotRetained : InheritableAttr { - let Spellings = [GNU<"cf_returns_not_retained">]; + let Spellings = [Clang<"cf_returns_not_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; } def CFConsumed : InheritableParamAttr { - let Spellings = [GNU<"cf_consumed">]; + let Spellings = [Clang<"cf_consumed">]; let Subjects = SubjectList<[ParmVar]>; let Documentation = [Undocumented]; } @@ -760,7 +771,7 @@ def CFConsumed : InheritableParamAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; let Args = [FunctionArgument<"FunctionDecl">]; - let Subjects = SubjectList<[Var]>; + let Subjects = SubjectList<[LocalVar]>; let Documentation = [Undocumented]; } @@ -788,8 +799,8 @@ def Constructor : InheritableAttr { let Documentation = [Undocumented]; } -// CUDA attributes are spelled __attribute__((attr)) or __declspec(__attr__). - +// CUDA attributes are spelled __attribute__((attr)) or __declspec(__attr__), +// and they do not receive a [[]] spelling. def CUDAConstant : InheritableAttr { let Spellings = [GNU<"constant">, Declspec<"__constant__">]; let Subjects = SubjectList<[Var]>; @@ -851,8 +862,7 @@ def CUDALaunchBounds : InheritableAttr { let Spellings = [GNU<"launch_bounds">, Declspec<"__launch_bounds__">]; let Args = [ExprArgument<"MaxThreads">, ExprArgument<"MinBlocks", 1>]; let LangOpts = [CUDA]; - let Subjects = SubjectList<[ObjCMethod, FunctionLike], WarnDiag, - "ExpectedFunctionOrMethod">; + let Subjects = SubjectList<[ObjCMethod, FunctionLike]>; // An AST node is created for this attribute, but is not used by other parts // of the compiler. However, this node needs to exist in the AST because // non-LLVM backends may be relying on the attribute's presence. @@ -874,11 +884,13 @@ def C11NoReturn : InheritableAttr { } def CXX11NoReturn : InheritableAttr { - let Spellings = [CXX11<"","noreturn", 200809>]; + let Spellings = [CXX11<"", "noreturn", 200809>]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [CXX11NoReturnDocs]; } +// Similar to CUDA, OpenCL attributes do not receive a [[]] spelling because +// the specification does not expose them with one currently. def OpenCLKernel : InheritableAttr { let Spellings = [Keyword<"__kernel">, Keyword<"kernel">]; let Subjects = SubjectList<[Function], ErrorDiag>; @@ -904,8 +916,7 @@ def OpenCLAccess : Attr { let Spellings = [Keyword<"__read_only">, Keyword<"read_only">, Keyword<"__write_only">, Keyword<"write_only">, Keyword<"__read_write">, Keyword<"read_write">]; - let Subjects = SubjectList<[ParmVar, TypedefName], ErrorDiag, - "ExpectedParameterOrTypedef">; + let Subjects = SubjectList<[ParmVar, TypedefName], ErrorDiag>; let Accessors = [Accessor<"isReadOnly", [Keyword<"__read_only">, Keyword<"read_only">]>, Accessor<"isReadWrite", [Keyword<"__read_write">, @@ -957,7 +968,7 @@ def RenderScriptKernel : Attr { def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, - CXX11<"","deprecated", 201309>]; + CXX11<"","deprecated", 201309>, C2x<"", "deprecated">]; let Args = [StringArgument<"Message", 1>, // An optional string argument that enables us to provide a // Fix-It. @@ -988,6 +999,9 @@ def AllocSize : InheritableAttr { } def EnableIf : InheritableAttr { + // Does not have a [[]] spelling because this attribute requires the ability + // to parse function arguments but the attribute is not written in the type + // position. let Spellings = [GNU<"enable_if">]; let Subjects = SubjectList<[Function]>; let Args = [ExprArgument<"Cond">, StringArgument<"Message">]; @@ -996,6 +1010,7 @@ def EnableIf : InheritableAttr { } def ExtVectorType : Attr { + // This is an OpenCL-related attribute and does not receive a [[]] spelling. let Spellings = [GNU<"ext_vector_type">]; let Subjects = SubjectList<[TypedefName], ErrorDiag>; let Args = [ExprArgument<"NumElements">]; @@ -1004,7 +1019,7 @@ def ExtVectorType : Attr { } def FallThrough : StmtAttr { - let Spellings = [CXX11<"", "fallthrough", 201603>, + let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">, CXX11<"clang", "fallthrough">]; // let Subjects = [NullStmt]; let Documentation = [FallthroughDocs]; @@ -1030,20 +1045,19 @@ def Final : InheritableAttr { } def MinSize : InheritableAttr { - let Spellings = [GNU<"minsize">]; + let Spellings = [Clang<"minsize">]; let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; let Documentation = [Undocumented]; } def FlagEnum : InheritableAttr { - let Spellings = [GNU<"flag_enum">]; + let Spellings = [Clang<"flag_enum">]; let Subjects = SubjectList<[Enum]>; let Documentation = [FlagEnumDocs]; } def EnumExtensibility : InheritableAttr { - let Spellings = [GNU<"enum_extensibility">, - CXX11<"clang", "enum_extensibility">]; + let Spellings = [Clang<"enum_extensibility">]; let Subjects = SubjectList<[Enum]>; let Args = [EnumArgument<"Extensibility", "Kind", ["closed", "open"], ["Closed", "Open"]>]; @@ -1060,16 +1074,14 @@ def Format : InheritableAttr { let Spellings = [GCC<"format">]; let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">, IntArgument<"FirstArg">]; - let Subjects = SubjectList<[ObjCMethod, Block, HasFunctionProto], WarnDiag, - "ExpectedFunctionWithProtoType">; + let Subjects = SubjectList<[ObjCMethod, Block, HasFunctionProto]>; let Documentation = [FormatDocs]; } def FormatArg : InheritableAttr { let Spellings = [GCC<"format_arg">]; let Args = [IntArgument<"FormatIdx">]; - let Subjects = SubjectList<[ObjCMethod, HasFunctionProto], WarnDiag, - "ExpectedFunctionWithProtoType">; + let Subjects = SubjectList<[ObjCMethod, HasFunctionProto]>; let Documentation = [Undocumented]; } @@ -1088,9 +1100,8 @@ def Hot : InheritableAttr { } def IBAction : InheritableAttr { - let Spellings = [GNU<"ibaction">]; - let Subjects = SubjectList<[ObjCInstanceMethod], WarnDiag, - "ExpectedObjCInstanceMethod">; + let Spellings = [Clang<"ibaction">]; + let Subjects = SubjectList<[ObjCInstanceMethod]>; // An AST node is created for this attribute, but is not used by other parts // of the compiler. However, this node needs to exist in the AST because // external tools rely on it. @@ -1098,13 +1109,13 @@ def IBAction : InheritableAttr { } def IBOutlet : InheritableAttr { - let Spellings = [GNU<"iboutlet">]; + let Spellings = [Clang<"iboutlet">]; // let Subjects = [ObjCIvar, ObjCProperty]; let Documentation = [Undocumented]; } def IBOutletCollection : InheritableAttr { - let Spellings = [GNU<"iboutletcollection">]; + let Spellings = [Clang<"iboutletcollection">]; let Args = [TypeArgument<"Interface", 1>]; // let Subjects = [ObjCIvar, ObjCProperty]; let Documentation = [Undocumented]; @@ -1153,23 +1164,23 @@ def MSABI : InheritableAttr { def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> { // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's // and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Args = [UnsignedArgument<"Number">]; let ParseKind = "Interrupt"; let HasCustomParsing = 1; let Documentation = [Undocumented]; } -def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { +def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"mips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } -def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> { +def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> { // NOTE: If you add any additional spellings, ARMInterrupt's, // MSP430Interrupt's and AnyX86Interrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; let Args = [EnumArgument<"Interrupt", "InterruptType", ["vector=sw0", "vector=sw1", "vector=hw0", @@ -1182,16 +1193,27 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> { let Documentation = [MipsInterruptDocs]; } -def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> { +def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"micromips">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [MicroMipsDocs]; } +def MipsLongCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> { + let Spellings = [GCC<"long_call">, GCC<"far">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MipsLongCallStyleDocs]; +} + +def MipsShortCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> { + let Spellings = [GCC<"short_call">, GCC<"near">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MipsShortCallStyleDocs]; +} + def Mode : Attr { let Spellings = [GCC<"mode">]; - let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag, - "ExpectedVariableEnumFieldOrTypedef">; + let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag>; let Args = [IdentifierArgument<"Mode">]; let Documentation = [Undocumented]; } @@ -1203,13 +1225,13 @@ def Naked : InheritableAttr { } def NeonPolyVectorType : TypeAttr { - let Spellings = [GNU<"neon_polyvector_type">]; + let Spellings = [Clang<"neon_polyvector_type">]; let Args = [IntArgument<"NumElements">]; let Documentation = [Undocumented]; } def NeonVectorType : TypeAttr { - let Spellings = [GNU<"neon_vector_type">]; + let Spellings = [Clang<"neon_vector_type">]; let Args = [IntArgument<"NumElements">]; let Documentation = [Undocumented]; } @@ -1221,8 +1243,7 @@ def ReturnsTwice : InheritableAttr { } def DisableTailCalls : InheritableAttr { - let Spellings = [GNU<"disable_tail_calls">, - CXX11<"clang", "disable_tail_calls">]; + let Spellings = [Clang<"disable_tail_calls">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [DisableTailCallsDocs]; } @@ -1241,19 +1262,18 @@ def NoCommon : InheritableAttr { def NoDebug : InheritableAttr { let Spellings = [GCC<"nodebug">]; - let Subjects = SubjectList<[FunctionLike, ObjCMethod, NonParmVar], WarnDiag, - "ExpectedVariableOrFunction">; + let Subjects = SubjectList<[FunctionLike, ObjCMethod, NonParmVar]>; let Documentation = [NoDebugDocs]; } def NoDuplicate : InheritableAttr { - let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; + let Spellings = [Clang<"noduplicate">]; let Subjects = SubjectList<[Function]>; let Documentation = [NoDuplicateDocs]; } def Convergent : InheritableAttr { - let Spellings = [GNU<"convergent">, CXX11<"clang", "convergent">]; + let Spellings = [Clang<"convergent">]; let Subjects = SubjectList<[Function]>; let Documentation = [ConvergentDocs]; } @@ -1264,13 +1284,13 @@ def NoInline : InheritableAttr { let Documentation = [Undocumented]; } -def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { +def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"nomips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } -def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> { +def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> { let Spellings = [GCC<"nomicromips">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [MicroMipsDocs]; @@ -1294,31 +1314,31 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> { // this should be rejected on non-kernels. def AMDGPUFlatWorkGroupSize : InheritableAttr { - let Spellings = [GNU<"amdgpu_flat_work_group_size">]; + let Spellings = [Clang<"amdgpu_flat_work_group_size">]; let Args = [UnsignedArgument<"Min">, UnsignedArgument<"Max">]; let Documentation = [AMDGPUFlatWorkGroupSizeDocs]; - let Subjects = SubjectList<[Function], ErrorDiag, "ExpectedKernelFunction">; + let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } def AMDGPUWavesPerEU : InheritableAttr { - let Spellings = [GNU<"amdgpu_waves_per_eu">]; + let Spellings = [Clang<"amdgpu_waves_per_eu">]; let Args = [UnsignedArgument<"Min">, UnsignedArgument<"Max", 1>]; let Documentation = [AMDGPUWavesPerEUDocs]; - let Subjects = SubjectList<[Function], ErrorDiag, "ExpectedKernelFunction">; + let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } def AMDGPUNumSGPR : InheritableAttr { - let Spellings = [GNU<"amdgpu_num_sgpr">]; + let Spellings = [Clang<"amdgpu_num_sgpr">]; let Args = [UnsignedArgument<"NumSGPR">]; let Documentation = [AMDGPUNumSGPRNumVGPRDocs]; - let Subjects = SubjectList<[Function], ErrorDiag, "ExpectedKernelFunction">; + let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } def AMDGPUNumVGPR : InheritableAttr { - let Spellings = [GNU<"amdgpu_num_vgpr">]; + let Spellings = [Clang<"amdgpu_num_vgpr">]; let Args = [UnsignedArgument<"NumVGPR">]; let Documentation = [AMDGPUNumSGPRNumVGPRDocs]; - let Subjects = SubjectList<[Function], ErrorDiag, "ExpectedKernelFunction">; + let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } def NoSplitStack : InheritableAttr { @@ -1330,7 +1350,7 @@ def NoSplitStack : InheritableAttr { def NonNull : InheritableParamAttr { let Spellings = [GCC<"nonnull">]; let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag, - "ExpectedFunctionMethodOrParameter">; + "functions, methods, and parameters">; let Args = [VariadicUnsignedArgument<"Args">]; let AdditionalMembers = [{bool isNonNull(unsigned idx) const { @@ -1348,15 +1368,14 @@ def NonNull : InheritableParamAttr { def ReturnsNonNull : InheritableAttr { let Spellings = [GCC<"returns_nonnull">]; - let Subjects = SubjectList<[ObjCMethod, Function], WarnDiag, - "ExpectedFunctionOrMethod">; + let Subjects = SubjectList<[ObjCMethod, Function]>; let Documentation = [ReturnsNonNullDocs]; } // pass_object_size(N) indicates that the parameter should have // __builtin_object_size with Type=N evaluated on the parameter at the callsite. def PassObjectSize : InheritableParamAttr { - let Spellings = [GNU<"pass_object_size">]; + let Spellings = [Clang<"pass_object_size">]; let Args = [IntArgument<"Type">]; let Subjects = SubjectList<[ParmVar]>; let Documentation = [PassObjectSizeDocs]; @@ -1383,6 +1402,12 @@ def ObjCKindOf : TypeAttr { let Documentation = [Undocumented]; } +def NoEscape : Attr { + let Spellings = [Clang<"noescape">]; + let Subjects = SubjectList<[ParmVar]>; + let Documentation = [NoEscapeDocs]; +} + def AssumeAligned : InheritableAttr { let Spellings = [GCC<"assume_aligned">]; let Subjects = SubjectList<[ObjCMethod, Function]>; @@ -1392,8 +1417,7 @@ def AssumeAligned : InheritableAttr { def AllocAlign : InheritableAttr { let Spellings = [GCC<"alloc_align">]; - let Subjects = SubjectList<[HasFunctionProto], WarnDiag, - "ExpectedFunctionWithProtoType">; + let Subjects = SubjectList<[HasFunctionProto]>; let Args = [IntArgument<"ParamIndex">]; let Documentation = [AllocAlignDocs]; } @@ -1411,39 +1435,42 @@ def NoInstrumentFunction : InheritableAttr { } def NotTailCalled : InheritableAttr { - let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">]; + let Spellings = [Clang<"not_tail_called">]; let Subjects = SubjectList<[Function]>; let Documentation = [NotTailCalledDocs]; } def NoThrow : InheritableAttr { let Spellings = [GCC<"nothrow">, Declspec<"nothrow">]; - let Documentation = [Undocumented]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoThrowDocs]; } def NvWeak : IgnoredAttr { // No Declspec spelling of this attribute; the CUDA headers use - // __attribute__((nv_weak)) unconditionally. + // __attribute__((nv_weak)) unconditionally. Does not receive an [[]] + // spelling because it is a CUDA attribute. let Spellings = [GNU<"nv_weak">]; let LangOpts = [CUDA]; } def ObjCBridge : InheritableAttr { - let Spellings = [GNU<"objc_bridge">]; - let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, - "ExpectedStructOrUnionOrTypedef">; + let Spellings = [Clang<"objc_bridge">]; + let Subjects = SubjectList<[Record, TypedefName], ErrorDiag>; let Args = [IdentifierArgument<"BridgedType">]; let Documentation = [Undocumented]; } def ObjCBridgeMutable : InheritableAttr { - let Spellings = [GNU<"objc_bridge_mutable">]; + let Spellings = [Clang<"objc_bridge_mutable">]; let Subjects = SubjectList<[Record], ErrorDiag>; let Args = [IdentifierArgument<"BridgedType">]; let Documentation = [Undocumented]; } def ObjCBridgeRelated : InheritableAttr { + // TODO: this attribute does not have a [[]] spelling because it requires + // custom parsing support. let Spellings = [GNU<"objc_bridge_related">]; let Subjects = SubjectList<[Record], ErrorDiag>; let Args = [IdentifierArgument<"RelatedClass">, @@ -1454,43 +1481,43 @@ def ObjCBridgeRelated : InheritableAttr { } def NSReturnsRetained : InheritableAttr { - let Spellings = [GNU<"ns_returns_retained">]; + let Spellings = [Clang<"ns_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; } def NSReturnsNotRetained : InheritableAttr { - let Spellings = [GNU<"ns_returns_not_retained">]; + let Spellings = [Clang<"ns_returns_not_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; } def NSReturnsAutoreleased : InheritableAttr { - let Spellings = [GNU<"ns_returns_autoreleased">]; + let Spellings = [Clang<"ns_returns_autoreleased">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; let Documentation = [Undocumented]; } def NSConsumesSelf : InheritableAttr { - let Spellings = [GNU<"ns_consumes_self">]; + let Spellings = [Clang<"ns_consumes_self">]; let Subjects = SubjectList<[ObjCMethod]>; let Documentation = [Undocumented]; } def NSConsumed : InheritableParamAttr { - let Spellings = [GNU<"ns_consumed">]; + let Spellings = [Clang<"ns_consumed">]; let Subjects = SubjectList<[ParmVar]>; let Documentation = [Undocumented]; } def ObjCException : InheritableAttr { - let Spellings = [GNU<"objc_exception">]; + let Spellings = [Clang<"objc_exception">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCMethodFamily : InheritableAttr { - let Spellings = [GNU<"objc_method_family">]; + let Spellings = [Clang<"objc_method_family">]; let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; let Args = [EnumArgument<"Family", "FamilyKind", ["none", "alloc", "copy", "init", "mutableCopy", "new"], @@ -1500,85 +1527,84 @@ def ObjCMethodFamily : InheritableAttr { } def ObjCNSObject : InheritableAttr { - let Spellings = [GNU<"NSObject">]; + let Spellings = [Clang<"NSObject">]; let Documentation = [Undocumented]; } def ObjCIndependentClass : InheritableAttr { - let Spellings = [GNU<"objc_independent_class">]; + let Spellings = [Clang<"objc_independent_class">]; let Documentation = [Undocumented]; } def ObjCPreciseLifetime : InheritableAttr { - let Spellings = [GNU<"objc_precise_lifetime">]; + let Spellings = [Clang<"objc_precise_lifetime">]; let Subjects = SubjectList<[Var], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCReturnsInnerPointer : InheritableAttr { - let Spellings = [GNU<"objc_returns_inner_pointer">]; + let Spellings = [Clang<"objc_returns_inner_pointer">]; let Subjects = SubjectList<[ObjCMethod, ObjCProperty], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCRequiresSuper : InheritableAttr { - let Spellings = [GNU<"objc_requires_super">]; + let Spellings = [Clang<"objc_requires_super">]; let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; let Documentation = [ObjCRequiresSuperDocs]; } def ObjCRootClass : InheritableAttr { - let Spellings = [GNU<"objc_root_class">]; + let Spellings = [Clang<"objc_root_class">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCSubclassingRestricted : InheritableAttr { - let Spellings = [GNU<"objc_subclassing_restricted">]; + let Spellings = [Clang<"objc_subclassing_restricted">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [ObjCSubclassingRestrictedDocs]; } def ObjCExplicitProtocolImpl : InheritableAttr { - let Spellings = [GNU<"objc_protocol_requires_explicit_implementation">]; + let Spellings = [Clang<"objc_protocol_requires_explicit_implementation">]; let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCDesignatedInitializer : Attr { - let Spellings = [GNU<"objc_designated_initializer">]; - let Subjects = SubjectList<[ObjCInterfaceDeclInitMethod], ErrorDiag, - "ExpectedObjCInterfaceDeclInitMethod">; + let Spellings = [Clang<"objc_designated_initializer">]; + let Subjects = SubjectList<[ObjCInterfaceDeclInitMethod], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCRuntimeName : Attr { - let Spellings = [GNU<"objc_runtime_name">]; + let Spellings = [Clang<"objc_runtime_name">]; let Subjects = SubjectList<[ObjCInterface, ObjCProtocol], ErrorDiag>; let Args = [StringArgument<"MetadataName">]; let Documentation = [ObjCRuntimeNameDocs]; } def ObjCRuntimeVisible : Attr { - let Spellings = [GNU<"objc_runtime_visible">]; + let Spellings = [Clang<"objc_runtime_visible">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [ObjCRuntimeVisibleDocs]; } def ObjCBoxable : Attr { - let Spellings = [GNU<"objc_boxable">]; - let Subjects = SubjectList<[Record], ErrorDiag, "ExpectedStructOrUnion">; + let Spellings = [Clang<"objc_boxable">]; + let Subjects = SubjectList<[Record], ErrorDiag>; let Documentation = [ObjCBoxableDocs]; } def OptimizeNone : InheritableAttr { - let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; + let Spellings = [Clang<"optnone">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [OptnoneDocs]; } def Overloadable : Attr { - let Spellings = [GNU<"overloadable">]; + let Spellings = [Clang<"overloadable">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [OverloadableDocs]; } @@ -1590,11 +1616,11 @@ def Override : InheritableAttr { } def Ownership : InheritableAttr { - let Spellings = [GNU<"ownership_holds">, GNU<"ownership_returns">, - GNU<"ownership_takes">]; - let Accessors = [Accessor<"isHolds", [GNU<"ownership_holds">]>, - Accessor<"isReturns", [GNU<"ownership_returns">]>, - Accessor<"isTakes", [GNU<"ownership_takes">]>]; + let Spellings = [Clang<"ownership_holds">, Clang<"ownership_returns">, + Clang<"ownership_takes">]; + let Accessors = [Accessor<"isHolds", [Clang<"ownership_holds">]>, + Accessor<"isReturns", [Clang<"ownership_returns">]>, + Accessor<"isTakes", [Clang<"ownership_takes">]>]; let AdditionalMembers = [{ enum OwnershipKind { Holds, Returns, Takes }; OwnershipKind getOwnKind() const { @@ -1604,8 +1630,7 @@ def Ownership : InheritableAttr { } }]; let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">]; - let Subjects = SubjectList<[HasFunctionProto], WarnDiag, - "ExpectedFunctionWithProtoType">; + let Subjects = SubjectList<[HasFunctionProto]>; let Documentation = [Undocumented]; } @@ -1616,7 +1641,7 @@ def Packed : InheritableAttr { } def IntelOclBicc : InheritableAttr { - let Spellings = [GNU<"intel_ocl_bicc">]; + let Spellings = [Clang<"intel_ocl_bicc">]; // let Subjects = [Function, ObjCMethod]; let Documentation = [Undocumented]; } @@ -1642,6 +1667,7 @@ def Regparm : TypeAttr { } def ReqdWorkGroupSize : InheritableAttr { + // Does not have a [[]] spelling because it is an OpenCL-related attribute. let Spellings = [GNU<"reqd_work_group_size">]; let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, UnsignedArgument<"ZDim">]; @@ -1650,15 +1676,14 @@ def ReqdWorkGroupSize : InheritableAttr { } def RequireConstantInit : InheritableAttr { - let Spellings = [GNU<"require_constant_initialization">, - CXX11<"clang", "require_constant_initialization">]; - let Subjects = SubjectList<[GlobalVar], ErrorDiag, - "ExpectedStaticOrTLSVar">; + let Spellings = [Clang<"require_constant_initialization">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag>; let Documentation = [RequireConstantInitDocs]; let LangOpts = [CPlusPlus]; } def WorkGroupSizeHint : InheritableAttr { + // Does not have a [[]] spelling because it is an OpenCL-related attribute. let Spellings = [GNU<"work_group_size_hint">]; let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, @@ -1668,7 +1693,7 @@ def WorkGroupSizeHint : InheritableAttr { } def InitPriority : InheritableAttr { - let Spellings = [GNU<"init_priority">]; + let Spellings = [GCC<"init_priority">]; let Args = [UnsignedArgument<"Priority">]; let Subjects = SubjectList<[Var], ErrorDiag>; let Documentation = [Undocumented]; @@ -1677,9 +1702,8 @@ def InitPriority : InheritableAttr { def Section : InheritableAttr { let Spellings = [GCC<"section">, Declspec<"allocate">]; let Args = [StringArgument<"Name">]; - let Subjects = SubjectList<[Function, GlobalVar, - ObjCMethod, ObjCProperty], ErrorDiag, - "ExpectedFunctionGlobalVarMethodOrProperty">; + let Subjects = + SubjectList<[ Function, GlobalVar, ObjCMethod, ObjCProperty ], ErrorDiag>; let Documentation = [SectionDocs]; } @@ -1687,8 +1711,7 @@ def PragmaClangBSSSection : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; let Args = [StringArgument<"Name">]; - let Subjects = SubjectList<[GlobalVar], ErrorDiag, - "ExpectedFunctionMethodOrGlobalVar">; + let Subjects = SubjectList<[GlobalVar], ErrorDiag>; let Documentation = [Undocumented]; } @@ -1696,8 +1719,7 @@ def PragmaClangDataSection : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; let Args = [StringArgument<"Name">]; - let Subjects = SubjectList<[GlobalVar], ErrorDiag, - "ExpectedFunctionMethodOrGlobalVar">; + let Subjects = SubjectList<[GlobalVar], ErrorDiag>; let Documentation = [Undocumented]; } @@ -1705,8 +1727,7 @@ def PragmaClangRodataSection : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; let Args = [StringArgument<"Name">]; - let Subjects = SubjectList<[GlobalVar], ErrorDiag, - "ExpectedFunctionMethodOrGlobalVar">; + let Subjects = SubjectList<[GlobalVar], ErrorDiag>; let Documentation = [Undocumented]; } @@ -1714,8 +1735,7 @@ def PragmaClangTextSection : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; let Args = [StringArgument<"Name">]; - let Subjects = SubjectList<[Function], ErrorDiag, - "ExpectedFunctionMethodOrGlobalVar">; + let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [Undocumented]; } @@ -1734,23 +1754,23 @@ def StdCall : InheritableAttr { } def SwiftCall : InheritableAttr { - let Spellings = [GCC<"swiftcall">]; + let Spellings = [Clang<"swiftcall">]; // let Subjects = SubjectList<[Function]>; let Documentation = [SwiftCallDocs]; } def SwiftContext : ParameterABIAttr { - let Spellings = [GCC<"swift_context">]; + let Spellings = [Clang<"swift_context">]; let Documentation = [SwiftContextDocs]; } def SwiftErrorResult : ParameterABIAttr { - let Spellings = [GCC<"swift_error_result">]; + let Spellings = [Clang<"swift_error_result">]; let Documentation = [SwiftErrorResultDocs]; } def SwiftIndirectResult : ParameterABIAttr { - let Spellings = [GCC<"swift_indirect_result">]; + let Spellings = [Clang<"swift_indirect_result">]; let Documentation = [SwiftIndirectResultDocs]; } @@ -1774,25 +1794,25 @@ def ThisCall : InheritableAttr { } def VectorCall : InheritableAttr { - let Spellings = [GNU<"vectorcall">, Keyword<"__vectorcall">, + let Spellings = [Clang<"vectorcall">, Keyword<"__vectorcall">, Keyword<"_vectorcall">]; // let Subjects = [Function, ObjCMethod]; let Documentation = [VectorCallDocs]; } def Pascal : InheritableAttr { - let Spellings = [GNU<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">]; + let Spellings = [Clang<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">]; // let Subjects = [Function, ObjCMethod]; let Documentation = [Undocumented]; } def PreserveMost : InheritableAttr { - let Spellings = [GNU<"preserve_most">]; + let Spellings = [Clang<"preserve_most">]; let Documentation = [PreserveMostDocs]; } def PreserveAll : InheritableAttr { - let Spellings = [GNU<"preserve_all">]; + let Spellings = [Clang<"preserve_all">]; let Documentation = [PreserveAllDocs]; } @@ -1853,7 +1873,7 @@ def TransparentUnion : InheritableAttr { } def Unavailable : InheritableAttr { - let Spellings = [GNU<"unavailable">]; + let Spellings = [Clang<"unavailable">]; let Args = [StringArgument<"Message", 1>, EnumArgument<"ImplicitReason", "ImplicitReason", ["", "", "", ""], @@ -1867,6 +1887,9 @@ def Unavailable : InheritableAttr { } def DiagnoseIf : InheritableAttr { + // Does not have a [[]] spelling because this attribute requires the ability + // to parse function arguments but the attribute is not written in the type + // position. let Spellings = [GNU<"diagnose_if">]; let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>; let Args = [ExprArgument<"Cond">, StringArgument<"Message">, @@ -1887,35 +1910,35 @@ def DiagnoseIf : InheritableAttr { } def ArcWeakrefUnavailable : InheritableAttr { - let Spellings = [GNU<"objc_arc_weak_reference_unavailable">]; + let Spellings = [Clang<"objc_arc_weak_reference_unavailable">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [Undocumented]; } def ObjCGC : TypeAttr { - let Spellings = [GNU<"objc_gc">]; + let Spellings = [Clang<"objc_gc">]; let Args = [IdentifierArgument<"Kind">]; let Documentation = [Undocumented]; } def ObjCOwnership : InheritableAttr { - let Spellings = [GNU<"objc_ownership">]; + let Spellings = [Clang<"objc_ownership">]; let Args = [IdentifierArgument<"Kind">]; let ASTNode = 0; let Documentation = [Undocumented]; } def ObjCRequiresPropertyDefs : InheritableAttr { - let Spellings = [GNU<"objc_requires_property_definitions">]; + let Spellings = [Clang<"objc_requires_property_definitions">]; let Subjects = SubjectList<[ObjCInterface], ErrorDiag>; let Documentation = [Undocumented]; } def Unused : InheritableAttr { - let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">]; + let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, + C2x<"", "maybe_unused">]; let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label, - Field, ObjCMethod, FunctionLike], WarnDiag, - "ExpectedForMaybeUnused">; + Field, ObjCMethod, FunctionLike]>; let Documentation = [WarnMaybeUnusedDocs]; } @@ -1927,7 +1950,7 @@ def Used : InheritableAttr { def Uuid : InheritableAttr { let Spellings = [Declspec<"uuid">, Microsoft<"uuid">]; let Args = [StringArgument<"Guid">]; - let Subjects = SubjectList<[Record, Enum], WarnDiag, "ExpectedEnumOrClass">; + let Subjects = SubjectList<[Record, Enum]>; // FIXME: Allow expressing logical AND for LangOpts. Our condition should be: // CPlusPlus && (MicrosoftExt || Borland) let LangOpts = [MicrosoftExt, Borland]; @@ -1941,6 +1964,7 @@ def VectorSize : TypeAttr { } def VecTypeHint : InheritableAttr { + // Does not have a [[]] spelling because it is an OpenCL-related attribute. let Spellings = [GNU<"vec_type_hint">]; let Args = [TypeArgument<"TypeHint">]; let Subjects = SubjectList<[Function], ErrorDiag>; @@ -1959,7 +1983,7 @@ def Visibility : InheritableAttr { def TypeVisibility : InheritableAttr { let Clone = 0; - let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">]; + let Spellings = [Clang<"type_visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; @@ -1968,23 +1992,22 @@ def TypeVisibility : InheritableAttr { } def VecReturn : InheritableAttr { - let Spellings = [GNU<"vecreturn">]; + let Spellings = [Clang<"vecreturn">]; let Subjects = SubjectList<[CXXRecord], ErrorDiag>; let Documentation = [Undocumented]; } def WarnUnused : InheritableAttr { - let Spellings = [GNU<"warn_unused">]; + let Spellings = [GCC<"warn_unused">]; let Subjects = SubjectList<[Record]>; let Documentation = [Undocumented]; } def WarnUnusedResult : InheritableAttr { - let Spellings = [CXX11<"", "nodiscard", 201603>, + let Spellings = [CXX11<"", "nodiscard", 201603>, C2x<"", "nodiscard">, CXX11<"clang", "warn_unused_result">, GCC<"warn_unused_result">]; - let Subjects = SubjectList<[ObjCMethod, Enum, CXXRecord, FunctionLike], - WarnDiag, "ExpectedFunctionMethodEnumOrClass">; + let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike]>; let Documentation = [WarnUnusedResultsDocs]; } @@ -1995,7 +2018,7 @@ def Weak : InheritableAttr { } def WeakImport : InheritableAttr { - let Spellings = [GNU<"weak_import">]; + let Spellings = [Clang<"weak_import">]; let Documentation = [Undocumented]; } @@ -2008,7 +2031,7 @@ def WeakRef : InheritableAttr { } def LTOVisibilityPublic : InheritableAttr { - let Spellings = [CXX11<"clang", "lto_visibility_public">]; + let Spellings = [Clang<"lto_visibility_public">]; let Subjects = SubjectList<[Record]>; let Documentation = [LTOVisibilityDocs]; } @@ -2016,11 +2039,11 @@ def LTOVisibilityPublic : InheritableAttr { def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { // NOTE: If you add any additional spellings, ARMInterrupt's, // MSP430Interrupt's and MipsInterrupt's spellings must match. - let Spellings = [GNU<"interrupt">]; + let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[HasFunctionProto]>; let ParseKind = "Interrupt"; let HasCustomParsing = 1; - let Documentation = [AnyX86InterruptDocs]; + let Documentation = [Undocumented]; } def AnyX86NoCallerSavedRegisters : InheritableAttr, @@ -2029,19 +2052,18 @@ def AnyX86NoCallerSavedRegisters : InheritableAttr, let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } -def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> { - let Spellings = [GNU<"force_align_arg_pointer">]; +def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { + let Spellings = [GCC<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific // code silently allows anything function-like (such as typedefs or function // pointers), but does not apply the attribute to them. - let Documentation = [Undocumented]; + let Documentation = [X86ForceAlignArgPointerDocs]; } def NoSanitize : InheritableAttr { - let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">]; + let Spellings = [Clang<"no_sanitize">]; let Args = [VariadicStringArgument<"Sanitizers">]; - let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag, - "ExpectedFunctionMethodOrGlobalVar">; + let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag>; let Documentation = [NoSanitizeDocs]; let AdditionalMembers = [{ SanitizerMask getMask() const { @@ -2062,27 +2084,28 @@ def NoSanitizeSpecific : InheritableAttr { let Spellings = [GCC<"no_address_safety_analysis">, GCC<"no_sanitize_address">, GCC<"no_sanitize_thread">, - GNU<"no_sanitize_memory">]; - let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag, - "ExpectedFunctionOrGlobalVar">; + Clang<"no_sanitize_memory">]; + let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>; let Documentation = [NoSanitizeAddressDocs, NoSanitizeThreadDocs, NoSanitizeMemoryDocs]; let ASTNode = 0; } // C/C++ Thread safety attributes (e.g. for deadlock, data race checking) - +// Not all of these attributes will be given a [[]] spelling. The attributes +// which require access to function parameter names cannot use the [[]] spelling +// because they are not written in the type position. Some attributes are given +// an updated captability-based name and the older name will only be supported +// under the GNU-style spelling. def GuardedVar : InheritableAttr { - let Spellings = [GNU<"guarded_var">]; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Spellings = [Clang<"guarded_var">]; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } def PtGuardedVar : InheritableAttr { - let Spellings = [GNU<"pt_guarded_var">]; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Spellings = [Clang<"pt_guarded_var">]; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } @@ -2094,21 +2117,17 @@ def Lockable : InheritableAttr { } def ScopedLockable : InheritableAttr { - let Spellings = [GNU<"scoped_lockable">]; + let Spellings = [Clang<"scoped_lockable">]; let Subjects = SubjectList<[Record]>; let Documentation = [Undocumented]; } def Capability : InheritableAttr { - let Spellings = [GNU<"capability">, CXX11<"clang", "capability">, - GNU<"shared_capability">, - CXX11<"clang", "shared_capability">]; - let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, - "ExpectedStructOrUnionOrTypedef">; + let Spellings = [Clang<"capability">, Clang<"shared_capability">]; + let Subjects = SubjectList<[Record, TypedefName], ErrorDiag>; let Args = [StringArgument<"Name">]; let Accessors = [Accessor<"isShared", - [GNU<"shared_capability">, - CXX11<"clang","shared_capability">]>]; + [Clang<"shared_capability">]>]; let Documentation = [Undocumented]; let AdditionalMembers = [{ bool isMutex() const { return getName().equals_lower("mutex"); } @@ -2117,27 +2136,22 @@ def Capability : InheritableAttr { } def AssertCapability : InheritableAttr { - let Spellings = [GNU<"assert_capability">, - CXX11<"clang", "assert_capability">, - GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]; + let Spellings = [Clang<"assert_capability">, + Clang<"assert_shared_capability">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Args = [ExprArgument<"Expr">]; + let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]>]; + [Clang<"assert_shared_capability">]>]; let Documentation = [AssertCapabilityDocs]; } def AcquireCapability : InheritableAttr { - let Spellings = [GNU<"acquire_capability">, - CXX11<"clang", "acquire_capability">, - GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + let Spellings = [Clang<"acquire_capability">, + Clang<"acquire_shared_capability">, GNU<"exclusive_lock_function">, GNU<"shared_lock_function">]; let Subjects = SubjectList<[Function]>; @@ -2147,17 +2161,14 @@ def AcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + [Clang<"acquire_shared_capability">, GNU<"shared_lock_function">]>]; let Documentation = [AcquireCapabilityDocs]; } def TryAcquireCapability : InheritableAttr { - let Spellings = [GNU<"try_acquire_capability">, - CXX11<"clang", "try_acquire_capability">, - GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]; + let Spellings = [Clang<"try_acquire_capability">, + Clang<"try_acquire_shared_capability">]; let Subjects = SubjectList<[Function], ErrorDiag>; let LateParsed = 1; @@ -2166,19 +2177,15 @@ def TryAcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]>]; + [Clang<"try_acquire_shared_capability">]>]; let Documentation = [TryAcquireCapabilityDocs]; } def ReleaseCapability : InheritableAttr { - let Spellings = [GNU<"release_capability">, - CXX11<"clang", "release_capability">, - GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">, - GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, - GNU<"unlock_function">]; + let Spellings = [Clang<"release_capability">, + Clang<"release_shared_capability">, + Clang<"release_generic_capability">, + Clang<"unlock_function">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; let TemplateDependent = 1; @@ -2186,36 +2193,31 @@ def ReleaseCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">]>, + [Clang<"release_shared_capability">]>, Accessor<"isGeneric", - [GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, - GNU<"unlock_function">]>]; + [Clang<"release_generic_capability">, + Clang<"unlock_function">]>]; let Documentation = [ReleaseCapabilityDocs]; } def RequiresCapability : InheritableAttr { - let Spellings = [GNU<"requires_capability">, - CXX11<"clang", "requires_capability">, - GNU<"exclusive_locks_required">, - GNU<"requires_shared_capability">, - CXX11<"clang", "requires_shared_capability">, - GNU<"shared_locks_required">]; + let Spellings = [Clang<"requires_capability">, + Clang<"exclusive_locks_required">, + Clang<"requires_shared_capability">, + Clang<"shared_locks_required">]; let Args = [VariadicExprArgument<"Args">]; let LateParsed = 1; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; let Subjects = SubjectList<[Function]>; - let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">, - GNU<"shared_locks_required">, - CXX11<"clang","requires_shared_capability">]>]; + let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability">, + Clang<"shared_locks_required">]>]; let Documentation = [Undocumented]; } def NoThreadSafetyAnalysis : InheritableAttr { - let Spellings = [GNU<"no_thread_safety_analysis">]; + let Spellings = [Clang<"no_thread_safety_analysis">]; let Subjects = SubjectList<[Function]>; let Documentation = [Undocumented]; } @@ -2227,8 +2229,7 @@ def GuardedBy : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } @@ -2239,8 +2240,7 @@ def PtGuardedBy : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } @@ -2251,8 +2251,7 @@ def AcquiredAfter : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } @@ -2263,8 +2262,7 @@ def AcquiredBefore : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; - let Subjects = SubjectList<[Field, SharedVar], WarnDiag, - "ExpectedFieldOrGlobalVar">; + let Subjects = SubjectList<[Field, SharedVar]>; let Documentation = [Undocumented]; } @@ -2340,7 +2338,7 @@ def LocksExcluded : InheritableAttr { // C/C++ consumed attributes. def Consumable : InheritableAttr { - let Spellings = [GNU<"consumable">]; + let Spellings = [Clang<"consumable">]; let Subjects = SubjectList<[CXXRecord]>; let Args = [EnumArgument<"DefaultState", "ConsumedState", ["unknown", "consumed", "unconsumed"], @@ -2349,19 +2347,19 @@ def Consumable : InheritableAttr { } def ConsumableAutoCast : InheritableAttr { - let Spellings = [GNU<"consumable_auto_cast_state">]; + let Spellings = [Clang<"consumable_auto_cast_state">]; let Subjects = SubjectList<[CXXRecord]>; let Documentation = [Undocumented]; } def ConsumableSetOnRead : InheritableAttr { - let Spellings = [GNU<"consumable_set_state_on_read">]; + let Spellings = [Clang<"consumable_set_state_on_read">]; let Subjects = SubjectList<[CXXRecord]>; let Documentation = [Undocumented]; } def CallableWhen : InheritableAttr { - let Spellings = [GNU<"callable_when">]; + let Spellings = [Clang<"callable_when">]; let Subjects = SubjectList<[CXXMethod]>; let Args = [VariadicEnumArgument<"CallableStates", "ConsumedState", ["unknown", "consumed", "unconsumed"], @@ -2370,7 +2368,7 @@ def CallableWhen : InheritableAttr { } def ParamTypestate : InheritableAttr { - let Spellings = [GNU<"param_typestate">]; + let Spellings = [Clang<"param_typestate">]; let Subjects = SubjectList<[ParmVar]>; let Args = [EnumArgument<"ParamState", "ConsumedState", ["unknown", "consumed", "unconsumed"], @@ -2379,7 +2377,7 @@ def ParamTypestate : InheritableAttr { } def ReturnTypestate : InheritableAttr { - let Spellings = [GNU<"return_typestate">]; + let Spellings = [Clang<"return_typestate">]; let Subjects = SubjectList<[Function, ParmVar]>; let Args = [EnumArgument<"State", "ConsumedState", ["unknown", "consumed", "unconsumed"], @@ -2388,7 +2386,7 @@ def ReturnTypestate : InheritableAttr { } def SetTypestate : InheritableAttr { - let Spellings = [GNU<"set_typestate">]; + let Spellings = [Clang<"set_typestate">]; let Subjects = SubjectList<[CXXMethod]>; let Args = [EnumArgument<"NewState", "ConsumedState", ["unknown", "consumed", "unconsumed"], @@ -2397,7 +2395,7 @@ def SetTypestate : InheritableAttr { } def TestTypestate : InheritableAttr { - let Spellings = [GNU<"test_typestate">]; + let Spellings = [Clang<"test_typestate">]; let Subjects = SubjectList<[CXXMethod]>; let Args = [EnumArgument<"TestState", "ConsumedState", ["consumed", "unconsumed"], @@ -2673,6 +2671,14 @@ def OMPCaptureNoInit : InheritableAttr { let Documentation = [Undocumented]; } +def OMPCaptureKind : Attr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Args = [UnsignedArgument<"CaptureKind">]; + let Documentation = [Undocumented]; +} + def OMPDeclareSimdDecl : Attr { let Spellings = [Pragma<"omp", "declare simd">]; let Subjects = SubjectList<[Function]>; @@ -2759,7 +2765,7 @@ def OMPDeclareTargetDecl : Attr { } def InternalLinkage : InheritableAttr { - let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; + let Spellings = [Clang<"internal_linkage">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; let Documentation = [InternalLinkageDocs]; } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td index 567c7a3a53b06..ecff329c4ccba 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td @@ -7,6 +7,24 @@ // //===---------------------------------------------------------------------===// +// To test that the documentation builds cleanly, you must run clang-tblgen to +// convert the .td file into a .rst file, and then run sphinx to convert the +// .rst file into an HTML file. After completing testing, you should revert the +// generated .rst file so that the modified version does not get checked in to +// version control. +// +// To run clang-tblgen to generate the .rst file: +// clang-tblgen -gen-attr-docs -I <root>/llvm/tools/clang/include +// <root>/llvm/tools/clang/include/clang/Basic/Attr.td -o +// <root>/llvm/tools/clang/docs/AttributeReference.rst +// +// To run sphinx to generate the .html files (note that sphinx-build must be +// available on the PATH): +// Windows (from within the clang\docs directory): +// make.bat html +// Non-Windows (from within the clang\docs directory): +// make -f Makefile.sphinx html + def GlobalDocumentation { code Intro =[{.. ------------------------------------------------------------------- @@ -112,6 +130,50 @@ members, and static locals. }]; } +def NoEscapeDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +``noescape`` placed on a function parameter of a pointer type is used to inform +the compiler that the pointer cannot escape: that is, no reference to the object +the pointer points to that is derived from the parameter value will survive +after the function returns. Users are responsible for making sure parameters +annotated with ``noescape`` do not actuallly escape. + +For example: + +.. code-block:: c + + int *gp; + + void nonescapingFunc(__attribute__((noescape)) int *p) { + *p += 100; // OK. + } + + void escapingFunc(__attribute__((noescape)) int *p) { + gp = p; // Not OK. + } + +Additionally, when the parameter is a `block pointer +<https://clang.llvm.org/docs/BlockLanguageSpec.html>`, the same restriction +applies to copies of the block. For example: + +.. code-block:: c + + typedef void (^BlockTy)(); + BlockTy g0, g1; + + void nonescapingFunc(__attribute__((noescape)) BlockTy block) { + block(); // OK. + } + + void escapingFunc(__attribute__((noescape)) BlockTy block) { + g0 = block; // Not OK. + g1 = Block_copy(block); // Not OK either. + } + + }]; +} + def CarriesDependencyDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -1231,6 +1293,7 @@ Here is an example: def ARMInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (ARM)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on ARM targets. This attribute may be attached to a function definition and @@ -1272,6 +1335,7 @@ The semantics are as follows: def MipsInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (MIPS)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on MIPS targets. This attribute may be attached to a function definition and instructs @@ -1323,8 +1387,52 @@ on the command line. }]; } +def MipsLongCallStyleDocs : Documentation { + let Category = DocCatFunction; + let Heading = "long_call (gnu::long_call, gnu::far)"; + let Content = [{ +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +and ``__attribute__((near))`` attributes on MIPS targets. These attributes may +only be added to function declarations and change the code generated +by the compiler when directly calling the function. The ``near`` attribute +allows calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB +segment as the caller. The ``long_call`` and ``far`` attributes are synonyms +and require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + }]; +} + +def MipsShortCallStyleDocs : Documentation { + let Category = DocCatFunction; + let Heading = "short_call (gnu::short_call, gnu::near)"; + let Content = [{ +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +``__attribute__((short__call))``, and ``__attribute__((near))`` attributes +on MIPS targets. These attributes may only be added to function declarations +and change the code generated by the compiler when directly calling +the function. The ``short_call`` and ``near`` attributes are synonyms and +allow calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB segment +as the caller. The ``long_call`` and ``far`` attributes are synonyms and +require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + }]; +} + def AVRInterruptDocs : Documentation { let Category = DocCatFunction; + let Heading = "interrupt (AVR)"; let Content = [{ Clang supports the GNU style ``__attribute__((interrupt))`` attribute on AVR targets. This attribute may be attached to a function definition and instructs @@ -2625,6 +2733,18 @@ Marking virtual functions as ``not_tail_called`` is an error: }]; } +def NoThrowDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((nothrow))`` and Microsoft style +``__declspec(nothrow)`` attribute as an equivilent of `noexcept` on function +declarations. This attribute informs the compiler that the annotated function +does not throw an exception. This prevents exception-unwinding. This attribute +is particularly useful on functions in the C Standard Library that are +guaranteed to not throw an exception. + }]; +} + def InternalLinkageDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -2673,59 +2793,6 @@ Marking virtual functions as ``disable_tail_calls`` is legal. }]; } -def AnyX86InterruptDocs : Documentation { - let Category = DocCatFunction; - let Content = [{ -Clang supports the GNU style ``__attribute__((interrupt))`` attribute on -x86/x86-64 targets.The compiler generates function entry and exit sequences -suitable for use in an interrupt handler when this attribute is present. -The 'IRET' instruction, instead of the 'RET' instruction, is used to return -from interrupt or exception handlers. All registers, except for the EFLAGS -register which is restored by the 'IRET' instruction, are preserved by the -compiler. - -Any interruptible-without-stack-switch code must be compiled with --mno-red-zone since interrupt handlers can and will, because of the -hardware design, touch the red zone. - -1. interrupt handler must be declared with a mandatory pointer argument: - - .. code-block:: c - - struct interrupt_frame - { - uword_t ip; - uword_t cs; - uword_t flags; - uword_t sp; - uword_t ss; - }; - - __attribute__ ((interrupt)) - void f (struct interrupt_frame *frame) { - ... - } - -2. exception handler: - - The exception handler is very similar to the interrupt handler with - a different mandatory function signature: - - .. code-block:: c - - __attribute__ ((interrupt)) - void f (struct interrupt_frame *frame, uword_t error_code) { - ... - } - - and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction. - - The exception handler should only be used for exceptions which push an - error code and all other exceptions must use the interrupt handler. - The system will crash if the wrong handler is used. - }]; -} - def AnyX86NoCallerSavedRegistersDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -2760,6 +2827,31 @@ For example: }]; } +def X86ForceAlignArgPointerDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use this attribute to force stack alignment. + +Legacy x86 code uses 4-byte stack alignment. Newer aligned SSE instructions +(like 'movaps') that work with the stack require operands to be 16-byte aligned. +This attribute realigns the stack in the function prologue to make sure the +stack can be used with SSE instructions. + +Note that the x86_64 ABI forces 16-byte stack alignment at the call site. +Because of this, 'force_align_arg_pointer' is not needed on x86_64, except in +rare cases where the caller does not align the stack properly (e.g. flow +jumps from i386 arch code). + + .. code-block:: c + + __attribute__ ((force_align_arg_pointer)) + void f () { + ... + } + + }]; +} + def SwiftCallDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h b/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h index ea9e28ae681ae..c651abacd482b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Attributes.h @@ -26,6 +26,8 @@ enum class AttrSyntax { Microsoft, // Is the identifier known as a C++-style attribute? CXX, + // Is the identifier known as a C-style attribute? + C, // Is the identifier known as a pragma attribute? Pragma }; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def index 1ddb9beaf9133..3d4deb5ed3064 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def @@ -103,9 +103,9 @@ #endif // Standard libc/libm functions: -BUILTIN(__builtin_atan2 , "ddd" , "Fnc") -BUILTIN(__builtin_atan2f, "fff" , "Fnc") -BUILTIN(__builtin_atan2l, "LdLdLd", "Fnc") +BUILTIN(__builtin_atan2 , "ddd" , "Fne") +BUILTIN(__builtin_atan2f, "fff" , "Fne") +BUILTIN(__builtin_atan2l, "LdLdLd", "Fne") BUILTIN(__builtin_abs , "ii" , "ncF") BUILTIN(__builtin_copysign, "ddd", "ncF") BUILTIN(__builtin_copysignf, "fff", "ncF") @@ -113,9 +113,9 @@ BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") BUILTIN(__builtin_fabs , "dd" , "ncF") BUILTIN(__builtin_fabsf, "ff" , "ncF") BUILTIN(__builtin_fabsl, "LdLd", "ncF") -BUILTIN(__builtin_fmod , "ddd" , "Fnc") -BUILTIN(__builtin_fmodf, "fff" , "Fnc") -BUILTIN(__builtin_fmodl, "LdLdLd", "Fnc") +BUILTIN(__builtin_fmod , "ddd" , "Fne") +BUILTIN(__builtin_fmodf, "fff" , "Fne") +BUILTIN(__builtin_fmodl, "LdLdLd", "Fne") BUILTIN(__builtin_frexp , "ddi*" , "Fn") BUILTIN(__builtin_frexpf, "ffi*" , "Fn") BUILTIN(__builtin_frexpl, "LdLdi*", "Fn") @@ -127,9 +127,9 @@ BUILTIN(__builtin_inff , "f" , "nc") BUILTIN(__builtin_infl , "Ld" , "nc") BUILTIN(__builtin_labs , "LiLi" , "Fnc") BUILTIN(__builtin_llabs, "LLiLLi", "Fnc") -BUILTIN(__builtin_ldexp , "ddi" , "Fnc") -BUILTIN(__builtin_ldexpf, "ffi" , "Fnc") -BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc") +BUILTIN(__builtin_ldexp , "ddi" , "Fne") +BUILTIN(__builtin_ldexpf, "ffi" , "Fne") +BUILTIN(__builtin_ldexpl, "LdLdi", "Fne") BUILTIN(__builtin_modf , "ddd*" , "Fn") BUILTIN(__builtin_modff, "fff*" , "Fn") BUILTIN(__builtin_modfl, "LdLdLd*", "Fn") @@ -142,119 +142,119 @@ BUILTIN(__builtin_nansl, "LdcC*", "ncF") BUILTIN(__builtin_powi , "ddi" , "Fnc") BUILTIN(__builtin_powif, "ffi" , "Fnc") BUILTIN(__builtin_powil, "LdLdi", "Fnc") -BUILTIN(__builtin_pow , "ddd" , "Fnc") -BUILTIN(__builtin_powf, "fff" , "Fnc") -BUILTIN(__builtin_powl, "LdLdLd", "Fnc") +BUILTIN(__builtin_pow , "ddd" , "Fne") +BUILTIN(__builtin_powf, "fff" , "Fne") +BUILTIN(__builtin_powl, "LdLdLd", "Fne") // Standard unary libc/libm functions with double/float/long double variants: -BUILTIN(__builtin_acos , "dd" , "Fnc") -BUILTIN(__builtin_acosf, "ff" , "Fnc") -BUILTIN(__builtin_acosl, "LdLd", "Fnc") -BUILTIN(__builtin_acosh , "dd" , "Fnc") -BUILTIN(__builtin_acoshf, "ff" , "Fnc") -BUILTIN(__builtin_acoshl, "LdLd", "Fnc") -BUILTIN(__builtin_asin , "dd" , "Fnc") -BUILTIN(__builtin_asinf, "ff" , "Fnc") -BUILTIN(__builtin_asinl, "LdLd", "Fnc") -BUILTIN(__builtin_asinh , "dd" , "Fnc") -BUILTIN(__builtin_asinhf, "ff" , "Fnc") -BUILTIN(__builtin_asinhl, "LdLd", "Fnc") -BUILTIN(__builtin_atan , "dd" , "Fnc") -BUILTIN(__builtin_atanf, "ff" , "Fnc") -BUILTIN(__builtin_atanl, "LdLd", "Fnc") -BUILTIN(__builtin_atanh , "dd", "Fnc") -BUILTIN(__builtin_atanhf, "ff", "Fnc") -BUILTIN(__builtin_atanhl, "LdLd", "Fnc") +BUILTIN(__builtin_acos , "dd" , "Fne") +BUILTIN(__builtin_acosf, "ff" , "Fne") +BUILTIN(__builtin_acosl, "LdLd", "Fne") +BUILTIN(__builtin_acosh , "dd" , "Fne") +BUILTIN(__builtin_acoshf, "ff" , "Fne") +BUILTIN(__builtin_acoshl, "LdLd", "Fne") +BUILTIN(__builtin_asin , "dd" , "Fne") +BUILTIN(__builtin_asinf, "ff" , "Fne") +BUILTIN(__builtin_asinl, "LdLd", "Fne") +BUILTIN(__builtin_asinh , "dd" , "Fne") +BUILTIN(__builtin_asinhf, "ff" , "Fne") +BUILTIN(__builtin_asinhl, "LdLd", "Fne") +BUILTIN(__builtin_atan , "dd" , "Fne") +BUILTIN(__builtin_atanf, "ff" , "Fne") +BUILTIN(__builtin_atanl, "LdLd", "Fne") +BUILTIN(__builtin_atanh , "dd", "Fne") +BUILTIN(__builtin_atanhf, "ff", "Fne") +BUILTIN(__builtin_atanhl, "LdLd", "Fne") BUILTIN(__builtin_cbrt , "dd", "Fnc") BUILTIN(__builtin_cbrtf, "ff", "Fnc") BUILTIN(__builtin_cbrtl, "LdLd", "Fnc") BUILTIN(__builtin_ceil , "dd" , "Fnc") BUILTIN(__builtin_ceilf, "ff" , "Fnc") BUILTIN(__builtin_ceill, "LdLd", "Fnc") -BUILTIN(__builtin_cos , "dd" , "Fnc") -BUILTIN(__builtin_cosf, "ff" , "Fnc") -BUILTIN(__builtin_cosh , "dd" , "Fnc") -BUILTIN(__builtin_coshf, "ff" , "Fnc") -BUILTIN(__builtin_coshl, "LdLd", "Fnc") -BUILTIN(__builtin_cosl, "LdLd", "Fnc") -BUILTIN(__builtin_erf , "dd", "Fnc") -BUILTIN(__builtin_erff, "ff", "Fnc") -BUILTIN(__builtin_erfl, "LdLd", "Fnc") -BUILTIN(__builtin_erfc , "dd", "Fnc") -BUILTIN(__builtin_erfcf, "ff", "Fnc") -BUILTIN(__builtin_erfcl, "LdLd", "Fnc") -BUILTIN(__builtin_exp , "dd" , "Fnc") -BUILTIN(__builtin_expf, "ff" , "Fnc") -BUILTIN(__builtin_expl, "LdLd", "Fnc") -BUILTIN(__builtin_exp2 , "dd" , "Fnc") -BUILTIN(__builtin_exp2f, "ff" , "Fnc") -BUILTIN(__builtin_exp2l, "LdLd", "Fnc") -BUILTIN(__builtin_expm1 , "dd", "Fnc") -BUILTIN(__builtin_expm1f, "ff", "Fnc") -BUILTIN(__builtin_expm1l, "LdLd", "Fnc") -BUILTIN(__builtin_fdim, "ddd", "Fnc") -BUILTIN(__builtin_fdimf, "fff", "Fnc") -BUILTIN(__builtin_fdiml, "LdLdLd", "Fnc") +BUILTIN(__builtin_cos , "dd" , "Fne") +BUILTIN(__builtin_cosf, "ff" , "Fne") +BUILTIN(__builtin_cosh , "dd" , "Fne") +BUILTIN(__builtin_coshf, "ff" , "Fne") +BUILTIN(__builtin_coshl, "LdLd", "Fne") +BUILTIN(__builtin_cosl, "LdLd", "Fne") +BUILTIN(__builtin_erf , "dd", "Fne") +BUILTIN(__builtin_erff, "ff", "Fne") +BUILTIN(__builtin_erfl, "LdLd", "Fne") +BUILTIN(__builtin_erfc , "dd", "Fne") +BUILTIN(__builtin_erfcf, "ff", "Fne") +BUILTIN(__builtin_erfcl, "LdLd", "Fne") +BUILTIN(__builtin_exp , "dd" , "Fne") +BUILTIN(__builtin_expf, "ff" , "Fne") +BUILTIN(__builtin_expl, "LdLd", "Fne") +BUILTIN(__builtin_exp2 , "dd" , "Fne") +BUILTIN(__builtin_exp2f, "ff" , "Fne") +BUILTIN(__builtin_exp2l, "LdLd", "Fne") +BUILTIN(__builtin_expm1 , "dd", "Fne") +BUILTIN(__builtin_expm1f, "ff", "Fne") +BUILTIN(__builtin_expm1l, "LdLd", "Fne") +BUILTIN(__builtin_fdim, "ddd", "Fne") +BUILTIN(__builtin_fdimf, "fff", "Fne") +BUILTIN(__builtin_fdiml, "LdLdLd", "Fne") BUILTIN(__builtin_floor , "dd" , "Fnc") BUILTIN(__builtin_floorf, "ff" , "Fnc") BUILTIN(__builtin_floorl, "LdLd", "Fnc") -BUILTIN(__builtin_fma, "dddd", "Fnc") -BUILTIN(__builtin_fmaf, "ffff", "Fnc") -BUILTIN(__builtin_fmal, "LdLdLdLd", "Fnc") +BUILTIN(__builtin_fma, "dddd", "Fne") +BUILTIN(__builtin_fmaf, "ffff", "Fne") +BUILTIN(__builtin_fmal, "LdLdLdLd", "Fne") BUILTIN(__builtin_fmax, "ddd", "Fnc") BUILTIN(__builtin_fmaxf, "fff", "Fnc") BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc") BUILTIN(__builtin_fmin, "ddd", "Fnc") BUILTIN(__builtin_fminf, "fff", "Fnc") BUILTIN(__builtin_fminl, "LdLdLd", "Fnc") -BUILTIN(__builtin_hypot , "ddd" , "Fnc") -BUILTIN(__builtin_hypotf, "fff" , "Fnc") -BUILTIN(__builtin_hypotl, "LdLdLd", "Fnc") -BUILTIN(__builtin_ilogb , "id", "Fnc") -BUILTIN(__builtin_ilogbf, "if", "Fnc") -BUILTIN(__builtin_ilogbl, "iLd", "Fnc") -BUILTIN(__builtin_lgamma , "dd", "Fnc") -BUILTIN(__builtin_lgammaf, "ff", "Fnc") -BUILTIN(__builtin_lgammal, "LdLd", "Fnc") -BUILTIN(__builtin_llrint, "LLid", "Fnc") -BUILTIN(__builtin_llrintf, "LLif", "Fnc") -BUILTIN(__builtin_llrintl, "LLiLd", "Fnc") -BUILTIN(__builtin_llround , "LLid", "Fnc") -BUILTIN(__builtin_llroundf, "LLif", "Fnc") -BUILTIN(__builtin_llroundl, "LLiLd", "Fnc") -BUILTIN(__builtin_log , "dd" , "Fnc") -BUILTIN(__builtin_log10 , "dd" , "Fnc") -BUILTIN(__builtin_log10f, "ff" , "Fnc") -BUILTIN(__builtin_log10l, "LdLd", "Fnc") -BUILTIN(__builtin_log1p , "dd" , "Fnc") -BUILTIN(__builtin_log1pf, "ff" , "Fnc") -BUILTIN(__builtin_log1pl, "LdLd", "Fnc") -BUILTIN(__builtin_log2, "dd" , "Fnc") -BUILTIN(__builtin_log2f, "ff" , "Fnc") -BUILTIN(__builtin_log2l, "LdLd" , "Fnc") -BUILTIN(__builtin_logb , "dd", "Fnc") -BUILTIN(__builtin_logbf, "ff", "Fnc") -BUILTIN(__builtin_logbl, "LdLd", "Fnc") -BUILTIN(__builtin_logf, "ff" , "Fnc") -BUILTIN(__builtin_logl, "LdLd", "Fnc") -BUILTIN(__builtin_lrint , "Lid", "Fnc") -BUILTIN(__builtin_lrintf, "Lif", "Fnc") -BUILTIN(__builtin_lrintl, "LiLd", "Fnc") -BUILTIN(__builtin_lround , "Lid", "Fnc") -BUILTIN(__builtin_lroundf, "Lif", "Fnc") -BUILTIN(__builtin_lroundl, "LiLd", "Fnc") +BUILTIN(__builtin_hypot , "ddd" , "Fne") +BUILTIN(__builtin_hypotf, "fff" , "Fne") +BUILTIN(__builtin_hypotl, "LdLdLd", "Fne") +BUILTIN(__builtin_ilogb , "id", "Fne") +BUILTIN(__builtin_ilogbf, "if", "Fne") +BUILTIN(__builtin_ilogbl, "iLd", "Fne") +BUILTIN(__builtin_lgamma , "dd", "Fn") +BUILTIN(__builtin_lgammaf, "ff", "Fn") +BUILTIN(__builtin_lgammal, "LdLd", "Fn") +BUILTIN(__builtin_llrint, "LLid", "Fne") +BUILTIN(__builtin_llrintf, "LLif", "Fne") +BUILTIN(__builtin_llrintl, "LLiLd", "Fne") +BUILTIN(__builtin_llround , "LLid", "Fne") +BUILTIN(__builtin_llroundf, "LLif", "Fne") +BUILTIN(__builtin_llroundl, "LLiLd", "Fne") +BUILTIN(__builtin_log , "dd" , "Fne") +BUILTIN(__builtin_log10 , "dd" , "Fne") +BUILTIN(__builtin_log10f, "ff" , "Fne") +BUILTIN(__builtin_log10l, "LdLd", "Fne") +BUILTIN(__builtin_log1p , "dd" , "Fne") +BUILTIN(__builtin_log1pf, "ff" , "Fne") +BUILTIN(__builtin_log1pl, "LdLd", "Fne") +BUILTIN(__builtin_log2, "dd" , "Fne") +BUILTIN(__builtin_log2f, "ff" , "Fne") +BUILTIN(__builtin_log2l, "LdLd" , "Fne") +BUILTIN(__builtin_logb , "dd", "Fne") +BUILTIN(__builtin_logbf, "ff", "Fne") +BUILTIN(__builtin_logbl, "LdLd", "Fne") +BUILTIN(__builtin_logf, "ff" , "Fne") +BUILTIN(__builtin_logl, "LdLd", "Fne") +BUILTIN(__builtin_lrint , "Lid", "Fne") +BUILTIN(__builtin_lrintf, "Lif", "Fne") +BUILTIN(__builtin_lrintl, "LiLd", "Fne") +BUILTIN(__builtin_lround , "Lid", "Fne") +BUILTIN(__builtin_lroundf, "Lif", "Fne") +BUILTIN(__builtin_lroundl, "LiLd", "Fne") BUILTIN(__builtin_nearbyint , "dd", "Fnc") BUILTIN(__builtin_nearbyintf, "ff", "Fnc") BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc") -BUILTIN(__builtin_nextafter , "ddd", "Fnc") -BUILTIN(__builtin_nextafterf, "fff", "Fnc") -BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc") -BUILTIN(__builtin_nexttoward , "ddLd", "Fnc") -BUILTIN(__builtin_nexttowardf, "ffLd", "Fnc") -BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc") -BUILTIN(__builtin_remainder , "ddd", "Fnc") -BUILTIN(__builtin_remainderf, "fff", "Fnc") -BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc") +BUILTIN(__builtin_nextafter , "ddd", "Fne") +BUILTIN(__builtin_nextafterf, "fff", "Fne") +BUILTIN(__builtin_nextafterl, "LdLdLd", "Fne") +BUILTIN(__builtin_nexttoward , "ddLd", "Fne") +BUILTIN(__builtin_nexttowardf, "ffLd", "Fne") +BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fne") +BUILTIN(__builtin_remainder , "ddd", "Fne") +BUILTIN(__builtin_remainderf, "fff", "Fne") +BUILTIN(__builtin_remainderl, "LdLdLd", "Fne") BUILTIN(__builtin_remquo , "dddi*", "Fn") BUILTIN(__builtin_remquof, "fffi*", "Fn") BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn") @@ -264,101 +264,101 @@ BUILTIN(__builtin_rintl, "LdLd", "Fnc") BUILTIN(__builtin_round, "dd" , "Fnc") BUILTIN(__builtin_roundf, "ff" , "Fnc") BUILTIN(__builtin_roundl, "LdLd" , "Fnc") -BUILTIN(__builtin_scalbln , "ddLi", "Fnc") -BUILTIN(__builtin_scalblnf, "ffLi", "Fnc") -BUILTIN(__builtin_scalblnl, "LdLdLi", "Fnc") -BUILTIN(__builtin_scalbn , "ddi", "Fnc") -BUILTIN(__builtin_scalbnf, "ffi", "Fnc") -BUILTIN(__builtin_scalbnl, "LdLdi", "Fnc") -BUILTIN(__builtin_sin , "dd" , "Fnc") -BUILTIN(__builtin_sinf, "ff" , "Fnc") -BUILTIN(__builtin_sinh , "dd" , "Fnc") -BUILTIN(__builtin_sinhf, "ff" , "Fnc") -BUILTIN(__builtin_sinhl, "LdLd", "Fnc") -BUILTIN(__builtin_sinl, "LdLd", "Fnc") -BUILTIN(__builtin_sqrt , "dd" , "Fnc") -BUILTIN(__builtin_sqrtf, "ff" , "Fnc") -BUILTIN(__builtin_sqrtl, "LdLd", "Fnc") -BUILTIN(__builtin_tan , "dd" , "Fnc") -BUILTIN(__builtin_tanf, "ff" , "Fnc") -BUILTIN(__builtin_tanh , "dd" , "Fnc") -BUILTIN(__builtin_tanhf, "ff" , "Fnc") -BUILTIN(__builtin_tanhl, "LdLd", "Fnc") -BUILTIN(__builtin_tanl, "LdLd", "Fnc") -BUILTIN(__builtin_tgamma , "dd", "Fnc") -BUILTIN(__builtin_tgammaf, "ff", "Fnc") -BUILTIN(__builtin_tgammal, "LdLd", "Fnc") +BUILTIN(__builtin_scalbln , "ddLi", "Fne") +BUILTIN(__builtin_scalblnf, "ffLi", "Fne") +BUILTIN(__builtin_scalblnl, "LdLdLi", "Fne") +BUILTIN(__builtin_scalbn , "ddi", "Fne") +BUILTIN(__builtin_scalbnf, "ffi", "Fne") +BUILTIN(__builtin_scalbnl, "LdLdi", "Fne") +BUILTIN(__builtin_sin , "dd" , "Fne") +BUILTIN(__builtin_sinf, "ff" , "Fne") +BUILTIN(__builtin_sinh , "dd" , "Fne") +BUILTIN(__builtin_sinhf, "ff" , "Fne") +BUILTIN(__builtin_sinhl, "LdLd", "Fne") +BUILTIN(__builtin_sinl, "LdLd", "Fne") +BUILTIN(__builtin_sqrt , "dd" , "Fne") +BUILTIN(__builtin_sqrtf, "ff" , "Fne") +BUILTIN(__builtin_sqrtl, "LdLd", "Fne") +BUILTIN(__builtin_tan , "dd" , "Fne") +BUILTIN(__builtin_tanf, "ff" , "Fne") +BUILTIN(__builtin_tanh , "dd" , "Fne") +BUILTIN(__builtin_tanhf, "ff" , "Fne") +BUILTIN(__builtin_tanhl, "LdLd", "Fne") +BUILTIN(__builtin_tanl, "LdLd", "Fne") +BUILTIN(__builtin_tgamma , "dd", "Fne") +BUILTIN(__builtin_tgammaf, "ff", "Fne") +BUILTIN(__builtin_tgammal, "LdLd", "Fne") BUILTIN(__builtin_trunc , "dd", "Fnc") BUILTIN(__builtin_truncf, "ff", "Fnc") BUILTIN(__builtin_truncl, "LdLd", "Fnc") // C99 complex builtins -BUILTIN(__builtin_cabs, "dXd", "Fnc") -BUILTIN(__builtin_cabsf, "fXf", "Fnc") -BUILTIN(__builtin_cabsl, "LdXLd", "Fnc") -BUILTIN(__builtin_cacos, "XdXd", "Fnc") -BUILTIN(__builtin_cacosf, "XfXf", "Fnc") -BUILTIN(__builtin_cacosh, "XdXd", "Fnc") -BUILTIN(__builtin_cacoshf, "XfXf", "Fnc") -BUILTIN(__builtin_cacoshl, "XLdXLd", "Fnc") -BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc") -BUILTIN(__builtin_carg, "dXd", "Fnc") -BUILTIN(__builtin_cargf, "fXf", "Fnc") -BUILTIN(__builtin_cargl, "LdXLd", "Fnc") -BUILTIN(__builtin_casin, "XdXd", "Fnc") -BUILTIN(__builtin_casinf, "XfXf", "Fnc") -BUILTIN(__builtin_casinh, "XdXd", "Fnc") -BUILTIN(__builtin_casinhf, "XfXf", "Fnc") -BUILTIN(__builtin_casinhl, "XLdXLd", "Fnc") -BUILTIN(__builtin_casinl, "XLdXLd", "Fnc") -BUILTIN(__builtin_catan, "XdXd", "Fnc") -BUILTIN(__builtin_catanf, "XfXf", "Fnc") -BUILTIN(__builtin_catanh, "XdXd", "Fnc") -BUILTIN(__builtin_catanhf, "XfXf", "Fnc") -BUILTIN(__builtin_catanhl, "XLdXLd", "Fnc") -BUILTIN(__builtin_catanl, "XLdXLd", "Fnc") -BUILTIN(__builtin_ccos, "XdXd", "Fnc") -BUILTIN(__builtin_ccosf, "XfXf", "Fnc") -BUILTIN(__builtin_ccosl, "XLdXLd", "Fnc") -BUILTIN(__builtin_ccosh, "XdXd", "Fnc") -BUILTIN(__builtin_ccoshf, "XfXf", "Fnc") -BUILTIN(__builtin_ccoshl, "XLdXLd", "Fnc") -BUILTIN(__builtin_cexp, "XdXd", "Fnc") -BUILTIN(__builtin_cexpf, "XfXf", "Fnc") -BUILTIN(__builtin_cexpl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cabs, "dXd", "Fne") +BUILTIN(__builtin_cabsf, "fXf", "Fne") +BUILTIN(__builtin_cabsl, "LdXLd", "Fne") +BUILTIN(__builtin_cacos, "XdXd", "Fne") +BUILTIN(__builtin_cacosf, "XfXf", "Fne") +BUILTIN(__builtin_cacosh, "XdXd", "Fne") +BUILTIN(__builtin_cacoshf, "XfXf", "Fne") +BUILTIN(__builtin_cacoshl, "XLdXLd", "Fne") +BUILTIN(__builtin_cacosl, "XLdXLd", "Fne") +BUILTIN(__builtin_carg, "dXd", "Fne") +BUILTIN(__builtin_cargf, "fXf", "Fne") +BUILTIN(__builtin_cargl, "LdXLd", "Fne") +BUILTIN(__builtin_casin, "XdXd", "Fne") +BUILTIN(__builtin_casinf, "XfXf", "Fne") +BUILTIN(__builtin_casinh, "XdXd", "Fne") +BUILTIN(__builtin_casinhf, "XfXf", "Fne") +BUILTIN(__builtin_casinhl, "XLdXLd", "Fne") +BUILTIN(__builtin_casinl, "XLdXLd", "Fne") +BUILTIN(__builtin_catan, "XdXd", "Fne") +BUILTIN(__builtin_catanf, "XfXf", "Fne") +BUILTIN(__builtin_catanh, "XdXd", "Fne") +BUILTIN(__builtin_catanhf, "XfXf", "Fne") +BUILTIN(__builtin_catanhl, "XLdXLd", "Fne") +BUILTIN(__builtin_catanl, "XLdXLd", "Fne") +BUILTIN(__builtin_ccos, "XdXd", "Fne") +BUILTIN(__builtin_ccosf, "XfXf", "Fne") +BUILTIN(__builtin_ccosl, "XLdXLd", "Fne") +BUILTIN(__builtin_ccosh, "XdXd", "Fne") +BUILTIN(__builtin_ccoshf, "XfXf", "Fne") +BUILTIN(__builtin_ccoshl, "XLdXLd", "Fne") +BUILTIN(__builtin_cexp, "XdXd", "Fne") +BUILTIN(__builtin_cexpf, "XfXf", "Fne") +BUILTIN(__builtin_cexpl, "XLdXLd", "Fne") BUILTIN(__builtin_cimag, "dXd", "Fnc") BUILTIN(__builtin_cimagf, "fXf", "Fnc") BUILTIN(__builtin_cimagl, "LdXLd", "Fnc") BUILTIN(__builtin_conj, "XdXd", "Fnc") BUILTIN(__builtin_conjf, "XfXf", "Fnc") BUILTIN(__builtin_conjl, "XLdXLd", "Fnc") -BUILTIN(__builtin_clog, "XdXd", "Fnc") -BUILTIN(__builtin_clogf, "XfXf", "Fnc") -BUILTIN(__builtin_clogl, "XLdXLd", "Fnc") +BUILTIN(__builtin_clog, "XdXd", "Fne") +BUILTIN(__builtin_clogf, "XfXf", "Fne") +BUILTIN(__builtin_clogl, "XLdXLd", "Fne") BUILTIN(__builtin_cproj, "XdXd", "Fnc") BUILTIN(__builtin_cprojf, "XfXf", "Fnc") BUILTIN(__builtin_cprojl, "XLdXLd", "Fnc") -BUILTIN(__builtin_cpow, "XdXdXd", "Fnc") -BUILTIN(__builtin_cpowf, "XfXfXf", "Fnc") -BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fnc") +BUILTIN(__builtin_cpow, "XdXdXd", "Fne") +BUILTIN(__builtin_cpowf, "XfXfXf", "Fne") +BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fne") BUILTIN(__builtin_creal, "dXd", "Fnc") BUILTIN(__builtin_crealf, "fXf", "Fnc") BUILTIN(__builtin_creall, "LdXLd", "Fnc") -BUILTIN(__builtin_csin, "XdXd", "Fnc") -BUILTIN(__builtin_csinf, "XfXf", "Fnc") -BUILTIN(__builtin_csinl, "XLdXLd", "Fnc") -BUILTIN(__builtin_csinh, "XdXd", "Fnc") -BUILTIN(__builtin_csinhf, "XfXf", "Fnc") -BUILTIN(__builtin_csinhl, "XLdXLd", "Fnc") -BUILTIN(__builtin_csqrt, "XdXd", "Fnc") -BUILTIN(__builtin_csqrtf, "XfXf", "Fnc") -BUILTIN(__builtin_csqrtl, "XLdXLd", "Fnc") -BUILTIN(__builtin_ctan, "XdXd", "Fnc") -BUILTIN(__builtin_ctanf, "XfXf", "Fnc") -BUILTIN(__builtin_ctanl, "XLdXLd", "Fnc") -BUILTIN(__builtin_ctanh, "XdXd", "Fnc") -BUILTIN(__builtin_ctanhf, "XfXf", "Fnc") -BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csin, "XdXd", "Fne") +BUILTIN(__builtin_csinf, "XfXf", "Fne") +BUILTIN(__builtin_csinl, "XLdXLd", "Fne") +BUILTIN(__builtin_csinh, "XdXd", "Fne") +BUILTIN(__builtin_csinhf, "XfXf", "Fne") +BUILTIN(__builtin_csinhl, "XLdXLd", "Fne") +BUILTIN(__builtin_csqrt, "XdXd", "Fne") +BUILTIN(__builtin_csqrtf, "XfXf", "Fne") +BUILTIN(__builtin_csqrtl, "XLdXLd", "Fne") +BUILTIN(__builtin_ctan, "XdXd", "Fne") +BUILTIN(__builtin_ctanf, "XfXf", "Fne") +BUILTIN(__builtin_ctanl, "XLdXLd", "Fne") +BUILTIN(__builtin_ctanh, "XdXd", "Fne") +BUILTIN(__builtin_ctanhf, "XfXf", "Fne") +BUILTIN(__builtin_ctanhl, "XLdXLd", "Fne") // FP Comparisons. BUILTIN(__builtin_isgreater , "i.", "Fnc") @@ -700,6 +700,21 @@ BUILTIN(__atomic_signal_fence, "vi", "n") BUILTIN(__atomic_always_lock_free, "izvCD*", "n") BUILTIN(__atomic_is_lock_free, "izvCD*", "n") +// OpenCL 2.0 atomic builtins. +ATOMIC_BUILTIN(__opencl_atomic_init, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_load, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_store, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_strong, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_weak, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t") +ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t") + #undef ATOMIC_BUILTIN // Non-overloaded atomic builtins. @@ -717,6 +732,7 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn") // Microsoft builtins. These are only active with -fms-extensions. LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES) LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) @@ -992,9 +1008,9 @@ LIBBUILTIN(modf, "ddd*", "fn", "math.h", ALL_LANGUAGES) LIBBUILTIN(modff, "fff*", "fn", "math.h", ALL_LANGUAGES) LIBBUILTIN(modfl, "LdLdLd*", "fn", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nan, "dcC*", "fnc", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nanf, "fcC*", "fnc", "math.h", ALL_LANGUAGES) -LIBBUILTIN(nanl, "LdcC*", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nan, "dcC*", "fUn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanf, "fcC*", "fUn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(nanl, "LdcC*", "fUn", "math.h", ALL_LANGUAGES) LIBBUILTIN(pow, "ddd", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(powf, "fff", "fne", "math.h", ALL_LANGUAGES) @@ -1024,9 +1040,9 @@ LIBBUILTIN(atanh, "dd", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(atanhf, "ff", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(atanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES) -LIBBUILTIN(cbrt, "dd", "fne", "math.h", ALL_LANGUAGES) -LIBBUILTIN(cbrtf, "ff", "fne", "math.h", ALL_LANGUAGES) -LIBBUILTIN(cbrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cbrt, "dd", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cbrtf, "ff", "fnc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cbrtl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(ceil, "dd", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(ceilf, "ff", "fnc", "math.h", ALL_LANGUAGES) @@ -1146,6 +1162,10 @@ LIBBUILTIN(remainder, "ddd", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(remainderf, "fff", "fne", "math.h", ALL_LANGUAGES) LIBBUILTIN(remainderl, "LdLdLd", "fne", "math.h", ALL_LANGUAGES) +LIBBUILTIN(remquo, "dddi*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(remquof, "fffi*", "fn", "math.h", ALL_LANGUAGES) +LIBBUILTIN(remquol, "LdLdLdi*", "fn", "math.h", ALL_LANGUAGES) + LIBBUILTIN(rint, "dd", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(rintf, "ff", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(rintl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) @@ -1190,49 +1210,49 @@ LIBBUILTIN(trunc, "dd", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(truncf, "ff", "fnc", "math.h", ALL_LANGUAGES) LIBBUILTIN(truncl, "LdLd", "fnc", "math.h", ALL_LANGUAGES) -LIBBUILTIN(cabs, "dXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cabsf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cabsl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cabs, "dXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cabsf, "fXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cabsl, "LdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacos, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacosf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacosl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cacoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacosh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacoshf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cacoshl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(carg, "dXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cargf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cargl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(carg, "dXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cargf, "fXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cargl, "LdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casin, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(casinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinhf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(casinhl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catan, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(catanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanhf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(catanhl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccos, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccosf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccosl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccos, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccosf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccosl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccosh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccoshf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ccoshl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccosh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccoshf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ccoshl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cexp, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cexpf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cexpl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cexp, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cexpf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cexpl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) LIBBUILTIN(cimag, "dXd", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(cimagf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) @@ -1242,41 +1262,41 @@ LIBBUILTIN(conj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(conjf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(conjl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(clog, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(clogf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(clogl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(clog, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(clogf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(clogl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) LIBBUILTIN(cproj, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(cprojf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(cprojl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cpow, "XdXdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cpowf, "XfXfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(cpowl, "XLdXLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cpow, "XdXdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cpowf, "XfXfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(cpowl, "XLdXLdXLd", "fne", "complex.h", ALL_LANGUAGES) LIBBUILTIN(creal, "dXd", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(crealf, "fXf", "fnc", "complex.h", ALL_LANGUAGES) LIBBUILTIN(creall, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csin, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csinf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csinl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csin, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csinh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csinhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csinhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinhf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csinhl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csqrt, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csqrtf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(csqrtl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csqrt, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csqrtf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(csqrtl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctan, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctanf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctanl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctan, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctanh, "XdXd", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctanhf, "XfXf", "fnc", "complex.h", ALL_LANGUAGES) -LIBBUILTIN(ctanhl, "XLdXLd", "fnc", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanh, "XdXd", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanhf, "XfXf", "fne", "complex.h", ALL_LANGUAGES) +LIBBUILTIN(ctanhl, "XLdXLd", "fne", "complex.h", ALL_LANGUAGES) // __sinpi and friends are OS X specific library functions, but otherwise much // like the standard (non-complex) sin (etc). @@ -1398,18 +1418,29 @@ LANGBUILTIN(get_pipe_max_packets, "Ui.", "tn", OCLC20_LANG) // OpenCL v2.0 s6.13.17 - Enqueue kernel functions. // Custom builtin check allows to perform special check of passed block arguments. LANGBUILTIN(enqueue_kernel, "i.", "tn", OCLC20_LANG) -LANGBUILTIN(get_kernel_work_group_size, "i.", "tn", OCLC20_LANG) -LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "i.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_work_group_size, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_max_sub_group_size_for_ndrange, "Ui.", "tn", OCLC20_LANG) +LANGBUILTIN(get_kernel_sub_group_count_for_ndrange, "Ui.", "tn", OCLC20_LANG) // OpenCL v2.0 s6.13.9 - Address space qualifier functions. LANGBUILTIN(to_global, "v*v*", "tn", OCLC20_LANG) LANGBUILTIN(to_local, "v*v*", "tn", OCLC20_LANG) LANGBUILTIN(to_private, "v*v*", "tn", OCLC20_LANG) +// OpenCL half load/store builtin +LANGBUILTIN(__builtin_store_half, "vdh*", "n", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_store_halff, "vfh*", "n", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_load_half, "dhC*", "nc", ALL_OCLC_LANGUAGES) +LANGBUILTIN(__builtin_load_halff, "fhC*", "nc", ALL_OCLC_LANGUAGES) + // Builtins for os_log/os_trace BUILTIN(__builtin_os_log_format_buffer_size, "zcC*.", "p:0:nut") BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt") +// OpenMP 4.0 +LANGBUILTIN(omp_is_initial_device, "i", "nc", OMP_LANG) + // Builtins for XRay BUILTIN(__xray_customevent, "vcC*z", "") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h index 87c1f93eedefe..963c72ea82e0e 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.h @@ -36,10 +36,13 @@ enum LanguageID { CXX_LANG = 0x4, // builtin for cplusplus only. OBJC_LANG = 0x8, // builtin for objective-c and objective-c++ MS_LANG = 0x10, // builtin requires MS mode. - OCLC20_LANG = 0x20, // builtin for OpenCL C only. + OCLC20_LANG = 0x20, // builtin for OpenCL C 2.0 only. + OCLC1X_LANG = 0x40, // builtin for OpenCL C 1.x only. + OMP_LANG = 0x80, // builtin requires OpenMP. ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages. ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. - ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. + ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG, // builtin requires MS mode. + ALL_OCLC_LANGUAGES = OCLC1X_LANG | OCLC20_LANG // builtin for OCLC languages. }; namespace Builtin { diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def index 1db4c1471029b..55a4f70176d00 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAArch64.def @@ -14,6 +14,10 @@ // The format of this database matches clang/Basic/Builtins.def. +#if defined(BUILTIN) && !defined(LANGBUILTIN) +# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + // In libgcc BUILTIN(__clear_cache, "vv*v*", "i") @@ -61,4 +65,9 @@ BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc") BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc") BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc") +LANGBUILTIN(__dmb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__dsb, "vUi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__isb, "vUi", "nc", ALL_MS_LANGUAGES) + #undef BUILTIN +#undef LANGBUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def index 6542acafe48a5..ec6a0fb917657 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -21,6 +21,7 @@ // SI+ only builtins. //===----------------------------------------------------------------------===// +BUILTIN(__builtin_amdgcn_dispatch_ptr, "Uc*2", "nc") BUILTIN(__builtin_amdgcn_kernarg_segment_ptr, "Uc*2", "nc") BUILTIN(__builtin_amdgcn_implicitarg_ptr, "Uc*2", "nc") @@ -120,6 +121,8 @@ TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts") // Special builtins. //===----------------------------------------------------------------------===// BUILTIN(__builtin_amdgcn_read_exec, "LUi", "nc") +BUILTIN(__builtin_amdgcn_read_exec_lo, "Ui", "nc") +BUILTIN(__builtin_amdgcn_read_exec_hi, "Ui", "nc") //===----------------------------------------------------------------------===// // R600-NI only builtins. diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def index 4e277f8a5a6b5..941d320d729f4 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def @@ -36,6 +36,7 @@ BUILTIN(__builtin_arm_smulwt, "iii", "nc") // Saturating arithmetic BUILTIN(__builtin_arm_qadd, "iii", "nc") BUILTIN(__builtin_arm_qsub, "iii", "nc") +BUILTIN(__builtin_arm_qdbl, "ii", "nc") BUILTIN(__builtin_arm_ssat, "iiUi", "nc") BUILTIN(__builtin_arm_usat, "UiiUi", "nc") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def index 14fc4adc25bc0..fda50b53589bd 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def @@ -17,7 +17,6 @@ // The builtins below are not autogenerated from iset.py. // Make sure you do not overwrite these. -BUILTIN(__builtin_SI_to_SXTHI_asrh, "ii", "") BUILTIN(__builtin_brev_ldd, "LLi*LLi*LLi*i", "") BUILTIN(__builtin_brev_ldw, "i*i*i*i", "") BUILTIN(__builtin_brev_ldh, "s*s*s*i", "") @@ -882,6 +881,7 @@ BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","") BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","") BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","") BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","") +BUILTIN(__builtin_HEXAGON_prefetch,"vv*","") BUILTIN(__builtin_HEXAGON_Y2_dccleana,"vv*","") BUILTIN(__builtin_HEXAGON_Y2_dccleaninva,"vv*","") BUILTIN(__builtin_HEXAGON_Y2_dcinva,"vv*","") @@ -1470,14 +1470,6 @@ BUILTIN(__builtin_HEXAGON_V6_vassign,"V16iV16i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vassign_128B,"V32iV32i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vcombine,"V32iV16iV16i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vcombine_128B,"V64iV32iV32i","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb,"V16iV16iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_128B,"V32iV32iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_acc,"V16iV16iV16iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_acc_128B,"V32iV32iV32iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_dv,"V32iV32iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_dv_128B,"V64iV64iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_dv_acc,"V32iV32iV32iLLii","v:60:") -BUILTIN(__builtin_HEXAGON_V6_vlutb_dv_acc_128B,"V64iV64iV64iLLii","v:60:") BUILTIN(__builtin_HEXAGON_V6_vdelta,"V16iV16iV16i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vdelta_128B,"V32iV32iV32i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vrdelta,"V16iV16iV16i","v:60:") @@ -1508,4 +1500,216 @@ BUILTIN(__builtin_HEXAGON_V6_lo_128B,"V32iV64i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vassignp,"V32iV32i","v:60:") BUILTIN(__builtin_HEXAGON_V6_vassignp_128B,"V64iV64i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_qpred_ai,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nqpred_ai,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nt_qpred_ai,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nt_nqpred_ai,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_qpred_ai_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nqpred_ai_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nt_qpred_ai_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vS32b_nt_nqpred_ai_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstoreq,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorenq,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorentq,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorentnq,"vV16iv*V16i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstoreq_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorenq_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorentq_128B,"vV32iv*V32i","v:60:") +BUILTIN(__builtin_HEXAGON_V6_vmaskedstorentnq_128B,"vV32iv*V32i","v:60:") + +BUILTIN(__builtin_HEXAGON_M6_vabsdiffb,"LLiLLiLLi","v:62:") +BUILTIN(__builtin_HEXAGON_M6_vabsdiffub,"LLiLLiLLi","v:62:") +BUILTIN(__builtin_HEXAGON_A6_vminub_RdP,"LLiLLiLLi","v:62:") +BUILTIN(__builtin_HEXAGON_S6_vsplatrbp,"LLii","v:62:") +BUILTIN(__builtin_HEXAGON_S6_vtrunehb_ppp,"LLiLLiLLi","v:62:") +BUILTIN(__builtin_HEXAGON_S6_vtrunohb_ppp,"LLiLLiLLi","v:62:") + +BUILTIN(__builtin_HEXAGON_V6_vlsrb,"V16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlsrb_128B,"V32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasrwuhrndsat,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasrwuhrndsat_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasruwuhrndsat,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasruwuhrndsat_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasrhbsat,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vasrhbsat_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vrounduwuh,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vrounduwuh_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vrounduhub,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vrounduhub_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduwsat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduwsat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduwsat_dv,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduwsat_dv_128B,"V64iV64iV64i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubuwsat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubuwsat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubuwsat_dv,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubuwsat_dv_128B,"V64iV64iV64i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddbsat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddbsat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddbsat_dv,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddbsat_dv_128B,"V64iV64iV64i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubbsat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubbsat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubbsat_dv,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubbsat_dv_128B,"V64iV64iV64i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddububb_sat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddububb_sat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubububb_sat,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubububb_sat_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddhw_acc,"V32iV32iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddhw_acc_128B,"V64iV64iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduhw_acc,"V32iV32iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vadduhw_acc_128B,"V64iV64iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddubh_acc,"V32iV32iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddubh_acc_128B,"V64iV64iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyewuh_64,"V32iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyewuh_64_128B,"V64iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyowh_64_acc,"V32iV32iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyowh_64_acc_128B,"V64iV64iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhb,"V32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhb_128B,"V64iV64ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhb_acc,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhb_acc_128B,"V64iV64iV64ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyiwub,"V16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyiwub_128B,"V32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyiwub_acc,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmpyiwub_acc_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandnqrt,"V16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandnqrt_128B,"V32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandnqrt_acc,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandnqrt_acc_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandvqv,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandvqv_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandvnqv,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vandvnqv_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_pred_scalar2v2,"V16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_pred_scalar2v2_128B,"V32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_shuffeqw,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_shuffeqw_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_shuffeqh,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_shuffeqh_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmaxb,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vmaxb_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vminb,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vminb_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsatuwuh,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsatuwuh_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_lvsplath,"V16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_lvsplath_128B,"V32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_lvsplatb,"V16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_lvsplatb_128B,"V32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddclbw,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddclbw_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddclbh,"V16iV16iV16i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddclbh_128B,"V32iV32iV32i","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvbi,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvbi_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvb_oracci,"V16iV16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvb_oracci_128B,"V32iV32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwhi,"V32iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwhi_128B,"V64iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwh_oracci,"V32iV32iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwh_oracci_128B,"V64iV64iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvb_nm,"V16iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvvb_nm_128B,"V32iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwh_nm,"V32iV16iV16ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vlutvwh_nm_128B,"V64iV32iV32ii","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddcarry,"V16iV16iV16iv*","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vaddcarry_128B,"V32iV32iV32iv*","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubcarry,"V16iV16iV16iv*","v:62:") +BUILTIN(__builtin_HEXAGON_V6_vsubcarry_128B,"V32iV32iV32iv*","v:62:") + +BUILTIN(__builtin_HEXAGON_A6_vcmpbeq_notany,"iLLiLLi","v:65:") +BUILTIN(__builtin_HEXAGON_A6_vcmpbeq_notany_128B,"iLLiLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt,"V32iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt_128B,"V64iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt_acc,"V32iV32iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B,"V64iV64iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpybub_rtt,"V32iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpybub_rtt_128B,"V64iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpybub_rtt_acc,"V32iV32iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B,"V64iV64iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruwuhsat,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruwuhsat_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruhubsat,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruhubsat_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruhubrndsat,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasruhubrndsat_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vaslh_acc,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vaslh_acc_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasrh_acc,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vasrh_acc_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavguw,"V16iV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavguw_128B,"V32iV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavguwrnd,"V16iV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavguwrnd_128B,"V32iV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavgb,"V16iV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavgb_128B,"V32iV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavgbrnd,"V16iV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vavgbrnd_128B,"V32iV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vnavgb,"V16iV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vnavgb_128B,"V32iV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vabsb,"V16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vabsb_128B,"V32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vabsb_sat,"V16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vabsb_sat_128B,"V32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpabuu,"V32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpabuu_128B,"V64iV64ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpabuu_acc,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpabuu_acc_128B,"V64iV64iV64ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyh_acc,"V32iV32iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyh_acc_128B,"V64iV64iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpahhsat,"V16iV16iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpahhsat_128B,"V32iV32iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhuhsat,"V16iV16iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpauhuhsat_128B,"V32iV32iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpsuhuhsat,"V16iV16iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpsuhuhsat_128B,"V32iV32iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vlut4,"V16iV16iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vlut4_128B,"V32iV32iLLi","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyuhe,"V16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyuhe_128B,"V32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyuhe_acc,"V16iV16iV16ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vmpyuhe_acc_128B,"V32iV32iV32ii","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermw,"vv*iiV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermw_128B,"vv*iiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermh,"vv*iiV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermh_128B,"vv*iiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhw,"vv*iiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhw_128B,"vv*iiV64i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermwq,"vv*V16iiiV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermwq_128B,"vv*V32iiiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhq,"vv*V16iiiV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhq_128B,"vv*V32iiiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhwq,"vv*V16iiiV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vgathermhwq_128B,"vv*V32iiiV64i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermw,"viiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermw_128B,"viiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermh,"viiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermh_128B,"viiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermw_add,"viiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermw_add_128B,"viiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermh_add,"viiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermh_add_128B,"viiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermwq,"vV16iiiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermwq_128B,"vV32iiiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhq,"vV16iiiV16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhq_128B,"vV32iiiV32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhw,"viiV32iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhw_128B,"viiV64iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhwq,"vV16iiiV32iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhwq_128B,"vV32iiiV64iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhw_add,"viiV32iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vscattermhw_add_128B,"viiV64iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqb,"V16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqb_128B,"V32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqh,"V16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqh_128B,"V32iV32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqw,"V16iV16i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vprefixqw_128B,"V32iV32i","v:65:") + +BUILTIN(__builtin_HEXAGON_V6_vdd0,"V32i","v:65:") +BUILTIN(__builtin_HEXAGON_V6_vdd0_128B,"V64i","v:65:") + + #undef BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def index afea6cb0f1b25..7bab73a3b110c 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -371,6 +371,9 @@ BUILTIN(__nvvm_bitcast_i2f, "fi", "") BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "") BUILTIN(__nvvm_bitcast_d2ll, "LLid", "") +// FNS +TARGET_BUILTIN(__nvvm_fns, "UiUiUii", "n", "ptx60") + // Sync BUILTIN(__syncthreads, "v", "") @@ -378,6 +381,9 @@ BUILTIN(__nvvm_bar0_popc, "ii", "") BUILTIN(__nvvm_bar0_and, "ii", "") BUILTIN(__nvvm_bar0_or, "ii", "") BUILTIN(__nvvm_bar_sync, "vi", "n") +TARGET_BUILTIN(__nvvm_bar_warp_sync, "vUi", "n", "ptx60") +TARGET_BUILTIN(__nvvm_barrier_sync, "vUi", "n", "ptx60") +TARGET_BUILTIN(__nvvm_barrier_sync_cnt, "vUiUi", "n", "ptx60") // Shuffle @@ -390,6 +396,33 @@ BUILTIN(__nvvm_shfl_bfly_f32, "ffii", "") BUILTIN(__nvvm_shfl_idx_i32, "iiii", "") BUILTIN(__nvvm_shfl_idx_f32, "ffii", "") +TARGET_BUILTIN(__nvvm_shfl_sync_down_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_down_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_up_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_up_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_bfly_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_bfly_f32, "fUifii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_idx_i32, "iUiiii", "", "ptx60") +TARGET_BUILTIN(__nvvm_shfl_sync_idx_f32, "fUifii", "", "ptx60") + +// Vote +BUILTIN(__nvvm_vote_all, "bb", "") +BUILTIN(__nvvm_vote_any, "bb", "") +BUILTIN(__nvvm_vote_uni, "bb", "") +BUILTIN(__nvvm_vote_ballot, "Uib", "") + +TARGET_BUILTIN(__nvvm_vote_all_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_any_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_uni_sync, "bUib", "", "ptx60") +TARGET_BUILTIN(__nvvm_vote_ballot_sync, "UiUib", "", "ptx60") + +// Match +TARGET_BUILTIN(__nvvm_match_any_sync_i32, "UiUiUi", "", "ptx60") +TARGET_BUILTIN(__nvvm_match_any_sync_i64, "WiUiWi", "", "ptx60") +// These return a pair {value, predicate}, which requires custom lowering. +TARGET_BUILTIN(__nvvm_match_all_sync_i32p, "UiUiUii*", "", "ptx60") +TARGET_BUILTIN(__nvvm_match_all_sync_i64p, "WiUiWii*", "", "ptx60") + // Membar BUILTIN(__nvvm_membar_cta, "v", "") @@ -451,7 +484,7 @@ TARGET_BUILTIN(__nvvm_atom_cta_add_gen_f, "ffD*f", "n", "satom") TARGET_BUILTIN(__nvvm_atom_sys_add_gen_f, "ffD*f", "n", "satom") BUILTIN(__nvvm_atom_add_g_d, "ddD*1d", "n") BUILTIN(__nvvm_atom_add_s_d, "ddD*3d", "n") -BUILTIN(__nvvm_atom_add_gen_d, "ddD*d", "n") +TARGET_BUILTIN(__nvvm_atom_add_gen_d, "ddD*d", "n", "satom") TARGET_BUILTIN(__nvvm_atom_cta_add_gen_d, "ddD*d", "n", "satom") TARGET_BUILTIN(__nvvm_atom_sys_add_gen_d, "ddD*d", "n", "satom") @@ -658,5 +691,18 @@ BUILTIN(__nvvm_ldg_f2, "E2fE2fC*", "") BUILTIN(__nvvm_ldg_f4, "E4fE4fC*", "") BUILTIN(__nvvm_ldg_d2, "E2dE2dC*", "") +// Builtins to support WMMA instructions on sm_70 +TARGET_BUILTIN(__hmma_m16n16k16_ld_a, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_b, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f16, "vi*iC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f32, "vf*fC*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_st_c_f16, "vi*i*UiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_st_c_f32, "vf*f*UiIi", "", "ptx60") + +TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f16, "vi*iC*iC*iC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f16, "vf*iC*iC*iC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f32, "vf*iC*iC*fC*IiIi", "", "ptx60") +TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f32, "vi*iC*iC*fC*IiIi", "", "ptx60") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def index 2f8f8919e5b30..d0be48467f1f0 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def @@ -32,7 +32,9 @@ // Miscellaneous builtin for checking x86 cpu features. // TODO: Make this somewhat generic so that other backends // can use it? +BUILTIN(__builtin_cpu_init, "v", "n") BUILTIN(__builtin_cpu_supports, "bcC*", "nc") +BUILTIN(__builtin_cpu_is, "bcC*", "nc") // Undefined Values // @@ -264,8 +266,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "", "sse2") TARGET_BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "", "sse2") -TARGET_BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "", "sse2") -TARGET_BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "", "sse2") TARGET_BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "", "sse2") @@ -520,8 +520,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "", "avx2") TARGET_BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIi", "", "avx2") -TARGET_BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "", "avx2") -TARGET_BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "", "avx2") TARGET_BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "", "avx2") TARGET_BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "", "avx2") @@ -640,8 +638,21 @@ TARGET_BUILTIN(__builtin_ia32_xrstors, "vv*ULLi", "", "xsaves") TARGET_BUILTIN(__builtin_ia32_xsavec, "vv*ULLi", "", "xsavec") TARGET_BUILTIN(__builtin_ia32_xsaves, "vv*ULLi", "", "xsaves") +// SHSTK +TARGET_BUILTIN(__builtin_ia32_incsspd, "vUi", "u", "shstk") +TARGET_BUILTIN(__builtin_ia32_rdsspd, "UiUi", "Un", "shstk") +TARGET_BUILTIN(__builtin_ia32_saveprevssp, "v", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_rstorssp, "vv*", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_wrssd, "vUiv*", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_wrussd, "vUiv*", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_setssbsy, "v", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_clrssbsy, "vv*", "", "shstk") + //CLFLUSHOPT -TARGET_BUILTIN(__builtin_ia32_clflushopt, "vc*", "", "clflushopt") +TARGET_BUILTIN(__builtin_ia32_clflushopt, "vvC*", "", "clflushopt") + +//CLWB +TARGET_BUILTIN(__builtin_ia32_clwb, "vvC*", "", "clwb") // ADX TARGET_BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "", "adx") @@ -681,36 +692,18 @@ TARGET_BUILTIN(__builtin_ia32_sha256msg2, "V4iV4iV4i", "", "sha") // FMA TARGET_BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmaddsd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubps, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubpd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubss, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubsd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmaddps, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmaddpd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmaddss, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmaddsd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubps, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubpd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubss, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubsd, "V2dV2dV2dV2d", "", "fma|fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddss3, "V4fV4fV4fV4f", "", "fma") +TARGET_BUILTIN(__builtin_ia32_vfmaddsd3, "V2dV2dV2dV2d", "", "fma") +TARGET_BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "", "fma4") +TARGET_BUILTIN(__builtin_ia32_vfmaddsd, "V2dV2dV2dV2d", "", "fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddsubps, "V4fV4fV4fV4f", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd, "V2dV2dV2dV2d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubaddps, "V4fV4fV4fV4f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd, "V2dV2dV2dV2d", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddps256, "V8fV8fV8fV8f", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubps256, "V8fV8fV8fV8f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfnmaddps256, "V8fV8fV8fV8f", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfnmaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubps256, "V8fV8fV8fV8f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfnmsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "", "fma|fma4") -TARGET_BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "", "fma|fma4") TARGET_BUILTIN(__builtin_ia32_vfmaddpd128_mask, "V2dV2dV2dV2dUc", "", "avx512vl") TARGET_BUILTIN(__builtin_ia32_vfmaddpd128_mask3, "V2dV2dV2dV2dUc", "", "avx512vl") @@ -909,39 +902,10 @@ TARGET_BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsIi", "", "avx512 TARGET_BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsIi", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUcIi", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUcIi", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fIiUsIi", "", "avx512f") +TARGET_BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fIiUsIi", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_cmpps256_mask, "UcV8fV8fIiUc", "", "avx512vl") TARGET_BUILTIN(__builtin_ia32_cmpps128_mask, "UcV4fV4fIiUc", "", "avx512vl") - -TARGET_BUILTIN(__builtin_ia32_pcmpeqb512_mask, "LLiV64cV64cLLi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpeqd512_mask, "sV16iV16is", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pcmpeqq512_mask, "cV8LLiV8LLic", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pcmpeqw512_mask, "iV32sV32si", "", "avx512bw") - -TARGET_BUILTIN(__builtin_ia32_pcmpeqb256_mask, "iV32cV32ci", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpeqd256_mask, "cV8iV8ic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpeqq256_mask, "cV4LLiV4LLic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpeqw256_mask, "sV16sV16ss", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpeqb128_mask, "sV16cV16cs", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpeqd128_mask, "cV4iV4ic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpeqq128_mask, "cV2LLiV2LLic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpeqw128_mask, "cV8sV8sc", "", "avx512vl,avx512bw") - -TARGET_BUILTIN(__builtin_ia32_pcmpgtb512_mask, "LLiV64cV64cLLi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpgtd512_mask, "sV16iV16is", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pcmpgtq512_mask, "cV8LLiV8LLic", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pcmpgtw512_mask, "iV32sV32si", "", "avx512bw") - -TARGET_BUILTIN(__builtin_ia32_pcmpgtb256_mask, "iV32cV32ci", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpgtd256_mask, "cV8iV8ic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpgtq256_mask, "cV4LLiV4LLic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpgtw256_mask, "sV16sV16ss", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpgtb128_mask, "sV16cV16cs", "", "avx512vl,avx512bw") -TARGET_BUILTIN(__builtin_ia32_pcmpgtd128_mask, "cV4iV4ic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpgtq128_mask, "cV2LLiV2LLic", "", "avx512vl") -TARGET_BUILTIN(__builtin_ia32_pcmpgtw128_mask, "cV8sV8sc", "", "avx512vl,avx512bw") - TARGET_BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8dIiUcIi", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_cmppd256_mask, "UcV4dV4dIiUc", "", "avx512vl") TARGET_BUILTIN(__builtin_ia32_cmppd128_mask, "UcV2dV2dIiUc", "", "avx512vl") @@ -973,9 +937,6 @@ TARGET_BUILTIN(__builtin_ia32_pminud512_mask, "V16iV16iV16iV16iUs", "", "avx512f TARGET_BUILTIN(__builtin_ia32_pminuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_pmuldq512, "V8LLiV16iV16i", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_pmuludq512, "V8LLiV16iV16i", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16iiC*V16iUs", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLiLLiC*V8LLiUc", "", "avx512f") TARGET_BUILTIN(__builtin_ia32_loadups512_mask, "V16ffC*V16fUs", "", "avx512f") @@ -1072,8 +1033,6 @@ TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx51 TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_paddusw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pavgb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") -TARGET_BUILTIN(__builtin_ia32_pavgw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw") TARGET_BUILTIN(__builtin_ia32_pmaxub512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw") @@ -1101,6 +1060,10 @@ TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx5 TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd") TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd") +TARGET_BUILTIN(__builtin_ia32_vpopcntd_128, "V4iV4i", "", "avx512vpopcntdq,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpopcntq_128, "V2LLiV2LLi", "", "avx512vpopcntdq,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpopcntd_256, "V8iV8i", "", "avx512vpopcntdq,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vpopcntq_256, "V4LLiV4LLi", "", "avx512vpopcntdq,avx512vl") TARGET_BUILTIN(__builtin_ia32_vpopcntd_512, "V16iV16i", "", "avx512vpopcntdq") TARGET_BUILTIN(__builtin_ia32_vpopcntq_512, "V8LLiV8LLi", "", "avx512vpopcntdq") @@ -1378,11 +1341,6 @@ TARGET_BUILTIN(__builtin_ia32_movdqa64load128_mask, "V2LLiV2LLiC*V2LLiUc","","av TARGET_BUILTIN(__builtin_ia32_movdqa64load256_mask, "V4LLiV4LLiC*V4LLiUc","","avx512vl") TARGET_BUILTIN(__builtin_ia32_movdqa64store128_mask, "vV2LLi*V2LLiUc","","avx512f") TARGET_BUILTIN(__builtin_ia32_movdqa64store256_mask, "vV4LLi*V4LLiUc","","avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb512_gpr_mask, "V64ccV64cULLi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb128_gpr_mask, "V16ccV16cUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastb256_gpr_mask, "V32ccV32cUi","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd128_gpr_mask, "V4iiV4iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastd256_gpr_mask, "V8iiV8iUc","","avx512vl") TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_maskz, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") TARGET_BUILTIN(__builtin_ia32_vpmadd52luq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma") @@ -1494,28 +1452,6 @@ TARGET_BUILTIN(__builtin_ia32_vpermt2vard512_maskz, "V16iV16iV16iV16iUs","","avx TARGET_BUILTIN(__builtin_ia32_vpermt2varpd512_maskz, "V8dV8LLiV8dV8dUc","","avx512f") TARGET_BUILTIN(__builtin_ia32_vpermt2varps512_maskz, "V16fV16iV16fV16fUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_vpermt2varq512_maskz, "V8LLiV8LLiV8LLiV8LLiUc","","avx512f") -TARGET_BUILTIN(__builtin_ia32_ptestmb512, "ULLiV64cV64cULLi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_ptestmw512, "UiV32sV32sUi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_ptestnmb512, "ULLiV64cV64cULLi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_ptestnmw512, "UiV32sV32sUi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_ptestmb128, "UsV16cV16cUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmb256, "UiV32cV32cUi","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmw128, "UcV8sV8sUc","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmw256, "UsV16sV16sUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmb128, "UsV16cV16cUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmb256, "UiV32cV32cUi","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmw128, "UcV8sV8sUc","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmw256, "UsV16sV16sUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmd128, "UcV4iV4iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmd256, "UcV8iV8iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmq128, "UcV2LLiV2LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestmq256, "UcV4LLiV4LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmd128, "UcV4iV4iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmd256, "UcV8iV8iUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmq128, "UcV2LLiV2LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmq256, "UcV4LLiV4LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_ptestnmd512, "UsV16iV16iUs","","avx512f") -TARGET_BUILTIN(__builtin_ia32_ptestnmq512, "UcV8LLiV8LLiUc","","avx512f") TARGET_BUILTIN(__builtin_ia32_rndscalesd_round_mask, "V2dV2dV2dV2dUcIiIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_rndscaless_round_mask, "V4fV4fV4fV4fUcIiIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_scalefpd512_mask, "V8dV8dV8dV8dUcIi","","avx512f") @@ -1587,20 +1523,6 @@ TARGET_BUILTIN(__builtin_ia32_cvtmask2q128, "V2LLiUc","","avx512dq,avx512vl") TARGET_BUILTIN(__builtin_ia32_cvtmask2q256, "V4LLiUc","","avx512dq,avx512vl") TARGET_BUILTIN(__builtin_ia32_cvtq2mask128, "UcV2LLi","","avx512dq,avx512vl") TARGET_BUILTIN(__builtin_ia32_cvtq2mask256, "UcV4LLi","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastmb512, "V8LLiUc","","avx512cd") -TARGET_BUILTIN(__builtin_ia32_broadcastmw512, "V16iUs","","avx512cd") -TARGET_BUILTIN(__builtin_ia32_broadcastmb128, "V2LLiUc","","avx512cd,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastmb256, "V4LLiUc","","avx512cd,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastmw128, "V4iUs","","avx512cd,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastmw256, "V8iUs","","avx512cd,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_512_mask, "V16fV4fV16fUs","","avx512dq") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_512_mask, "V16iV4iV16iUs","","avx512dq") -TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_256_mask, "V8fV4fV8fUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_128_mask, "V4iV4iV4iUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_256_mask, "V8iV4iV8iUc","","avx512dq,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw512_gpr_mask, "V32shV32sUi","","avx512bw") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw256_gpr_mask, "V16shV16sUs","","avx512bw,avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastw128_gpr_mask, "V8ssV8sUc","","avx512bw,avx512vl") TARGET_BUILTIN(__builtin_ia32_pmovsdb512_mask, "V16cV16iV16cUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_pmovsdb512mem_mask, "vV16c*V16iUs","","avx512f") TARGET_BUILTIN(__builtin_ia32_pmovswb512mem_mask, "vV32c*V32sUi","","avx512bw") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def index 4cde153d83722..fe2c887c7e0f5 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def @@ -40,6 +40,7 @@ TARGET_HEADER_BUILTIN(_InterlockedExchangeSub64, "LLiLLiD*LLi", "nh", "intrin.h" TARGET_HEADER_BUILTIN(_InterlockedIncrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedOr64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedXor64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_InterlockedCompareExchange128, "UcLLiD*LLiLLiLLi*", "nh", "intrin.h", ALL_MS_LANGUAGES, "cx16") TARGET_BUILTIN(__builtin_ia32_readeflags_u64, "ULLi", "n", "") TARGET_BUILTIN(__builtin_ia32_writeeflags_u64, "vULLi", "n", "") @@ -60,6 +61,10 @@ TARGET_BUILTIN(__builtin_ia32_xsaveopt64, "vv*ULLi", "", "xsaveopt") TARGET_BUILTIN(__builtin_ia32_xrstors64, "vv*ULLi", "", "xsaves") TARGET_BUILTIN(__builtin_ia32_xsavec64, "vv*ULLi", "", "xsavec") TARGET_BUILTIN(__builtin_ia32_xsaves64, "vv*ULLi", "", "xsaves") +TARGET_BUILTIN(__builtin_ia32_incsspq, "vULLi", "u", "shstk") +TARGET_BUILTIN(__builtin_ia32_rdsspq, "ULLiULLi", "Un", "shstk") +TARGET_BUILTIN(__builtin_ia32_wrssq, "vULLiv*", "", "shstk") +TARGET_BUILTIN(__builtin_ia32_wrussq, "vULLiv*", "", "shstk") TARGET_BUILTIN(__builtin_ia32_addcarryx_u64, "UcUcULLiULLiULLi*", "", "adx") TARGET_BUILTIN(__builtin_ia32_addcarry_u64, "UcUcULLiULLiULLi*", "", "") TARGET_BUILTIN(__builtin_ia32_subborrow_u64, "UcUcULLiULLiULLi*", "", "") @@ -71,9 +76,6 @@ TARGET_BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "", "bmi2") TARGET_BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "", "tbm") TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcULLiUiUi", "", "lwp") TARGET_BUILTIN(__builtin_ia32_lwpval64, "vULLiUiUi", "", "lwp") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "", "avx512f") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq128_gpr_mask, "V2LLiULLiV2LLiUc","","avx512vl") -TARGET_BUILTIN(__builtin_ia32_pbroadcastq256_gpr_mask, "V4LLiULLiV4LLiUc","","avx512vl") TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "LLiV2dIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_vcvtsd2usi64, "ULLiV2dIi","","avx512f") TARGET_BUILTIN(__builtin_ia32_vcvtss2si64, "LLiV4fIi","","avx512f") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h index dd9c55431e015..cc27bbb48e0d1 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/CharInfo.h @@ -40,14 +40,14 @@ namespace charinfo { } // end namespace charinfo /// Returns true if this is an ASCII character. -LLVM_READNONE static inline bool isASCII(char c) { +LLVM_READNONE inline bool isASCII(char c) { return static_cast<unsigned char>(c) <= 127; } /// Returns true if this is a valid first character of a C identifier, /// which is [a-zA-Z_]. -LLVM_READONLY static inline bool isIdentifierHead(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isIdentifierHead(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER)) return true; @@ -56,8 +56,8 @@ LLVM_READONLY static inline bool isIdentifierHead(unsigned char c, /// Returns true if this is a body character of a C identifier, /// which is [a-zA-Z0-9_]. -LLVM_READONLY static inline bool isIdentifierBody(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isIdentifierBody(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER)) return true; @@ -68,7 +68,7 @@ LLVM_READONLY static inline bool isIdentifierBody(unsigned char c, /// ' ', '\\t', '\\f', '\\v'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) { +LLVM_READONLY inline bool isHorizontalWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0; } @@ -76,7 +76,7 @@ LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) { /// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) { +LLVM_READONLY inline bool isVerticalWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_VERT_WS) != 0; } @@ -85,43 +85,43 @@ LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) { /// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'. /// /// Note that this returns false for '\\0'. -LLVM_READONLY static inline bool isWhitespace(unsigned char c) { +LLVM_READONLY inline bool isWhitespace(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0; } /// Return true if this character is an ASCII digit: [0-9] -LLVM_READONLY static inline bool isDigit(unsigned char c) { +LLVM_READONLY inline bool isDigit(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_DIGIT) != 0; } /// Return true if this character is a lowercase ASCII letter: [a-z] -LLVM_READONLY static inline bool isLowercase(unsigned char c) { +LLVM_READONLY inline bool isLowercase(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_LOWER) != 0; } /// Return true if this character is an uppercase ASCII letter: [A-Z] -LLVM_READONLY static inline bool isUppercase(unsigned char c) { +LLVM_READONLY inline bool isUppercase(unsigned char c) { using namespace charinfo; return (InfoTable[c] & CHAR_UPPER) != 0; } /// Return true if this character is an ASCII letter: [a-zA-Z] -LLVM_READONLY static inline bool isLetter(unsigned char c) { +LLVM_READONLY inline bool isLetter(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0; } /// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9] -LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) { +LLVM_READONLY inline bool isAlphanumeric(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0; } /// Return true if this character is an ASCII hex digit: [0-9a-fA-F] -LLVM_READONLY static inline bool isHexDigit(unsigned char c) { +LLVM_READONLY inline bool isHexDigit(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0; } @@ -129,7 +129,7 @@ LLVM_READONLY static inline bool isHexDigit(unsigned char c) { /// Return true if this character is an ASCII punctuation character. /// /// Note that '_' is both a punctuation character and an identifier character! -LLVM_READONLY static inline bool isPunctuation(unsigned char c) { +LLVM_READONLY inline bool isPunctuation(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0; } @@ -137,7 +137,7 @@ LLVM_READONLY static inline bool isPunctuation(unsigned char c) { /// Return true if this character is an ASCII printable character; that is, a /// character that should take exactly one column to print in a fixed-width /// terminal. -LLVM_READONLY static inline bool isPrintable(unsigned char c) { +LLVM_READONLY inline bool isPrintable(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT| CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0; @@ -145,14 +145,14 @@ LLVM_READONLY static inline bool isPrintable(unsigned char c) { /// Return true if this is the body character of a C preprocessing number, /// which is [a-zA-Z0-9_.]. -LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) { +LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0; } /// Return true if this is the body character of a C++ raw string delimiter. -LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) { +LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) { using namespace charinfo; return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD| CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0; @@ -162,7 +162,7 @@ LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) { /// Converts the given ASCII character to its lowercase equivalent. /// /// If the character is not an uppercase character, it is returned as is. -LLVM_READONLY static inline char toLowercase(char c) { +LLVM_READONLY inline char toLowercase(char c) { if (isUppercase(c)) return c + 'a' - 'A'; return c; @@ -171,7 +171,7 @@ LLVM_READONLY static inline char toLowercase(char c) { /// Converts the given ASCII character to its uppercase equivalent. /// /// If the character is not a lowercase character, it is returned as is. -LLVM_READONLY static inline char toUppercase(char c) { +LLVM_READONLY inline char toUppercase(char c) { if (isLowercase(c)) return c + 'A' - 'a'; return c; @@ -182,7 +182,7 @@ LLVM_READONLY static inline char toUppercase(char c) { /// /// Note that this is a very simple check; it does not accept '$' or UCNs as /// valid identifier characters. -LLVM_READONLY static inline bool isValidIdentifier(StringRef S) { +LLVM_READONLY inline bool isValidIdentifier(StringRef S) { if (S.empty() || !isIdentifierHead(S[0])) return false; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Cuda.h b/contrib/llvm/tools/clang/include/clang/Basic/Cuda.h index ad1139b8c197e..1a0731c37a35f 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Cuda.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Cuda.h @@ -21,6 +21,8 @@ enum class CudaVersion { CUDA_70, CUDA_75, CUDA_80, + CUDA_90, + LATEST = CUDA_90, }; const char *CudaVersionToString(CudaVersion V); @@ -41,6 +43,7 @@ enum class CudaArch { SM_60, SM_61, SM_62, + SM_70, }; const char *CudaArchToString(CudaArch A); @@ -60,6 +63,7 @@ enum class CudaVirtualArch { COMPUTE_60, COMPUTE_61, COMPUTE_62, + COMPUTE_70, }; const char *CudaVirtualArchToString(CudaVirtualArch A); @@ -72,6 +76,9 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A); /// Get the earliest CudaVersion that supports the given CudaArch. CudaVersion MinVersionForCudaArch(CudaArch A); +/// Get the latest CudaVersion that supports the given CudaArch. +CudaVersion MaxVersionForCudaArch(CudaArch A); + } // namespace clang #endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td index 3298a80e51341..67ca9e5c6c62c 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td @@ -1,66 +1,68 @@ class AttrSubject; -class Decl<bit abstract = 0> : AttrSubject { +class Decl<string diagSpelling = "", bit abstract = 0> : AttrSubject { bit Abstract = abstract; + string DiagSpelling = diagSpelling; } -class DDecl<Decl base, bit abstract = 0> : Decl<abstract> { +class DDecl<Decl base, string diagSpelling = "", bit abstract = 0> + : Decl<diagSpelling, abstract> { Decl Base = base; } -class DeclContext { } +class DeclContext {} def TranslationUnit : Decl, DeclContext; def PragmaComment : Decl; def PragmaDetectMismatch : Decl; def ExternCContext : Decl, DeclContext; -def Named : Decl<1>; - def Namespace : DDecl<Named>, DeclContext; +def Named : Decl<"named declarations", 1>; + def Namespace : DDecl<Named, "namespaces">, DeclContext; def UsingDirective : DDecl<Named>; def NamespaceAlias : DDecl<Named>; - def Label : DDecl<Named>; - def Type : DDecl<Named, 1>; - def TypedefName : DDecl<Type, 1>; + def Label : DDecl<Named, "labels">; + def Type : DDecl<Named, "types", 1>; + def TypedefName : DDecl<Type, "typedefs", 1>; def Typedef : DDecl<TypedefName>; def TypeAlias : DDecl<TypedefName>; def ObjCTypeParam : DDecl<TypedefName>; def UnresolvedUsingTypename : DDecl<Type>; - def Tag : DDecl<Type, 1>, DeclContext; - def Enum : DDecl<Tag>; - def Record : DDecl<Tag>; - def CXXRecord : DDecl<Record>; + def Tag : DDecl<Type, "tag types", 1>, DeclContext; + def Enum : DDecl<Tag, "enums">; + def Record : DDecl<Tag, "structs, unions, classes">; + def CXXRecord : DDecl<Record, "classes">; def ClassTemplateSpecialization : DDecl<CXXRecord>; def ClassTemplatePartialSpecialization : DDecl<ClassTemplateSpecialization>; def TemplateTypeParm : DDecl<Type>; - def Value : DDecl<Named, 1>; - def EnumConstant : DDecl<Value>; + def Value : DDecl<Named, "value declarations", 1>; + def EnumConstant : DDecl<Value, "enumerators">; def UnresolvedUsingValue : DDecl<Value>; def IndirectField : DDecl<Value>; def Binding : DDecl<Value>; def OMPDeclareReduction : DDecl<Value>, DeclContext; - def Declarator : DDecl<Value, 1>; - def Field : DDecl<Declarator>; + def Declarator : DDecl<Value, "declarators", 1>; + def Field : DDecl<Declarator, "non-static data members">; def ObjCIvar : DDecl<Field>; def ObjCAtDefsField : DDecl<Field>; def MSProperty : DDecl<Declarator>; - def Function : DDecl<Declarator>, DeclContext; + def Function : DDecl<Declarator, "functions">, DeclContext; def CXXDeductionGuide : DDecl<Function>; def CXXMethod : DDecl<Function>; def CXXConstructor : DDecl<CXXMethod>; def CXXDestructor : DDecl<CXXMethod>; def CXXConversion : DDecl<CXXMethod>; - def Var : DDecl<Declarator>; + def Var : DDecl<Declarator, "variables">; def VarTemplateSpecialization : DDecl<Var>; def VarTemplatePartialSpecialization : DDecl<VarTemplateSpecialization>; def ImplicitParam : DDecl<Var>; - def ParmVar : DDecl<Var>; + def ParmVar : DDecl<Var, "parameters">; def Decomposition : DDecl<Var>; def OMPCapturedExpr : DDecl<Var>; def NonTypeTemplateParm : DDecl<Declarator>; - def Template : DDecl<Named, 1>; - def RedeclarableTemplate : DDecl<Template, 1>; + def Template : DDecl<Named, "templates", 1>; + def RedeclarableTemplate : DDecl<Template, "redeclarable templates", 1>; def FunctionTemplate : DDecl<RedeclarableTemplate>; def ClassTemplate : DDecl<RedeclarableTemplate>; def VarTemplate : DDecl<RedeclarableTemplate>; @@ -71,15 +73,16 @@ def Named : Decl<1>; def UsingPack : DDecl<Named>; def UsingShadow : DDecl<Named>; def ConstructorUsingShadow : DDecl<UsingShadow>; - def ObjCMethod : DDecl<Named>, DeclContext; - def ObjCContainer : DDecl<Named, 1>, DeclContext; + def ObjCMethod : DDecl<Named, "Objective-C methods">, DeclContext; + def ObjCContainer : DDecl<Named, "Objective-C containers", 1>, DeclContext; def ObjCCategory : DDecl<ObjCContainer>; - def ObjCProtocol : DDecl<ObjCContainer>; - def ObjCInterface : DDecl<ObjCContainer>; - def ObjCImpl : DDecl<ObjCContainer, 1>; + def ObjCProtocol : DDecl<ObjCContainer, "Objective-C protocols">; + def ObjCInterface : DDecl<ObjCContainer, "Objective-C interfaces">; + def ObjCImpl + : DDecl<ObjCContainer, "Objective-C implementation declarations", 1>; def ObjCCategoryImpl : DDecl<ObjCImpl>; def ObjCImplementation : DDecl<ObjCImpl>; - def ObjCProperty : DDecl<Named>; + def ObjCProperty : DDecl<Named, "Objective-C properties">; def ObjCCompatibleAlias : DDecl<Named>; def LinkageSpec : Decl, DeclContext; def Export : Decl, DeclContext; @@ -89,7 +92,7 @@ def AccessSpec : Decl; def Friend : Decl; def FriendTemplate : Decl; def StaticAssert : Decl; -def Block : Decl, DeclContext; +def Block : Decl<"blocks">, DeclContext; def Captured : Decl, DeclContext; def ClassScopeFunctionSpecialization : Decl; def Import : Decl; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h index 22cded21c12df..a7458d45618ee 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h @@ -575,13 +575,15 @@ public: OverloadsShown getShowOverloads() const { return ShowOverloads; } /// \brief Pretend that the last diagnostic issued was ignored, so any - /// subsequent notes will be suppressed. + /// subsequent notes will be suppressed, or restore a prior ignoring + /// state after ignoring some diagnostics and their notes, possibly in + /// the middle of another diagnostic. /// /// This can be used by clients who suppress diagnostics themselves. - void setLastDiagnosticIgnored() { + void setLastDiagnosticIgnored(bool Ignored = true) { if (LastDiagLevel == DiagnosticIDs::Fatal) FatalErrorOccurred = true; - LastDiagLevel = DiagnosticIDs::Ignored; + LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning; } /// \brief Determine whether the previous diagnostic was ignored. This can diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td index f25068eca1322..52ccf350e651e 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td @@ -133,10 +133,12 @@ include "DiagnosticASTKinds.td" include "DiagnosticAnalysisKinds.td" include "DiagnosticCommentKinds.td" include "DiagnosticCommonKinds.td" +include "DiagnosticCrossTUKinds.td" include "DiagnosticDriverKinds.td" include "DiagnosticFrontendKinds.td" include "DiagnosticLexKinds.td" include "DiagnosticParseKinds.td" +include "DiagnosticRefactoringKinds.td" include "DiagnosticSemaKinds.td" include "DiagnosticSerializationKinds.td" diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td index b3cba2066edd8..215580b2e9b66 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -127,6 +127,10 @@ def note_constexpr_access_null : Note< def note_constexpr_access_past_end : Note< "%select{read of|assignment to|increment of|decrement of}0 " "dereferenced one-past-the-end pointer is not allowed in a constant expression">; +def note_constexpr_access_unsized_array : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "pointer to element of array without known bound " + "is not allowed in a constant expression">; def note_constexpr_access_inactive_union_member : Note< "%select{read of|assignment to|increment of|decrement of}0 " "member %1 of union with %select{active member %3|no active member}2 " @@ -154,6 +158,11 @@ def note_constexpr_baa_insufficient_alignment : Note< def note_constexpr_baa_value_insufficient_alignment : Note< "value of the aligned pointer (%0) is not a multiple of the asserted %1 " "%plural{1:byte|:bytes}1">; +def note_constexpr_unsupported_unsized_array : Note< + "array-to-pointer decay of array member without known bound is not supported">; +def note_constexpr_unsized_array_indexed : Note< + "indexing of array without known bound is not allowed " + "in a constant expression">; def warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td index 98fd3c4d57ac0..82ca27b7345e3 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -185,6 +185,8 @@ def note_invalid_subexpr_in_const_expr : Note< def err_target_unknown_triple : Error< "unknown target triple '%0', please use -triple or -arch">; def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; +def err_target_unsupported_cpu_for_micromips : Error< + "micromips is not supported for target CPU '%0'">; def err_target_unknown_abi : Error<"unknown target ABI '%0'">; def err_target_unsupported_abi : Error<"ABI '%0' is not supported on CPU '%1'">; def err_target_unsupported_abi_for_triple : Error< diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCrossTUKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCrossTUKinds.td new file mode 100644 index 0000000000000..8b6d8b681445d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCrossTUKinds.td @@ -0,0 +1,18 @@ +//==--- DiagnosticCrossTUKinds.td - Cross Translation Unit diagnostics ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "CrossTU" in { + +def err_fnmap_parsing : Error< + "error parsing index file: '%0' line: %1 'UniqueID filename' format " + "expected">; + +def err_multiple_def_index : Error< + "multiple definitions are found for the same key in index ">; +} diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td index fcef881fa0aef..41b5e42b44322 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -29,9 +29,10 @@ def err_drv_no_cuda_installation : Error< def err_drv_no_cuda_libdevice : Error< "cannot find libdevice for %0. Provide path to different CUDA installation " "via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; -def err_drv_cuda_version_too_low : Error< - "GPU arch %1 requires CUDA version at least %3, but installation at %0 is %2. " - "Use --cuda-path to specify a different CUDA install, or pass " +def err_drv_cuda_version_unsupported : Error< + "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " + "but installation at %3 is %4. Use --cuda-path to specify a different CUDA " + "install, pass a different GPU arch with --cuda-gpu-arch, or pass " "--no-cuda-version-check.">; def err_drv_cuda_nvptx_host : Error<"unsupported use of NVPTX for host compilation.">; def err_drv_invalid_thread_model_for_target : Error< @@ -69,6 +70,10 @@ def err_drv_invalid_Xarch_argument_with_args : Error< "invalid Xarch argument: '%0', options requiring arguments are unsupported">; def err_drv_invalid_Xarch_argument_isdriver : Error< "invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">; +def err_drv_Xopenmp_target_missing_triple : Error< + "cannot deduce implicit triple value for -Xopenmp-target, specify triple using -Xopenmp-target=<triple>">; +def err_drv_invalid_Xopenmp_target_with_args : Error< + "invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">; def err_drv_argument_only_allowed_with : Error< "invalid argument '%0' only allowed with '%1'">; def err_drv_argument_not_allowed_with : Error< @@ -97,6 +102,10 @@ def err_drv_force_crash : Error< "failing because %select{environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set|'-gen-reproducer' is used}0">; def err_drv_invalid_mfloat_abi : Error< "invalid float ABI '%0'">; +def err_drv_invalid_mtp : Error< + "invalid thread pointer reading mode '%0'">; +def err_drv_missing_arg_mtp : Error< + "missing argument to '%0'">; def err_drv_invalid_libcxx_deployment : Error< "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; def err_drv_invalid_argument_to_fdebug_prefix_map : Error< @@ -106,6 +115,10 @@ def err_drv_malformed_sanitizer_blacklist : Error< def err_target_unsupported_arch : Error<"the target architecture '%0' is not supported by the target '%1'">; +def err_cpu_unsupported_isa + : Error<"CPU '%0' does not support '%1' execution mode">; +def err_arch_unsupported_isa + : Error<"Architecture '%0' does not support '%1' execution mode">; def err_drv_I_dash_not_supported : Error< "'%0' not supported, please use -iquote instead">; @@ -231,7 +244,7 @@ def warn_drv_enabling_rtti_with_exceptions : Warning< InGroup<DiagGroup<"rtti-for-exceptions">>; def warn_drv_disabling_vptr_no_rtti_default : Warning< "implicitly disabling vptr sanitizer because rtti wasn't enabled">, - InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>; + InGroup<AutoDisableVptrSanitizer>; def warn_drv_object_size_disabled_O0 : Warning< "the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">, InGroup<InvalidCommandLineArgument>; @@ -251,6 +264,9 @@ def err_analyzer_config_no_value : Error< def err_analyzer_config_multiple_values : Error< "analyzer-config option '%0' should contain only one '='">; +def err_drv_invalid_hvx_length : Error< + "-mhvx-length is not supported without a -mhvx/-mhvx= flag">; + def err_drv_modules_validate_once_requires_timestamp : Error< "option '-fmodules-validate-once-per-build-session' requires " "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">; @@ -277,9 +293,27 @@ def warn_target_unsupported_nan2008 : Warning< def warn_target_unsupported_nanlegacy : Warning< "ignoring '-mnan=legacy' option because the '%0' architecture does not support it">, InGroup<UnsupportedNan>; +def warn_target_unsupported_abslegacy : Warning< + "ignoring '-mabs=legacy' option because the '%0' architecture does not support it">, + InGroup<UnsupportedAbs>; +def warn_target_unsupported_abs2008 : Warning< + "ignoring '-mabs=2008' option because the '%0' architecture does not support it">, + InGroup<UnsupportedAbs>; def warn_target_unsupported_compact_branches : Warning< "ignoring '-mcompact-branches=' option because the '%0' architecture does not" " support it">, InGroup<UnsupportedCB>; +def warn_drv_unsupported_gpopt : Warning< + "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" + " usage of }0-mabicalls">, + InGroup<UnsupportedGPOpt>; +def warn_drv_unsupported_longcalls : Warning< + "ignoring '-mlong-calls' option as it is not currently supported with " + "%select{|the implicit usage of }0-mabicalls">, + InGroup<OptionIgnored>; +def warn_drv_unsupported_abicalls : Warning< + "ignoring '-mabicalls' option as it cannot be used with " + "non position-independent code and the N64 ABI">, + InGroup<OptionIgnored>; def warn_drv_unable_to_find_directory_expected : Warning< "unable to find %0 directory, expected to be in '%1'">, @@ -300,4 +334,12 @@ def warn_drv_msvc_not_found : Warning< "unable to find a Visual Studio installation; " "try running Clang from a developer command prompt">, InGroup<DiagGroup<"msvc-not-found">>; + +def warn_drv_fine_grained_bitfield_accesses_ignored : Warning< + "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">, + InGroup<OptionIgnored>; + +def note_drv_verify_prefix_spelling : Note< + "-verify prefixes must start with a letter and contain only alphanumeric" + " characters, hyphens, and underscores">; } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticError.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticError.h new file mode 100644 index 0000000000000..6b4b073736a8d --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticError.h @@ -0,0 +1,61 @@ +//===--- DiagnosticError.h - Diagnostic payload for llvm::Error -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Error.h" + +namespace clang { + +/// \brief Carries a Clang diagnostic in an llvm::Error. +/// +/// Users should emit the stored diagnostic using the DiagnosticsEngine. +class DiagnosticError : public llvm::ErrorInfo<DiagnosticError> { +public: + DiagnosticError(PartialDiagnosticAt Diag) : Diag(std::move(Diag)) {} + + void log(raw_ostream &OS) const override { OS << "clang diagnostic"; } + + PartialDiagnosticAt &getDiagnostic() { return Diag; } + const PartialDiagnosticAt &getDiagnostic() const { return Diag; } + + /// Creates a new \c DiagnosticError that contains the given diagnostic at + /// the given location. + static llvm::Error create(SourceLocation Loc, PartialDiagnostic Diag) { + return llvm::make_error<DiagnosticError>( + PartialDiagnosticAt(Loc, std::move(Diag))); + } + + /// Extracts and returns the diagnostic payload from the given \c Error if + /// the error is a \c DiagnosticError. Returns none if the given error is not + /// a \c DiagnosticError. + static Optional<PartialDiagnosticAt> take(llvm::Error &Err) { + Optional<PartialDiagnosticAt> Result; + Err = llvm::handleErrors(std::move(Err), [&](DiagnosticError &E) { + Result = std::move(E.getDiagnostic()); + }); + return Result; + } + + static char ID; + +private: + // Users are not expected to use error_code. + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + + PartialDiagnosticAt Diag; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 57c24e9be73a7..392a340a3bb72 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -116,6 +116,8 @@ def err_fe_action_not_available : Error< "action %0 not compiled in">; def err_fe_invalid_alignment : Error< "invalid value '%1' in '%0'; alignment must be a power of 2">; +def err_fe_invalid_wchar_type + : Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">; def warn_fe_serialized_diag_merge_failure : Warning< "unable to merge a subprocess's serialized diagnostics">, diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td index 23e4d4633ae2c..c23183c81ac8b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -27,11 +27,16 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; def GNUAutoType : DiagGroup<"gnu-auto-type">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; +def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">; def Availability : DiagGroup<"availability">; def Section : DiagGroup<"section">; def AutoImport : DiagGroup<"auto-import">; def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">; +def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">; def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">; +def BinaryLiteral : DiagGroup<"binary-literal", [CXX14BinaryLiteral, + CXXPre14CompatBinaryLiteral, + GNUBinaryLiteral]>; def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">; def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">; @@ -60,7 +65,9 @@ def FloatConversion : def DoublePromotion : DiagGroup<"double-promotion">; def EnumTooLarge : DiagGroup<"enum-too-large">; def UnsupportedNan : DiagGroup<"unsupported-nan">; +def UnsupportedAbs : DiagGroup<"unsupported-abs">; def UnsupportedCB : DiagGroup<"unsupported-cb">; +def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">; def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; def NullConversion : DiagGroup<"null-conversion">; def ImplicitConversionFloatingPointToBool : @@ -87,6 +94,7 @@ def GNUStringLiteralOperatorTemplate : DiagGroup<"gnu-string-literal-operator-template">; def UndefinedVarTemplate : DiagGroup<"undefined-var-template">; def UndefinedFuncTemplate : DiagGroup<"undefined-func-template">; +def MissingNoEscape : DiagGroup<"missing-noescape">; def DeleteIncomplete : DiagGroup<"delete-incomplete">; def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; @@ -162,10 +170,14 @@ def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>; // Warnings for C++1y code which is not compatible with prior C++ standards. def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", - [CXXPre14Compat]>; -def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; -def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", - [CXXPre1zCompat]>; + [CXXPre14Compat, + CXXPre14CompatBinaryLiteral]>; +def CXXPre17Compat : DiagGroup<"c++98-c++11-c++14-compat">; +def CXXPre17CompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", + [CXXPre17Compat]>; +def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">; +def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", + [CXXPre2aCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -178,13 +190,15 @@ def CXX98Compat : DiagGroup<"c++98-compat", [CXX98CompatLocalTypeTemplateArgs, CXX98CompatUnnamedTypeTemplateArgs, CXXPre14Compat, - CXXPre1zCompat]>; + CXXPre17Compat, + CXXPre2aCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, CXX98CompatBindToTemporaryCopy, CXXPre14CompatPedantic, - CXXPre1zCompatPedantic]>; + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; @@ -209,21 +223,35 @@ def CXX11Compat : DiagGroup<"c++11-compat", CXX11CompatReservedUserDefinedLiteral, CXX11CompatDeprecatedWritableStr, CXXPre14Compat, - CXXPre1zCompat]>; + CXXPre17Compat, + CXXPre2aCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", - [CXXPre14CompatPedantic, - CXXPre1zCompatPedantic]>; + [CXX11Compat, + CXXPre14CompatPedantic, + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; -def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; +def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre17Compat, + CXXPre2aCompat]>; def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", - [CXXPre1zCompatPedantic]>; + [CXX14Compat, + CXXPre17CompatPedantic, + CXXPre2aCompatPedantic]>; def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister, DeprecatedIncrementBool, - CXX17CompatMangling]>; + CXX17CompatMangling, + CXXPre2aCompat]>; +def CXX17CompatPedantic : DiagGroup<"c++17-compat-pedantic", + [CXX17Compat, + CXXPre2aCompatPedantic]>; def : DiagGroup<"c++1z-compat", [CXX17Compat]>; +def CXX2aCompat : DiagGroup<"c++2a-compat">; +def CXX2aCompatPedantic : DiagGroup<"c++2a-compat-pedantic", + [CXX2aCompat]>; + def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; def FourByteMultiChar : DiagGroup<"four-char-constants">; @@ -316,6 +344,7 @@ def NonPODVarargs : DiagGroup<"non-pod-varargs">; def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>; def : DiagGroup<"nonportable-cfstrings">; def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; +def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">; def : DiagGroup<"effc++", [NonVirtualDtor]>; def OveralignedType : DiagGroup<"over-aligned">; def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">; @@ -345,6 +374,7 @@ def ObjCRootClass : DiagGroup<"objc-root-class">; def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">; def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; +def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; @@ -405,12 +435,18 @@ def StringCompare : DiagGroup<"string-compare">; def StringPlusInt : DiagGroup<"string-plus-int">; def StringPlusChar : DiagGroup<"string-plus-char">; def StrncatSize : DiagGroup<"strncat-size">; +def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">; +def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">; def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; +def TautologicalConstantCompare : DiagGroup<"tautological-constant-compare", + [TautologicalUnsignedZeroCompare, + TautologicalUnsignedEnumZeroCompare, + TautologicalOutOfRangeCompare]>; def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">; def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">; def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">; def TautologicalCompare : DiagGroup<"tautological-compare", - [TautologicalOutOfRangeCompare, + [TautologicalConstantCompare, TautologicalPointerCompare, TautologicalOverlapCompare, TautologicalUndefinedCompare]>; @@ -454,6 +490,8 @@ def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; def SwitchBool : DiagGroup<"switch-bool">; def SwitchEnum : DiagGroup<"switch-enum">; def Switch : DiagGroup<"switch">; +def EnumCompareSwitch : DiagGroup<"enum-compare-switch">; +def EnumCompare : DiagGroup<"enum-compare", [EnumCompareSwitch]>; def ImplicitFallthroughPerFunction : DiagGroup<"implicit-fallthrough-per-function">; def ImplicitFallthrough : DiagGroup<"implicit-fallthrough", @@ -474,10 +512,15 @@ def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">; def UnknownPragmas : DiagGroup<"unknown-pragmas">; def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>; def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">; +def PragmaPackSuspiciousInclude : DiagGroup<"pragma-pack-suspicious-include">; +def PragmaPack : DiagGroup<"pragma-pack", [PragmaPackSuspiciousInclude]>; def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas, - PragmaClangAttribute]>; + PragmaClangAttribute, PragmaPack]>; def UnknownWarningOption : DiagGroup<"unknown-warning-option">; def NSobjectAttribute : DiagGroup<"NSObject-attribute">; +def NSConsumedMismatch : DiagGroup<"nsconsumed-mismatch">; +def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">; + def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">; def UnknownAttributes : DiagGroup<"unknown-attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; @@ -678,7 +721,8 @@ def Extra : DiagGroup<"extra", [ SemiBeforeMethodBody, MissingMethodReturnType, SignCompare, - UnusedParameter + UnusedParameter, + NullPointerArithmetic ]>; def Most : DiagGroup<"most", [ @@ -707,6 +751,7 @@ def Most : DiagGroup<"most", [ VolatileRegisterVar, ObjCMissingSuperCalls, ObjCDesignatedInit, + ObjCFlexibleArray, OverloadedVirtual, PrivateExtern, SelTypeCast, @@ -772,10 +817,14 @@ def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11InlineNamespace, // earlier C++ versions. def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>; -// A warning group for warnings about using C++1z features as extensions in +// A warning group for warnings about using C++17 features as extensions in // earlier C++ versions. def CXX17 : DiagGroup<"c++17-extensions">; +// A warning group for warnings about using C++2a features as extensions in +// earlier C++ versions. +def CXX2a : DiagGroup<"c++2a-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; def : DiagGroup<"c++1z-extensions", [CXX17]>; @@ -841,6 +890,7 @@ def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">; def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">; def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">; def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">; +def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; // -Wmsvc-include = -Wmicrosoft-include diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h index cdd358542a0d3..43183a120bb9a 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h @@ -26,19 +26,36 @@ namespace clang { // Import the diagnostic enums themselves. namespace diag { + // Size of each of the diagnostic categories. + enum { + DIAG_SIZE_COMMON = 300, + DIAG_SIZE_DRIVER = 200, + DIAG_SIZE_FRONTEND = 100, + DIAG_SIZE_SERIALIZATION = 120, + DIAG_SIZE_LEX = 400, + DIAG_SIZE_PARSE = 500, + DIAG_SIZE_AST = 150, + DIAG_SIZE_COMMENT = 100, + DIAG_SIZE_CROSSTU = 100, + DIAG_SIZE_SEMA = 3500, + DIAG_SIZE_ANALYSIS = 100, + DIAG_SIZE_REFACTORING = 1000, + }; // Start position for diagnostics. enum { - DIAG_START_COMMON = 0, - DIAG_START_DRIVER = DIAG_START_COMMON + 300, - DIAG_START_FRONTEND = DIAG_START_DRIVER + 200, - DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100, - DIAG_START_LEX = DIAG_START_SERIALIZATION + 120, - DIAG_START_PARSE = DIAG_START_LEX + 400, - DIAG_START_AST = DIAG_START_PARSE + 500, - DIAG_START_COMMENT = DIAG_START_AST + 110, - DIAG_START_SEMA = DIAG_START_COMMENT + 100, - DIAG_START_ANALYSIS = DIAG_START_SEMA + 3500, - DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 + DIAG_START_COMMON = 0, + DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON, + DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER, + DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND, + DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION, + DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX, + DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE, + DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST, + DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_CROSSTU, + DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_COMMENT, + DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA, + DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS, + DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING }; class CustomDiagInfo; @@ -279,8 +296,8 @@ public: SmallVectorImpl<diag::kind> &Diags) const; /// \brief Get the set of all diagnostic IDs. - void getAllDiagnostics(diag::Flavor Flavor, - SmallVectorImpl<diag::kind> &Diags) const; + static void getAllDiagnostics(diag::Flavor Flavor, + SmallVectorImpl<diag::kind> &Diags); /// \brief Get the diagnostic option with the closest edit distance to the /// given group name. diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td index 706881bfdc5d7..c664281ffcd48 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -31,6 +31,14 @@ def warn_cxx98_compat_less_colon_colon : Warning< "'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx17_compat_spaceship : Warning< + "'<=>' operator is incompatible with C++ standards before C++2a">, + InGroup<CXXPre2aCompat>, DefaultIgnore; +def warn_cxx2a_compat_spaceship : Warning< + "'<=>' is a single token in C++2a; " + "add a space to avoid a change in behavior">, + InGroup<CXX2aCompat>; + // Trigraphs. def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>; def trigraph_ignored_block_comment : Warning< @@ -71,6 +79,8 @@ def ext_token_used : Extension<"extension used">, def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">, InGroup<CXX11Compat>, DefaultIgnore; +def warn_cxx2a_keyword : Warning<"'%0' is a keyword in C++2a">, + InGroup<CXX2aCompat>, DefaultIgnore; def ext_unterminated_char_or_string : ExtWarn< "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>; @@ -109,6 +119,9 @@ def err_non_ascii : Error< def ext_unicode_whitespace : ExtWarn< "treating Unicode character as whitespace">, InGroup<DiagGroup<"unicode-whitespace">>; +def warn_utf8_symbol_homoglyph : Warning< + "treating Unicode character <U+%0> as identifier character rather than " + "as '%1' symbol">, InGroup<DiagGroup<"unicode-homoglyph">>; def err_hex_escape_no_digits : Error< "\\%0 used with no following hex digits">; @@ -173,8 +186,6 @@ def warn_char_constant_too_large : Warning< def err_multichar_utf_character_literal : Error< "Unicode character literals may not contain multiple characters">; def err_exponent_has_no_digits : Error<"exponent has no digits">; -def ext_imaginary_constant : Extension< - "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def err_hex_constant_requires : Error< "hexadecimal floating %select{constant|literal}0 requires " "%select{an exponent|a significand}1">; @@ -182,17 +193,17 @@ def ext_hex_constant_invalid : Extension< "hexadecimal floating constants are a C99 feature">, InGroup<C99>; def ext_hex_literal_invalid : Extension< "hexadecimal floating literals are a C++17 feature">, InGroup<CXX17>; -def warn_cxx1z_hex_literal : Warning< +def warn_cxx17_hex_literal : Warning< "hexadecimal floating literals are incompatible with " "C++ standards before C++17">, - InGroup<CXXPre1zCompatPedantic>, DefaultIgnore; + InGroup<CXXPre17CompatPedantic>, DefaultIgnore; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>; def ext_binary_literal_cxx14 : Extension< "binary integer literals are a C++14 extension">, InGroup<CXX14BinaryLiteral>; def warn_cxx11_compat_binary_literal : Warning< "binary integer literals are incompatible with C++ standards before C++14">, - InGroup<CXXPre14CompatPedantic>, DefaultIgnore; + InGroup<CXXPre14CompatBinaryLiteral>, DefaultIgnore; def err_pascal_string_too_long : Error<"Pascal string is too long">; def err_escape_too_large : Error< "%select{hex|octal}0 escape sequence out of range">; @@ -209,7 +220,7 @@ def warn_cxx98_compat_unicode_literal : Warning< InGroup<CXX98Compat>, DefaultIgnore; def warn_cxx14_compat_u8_character_literal : Warning< "unicode literals are incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17Compat>, DefaultIgnore; def warn_cxx11_compat_user_defined_literal : Warning< "identifier after literal will be treated as a user-defined literal suffix " "in C++11">, InGroup<CXX11Compat>, DefaultIgnore; @@ -346,6 +357,23 @@ def ext_pp_extra_tokens_at_eol : ExtWarn< def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; def ext_pp_bad_vaargs_use : Extension< "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; + +def ext_pp_bad_vaopt_use + : ExtWarn< + "__VA_OPT__ can only appear in the expansion of a variadic macro">, + InGroup<VariadicMacros>; + +def err_pp_missing_lparen_in_vaopt_use : Error< + "missing '(' following __VA_OPT__">; +def err_pp_vaopt_nested_use : Error< + "__VA_OPT__ cannot be nested within its own replacement tokens">; + +def err_vaopt_paste_at_start : Error< + "'##' cannot appear at start of __VA_OPT__ argument">; + +def err_vaopt_paste_at_end + : Error<"'##' cannot appear at end of __VA_OPT__ argument">; + def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">, InGroup<MacroRedefined>; def ext_variadic_macro : Extension<"variadic macros are a C99 feature">, InGroup<VariadicMacros>; @@ -674,6 +702,13 @@ def err_mmap_invalid_header_attribute_value : Error< "expected integer literal as value for header attribute '%0'">; def err_mmap_expected_header_attribute : Error< "expected a header attribute name ('size' or 'mtime')">; +def err_mmap_conflicting_export_as : Error< + "conflicting re-export of module '%0' as '%1' or '%2'">; +def warn_mmap_redundant_export_as : Warning< + "module '%0' already re-exported as '%1'">, + InGroup<PrivateModule>; +def err_mmap_submodule_export_as : Error< + "only top-level modules can be re-exported as public">; def warn_auto_module_import : Warning< "treating #%select{include|import|include_next|__include_macros}0 as an " diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h index c195003de5c45..3844eb63f0eaf 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h @@ -100,6 +100,10 @@ public: /// prefixes removed. std::vector<std::string> Remarks; + /// The prefixes for comment directives sought by -verify ("expected" by + /// default). + std::vector<std::string> VerifyPrefixes; + public: // Define accessors/mutators for diagnostic options of enumeration type. #define DIAGOPT(Name, Bits, Default) diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td index 5170c07bf6668..a8d6955da3c09 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -215,7 +215,7 @@ def ext_nested_namespace_definition : ExtWarn< "define each namespace separately">, InGroup<CXX17>; def warn_cxx14_compat_nested_namespace_definition : Warning< "nested namespace definition is incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17Compat>, DefaultIgnore; def err_inline_nested_namespace_definition : Error< "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< @@ -525,13 +525,13 @@ def ext_constexpr_if : ExtWarn< "constexpr if is a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_constexpr_if : Warning< "constexpr if is incompatible with C++ standards before C++17">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + DefaultIgnore, InGroup<CXXPre17Compat>; def ext_init_statement : ExtWarn< "'%select{if|switch}0' initialization statements are a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_init_statement : Warning< "%select{if|switch}0 initialization statements are incompatible with " - "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre1zCompat>; + "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; @@ -558,10 +558,13 @@ def warn_cxx98_compat_noexcept_expr : Warning< def warn_cxx98_compat_nullptr : Warning< "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def warn_cxx14_compat_attribute : Warning< +def ext_ns_enum_attribute : Extension< + "attributes on %select{a namespace|an enumerator}0 declaration are " + "a C++17 extension">, InGroup<CXX17>; +def warn_cxx14_compat_ns_enum_attribute : Warning< "attributes on %select{a namespace|an enumerator}0 declaration are " "incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17CompatPedantic>, DefaultIgnore; def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def warn_cxx98_compat_attribute : Warning< @@ -577,7 +580,7 @@ def err_cxx11_attribute_repeated : Error< "attribute %0 cannot appear multiple times in an attribute specifier">; def warn_cxx14_compat_using_attribute_ns : Warning< "default scope specifier for attributes is incompatible with C++ standards " - "before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; def ext_using_attribute_ns : ExtWarn< "default scope specifier for attributes is a C++17 extension">, InGroup<CXX17>; @@ -622,7 +625,7 @@ def ext_template_template_param_typename : ExtWarn< def warn_cxx14_compat_template_template_param_typename : Warning< "template template parameter using 'typename' is " "incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17Compat>, DefaultIgnore; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function template|" @@ -699,7 +702,7 @@ def ext_fold_expression : ExtWarn< InGroup<CXX17>; def warn_cxx14_compat_fold_expression : Warning< "pack fold expression is incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17Compat>, DefaultIgnore; def err_expected_fold_operator : Error< "expected a foldable binary operator in fold expression">; def err_fold_operator_mismatch : Error< @@ -730,8 +733,12 @@ def ext_nonstatic_member_init : ExtWarn< def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def err_bitfield_member_init: Error< - "bit-field member cannot have an in-class initializer">; +def ext_bitfield_member_init: ExtWarn< + "default member initializer for bit-field is a C++2a extension">, + InGroup<CXX2a>; +def warn_cxx17_compat_bitfield_member_init: Warning< + "default member initializer for bit-field is incompatible with " + "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; @@ -748,19 +755,19 @@ def err_alias_declaration_specialization : Error< def err_alias_declaration_pack_expansion : Error< "alias declaration cannot be a pack expansion">; -// C++1z using-declaration pack expansions +// C++17 using-declaration pack expansions def ext_multi_using_declaration : ExtWarn< "use of multiple declarators in a single using declaration is " "a C++17 extension">, InGroup<CXX17>; -def warn_cxx1z_compat_multi_using_declaration : Warning< +def warn_cxx17_compat_multi_using_declaration : Warning< "use of multiple declarators in a single using declaration is " "incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; + InGroup<CXXPre17Compat>, DefaultIgnore; def ext_using_declaration_pack : ExtWarn< "pack expansion of using declaration is a C++17 extension">, InGroup<CXX17>; -def warn_cxx1z_compat_using_declaration_pack : Warning< +def warn_cxx17_compat_using_declaration_pack : Warning< "pack expansion using declaration is incompatible with C++ standards " - "before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; // C++11 override control def ext_override_control_keyword : ExtWarn< @@ -811,15 +818,15 @@ def err_lambda_missing_parens : Error< "attribute specifier|'constexpr'}0">; def err_lambda_decl_specifier_repeated : Error< "%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">; -// C++1z lambda expressions +// C++17 lambda expressions def err_expected_star_this_capture : Error< "expected 'this' following '*' in lambda capture list">; -// C++1z constexpr lambda expressions +// C++17 constexpr lambda expressions def warn_cxx14_compat_constexpr_on_lambda : Warning< "constexpr on lambda expressions is incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; -def ext_constexpr_on_lambda_cxx1z : ExtWarn< + InGroup<CXXPre17Compat>, DefaultIgnore; +def ext_constexpr_on_lambda_cxx17 : ExtWarn< "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>; // Availability attribute @@ -893,8 +900,6 @@ def err_pragma_expected_clang_section_name : Error< "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">; def err_pragma_clang_section_expected_equal : Error< "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; -def err_pragma_clang_section_expected_name_or_clear : Error< - "expected section name or '\"\"' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticRefactoringKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticRefactoringKinds.td new file mode 100644 index 0000000000000..ee396b9307299 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticRefactoringKinds.td @@ -0,0 +1,34 @@ +//==--- DiagnosticRefactoringKinds.td - refactoring diagnostics -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Refactoring Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Refactoring" in { + +let CategoryName = "Refactoring Invocation Issue" in { + +def err_refactor_no_selection : Error<"refactoring action can't be initiated " + "without a selection">; +def err_refactor_selection_no_symbol : Error<"there is no symbol at the given " + "location">; +def err_refactor_selection_invalid_ast : Error<"the provided selection does " + "not overlap with the AST nodes of interest">; + +def err_refactor_code_outside_of_function : Error<"the selected code is not a " + "part of a function's / method's body">; +def err_refactor_extract_simple_expression : Error<"the selected expression " + "is too simple to extract">; +def err_refactor_extract_prohibited_expression : Error<"the selected " + "expression can't be extracted">; + +} + +} // end of Refactoring diagnostics diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8dc6e7b460e86..29236eab5446c 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -141,6 +141,10 @@ def err_vla_decl_has_extern_linkage : Error< "variable length array declaration cannot have 'extern' linkage">; def ext_vla_folded_to_constant : Extension< "variable length array folded to constant array as an extension">, InGroup<GNUFoldingConstant>; +def err_vla_unsupported : Error< + "variable length arrays are not supported for the current target">; +def note_vla_unsupported : Note< + "variable length arrays are not supported for the current target">; // C99 variably modified types def err_variably_modified_template_arg : Error< @@ -194,6 +198,8 @@ def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, InGroup<DuplicateDeclSpecifier>; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_imaginary_constant : Extension< + "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>; @@ -293,8 +299,20 @@ def warn_empty_parens_are_function_decl : Warning< def warn_parens_disambiguated_as_function_declaration : Warning< "parentheses were disambiguated as a function declaration">, InGroup<VexingParse>; +def warn_parens_disambiguated_as_variable_declaration : Warning< + "parentheses were disambiguated as redundant parentheses around declaration " + "of variable named %0">, InGroup<VexingParse>; +def warn_redundant_parens_around_declarator : Warning< + "redundant parentheses surrounding declarator">, + InGroup<DiagGroup<"redundant-parens">>, DefaultIgnore; def note_additional_parens_for_variable_declaration : Note< "add a pair of parentheses to declare a variable">; +def note_raii_guard_add_name : Note< + "add a variable name to declare a %0 initialized with %1">; +def note_function_style_cast_add_parentheses : Note< + "add enclosing parentheses to perform a function-style cast">; +def note_remove_parens_for_variable_declaration : Note< + "remove parentheses to silence this warning">; def note_empty_parens_function_call : Note< "change this ',' to a ';' to call %0">; def note_empty_parens_default_ctor : Note< @@ -341,7 +359,7 @@ def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup<ImplicitFunctionDeclare>, DefaultIgnore; def ext_implicit_function_decl : ExtWarn< - "implicit declaration of function %0 is invalid in C99">, + "implicit declaration of function %0 is invalid in %select{C99|OpenCL}1">, InGroup<ImplicitFunctionDeclare>; def note_function_suggestion : Note<"did you mean %0?">; @@ -352,8 +370,10 @@ def err_language_linkage_spec_unknown : Error<"unknown linkage language">; def err_language_linkage_spec_not_ascii : Error< "string literal in language linkage specifier cannot have an " "encoding-prefix">; -def warn_use_out_of_scope_declaration : Warning< - "use of out-of-scope declaration of %0">; +def ext_use_out_of_scope_declaration : ExtWarn< + "use of out-of-scope declaration of %0%select{| whose type is not " + "compatible with that of an implicit declaration}1">, + InGroup<DiagGroup<"out-of-scope-function">>; def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< @@ -391,9 +411,12 @@ def err_decomp_decl_context : Error< "decomposition declaration not permitted in this context">; def warn_cxx14_compat_decomp_decl : Warning< "decomposition declarations are incompatible with " - "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre1zCompat>; + "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>; def ext_decomp_decl : ExtWarn< "decomposition declarations are a C++17 extension">, InGroup<CXX17>; +def ext_decomp_decl_cond : ExtWarn< + "ISO C++17 does not permit structured binding declaration in a condition">, + InGroup<DiagGroup<"binding-in-condition">>; def err_decomp_decl_spec : Error< "decomposition declaration cannot be declared " "%plural{1:'%1'|:with '%1' specifiers}0">; @@ -505,7 +528,7 @@ def warn_deprecated_copy_operation : Warning< "for %0 is deprecated because it has a user-declared " "%select{copy %select{assignment operator|constructor}1|destructor}2">, InGroup<Deprecated>, DefaultIgnore; -def warn_cxx1z_compat_exception_spec_in_signature : Warning< +def warn_cxx17_compat_exception_spec_in_signature : Warning< "mangled name of %0 will change in C++17 due to non-throwing exception " "specification in function signature">, InGroup<CXX17CompatMangling>; @@ -581,6 +604,7 @@ def warn_redecl_library_builtin : Warning< def err_builtin_definition : Error<"definition of builtin function %0">; def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; +def err_invalid_cpu_is : Error<"invalid cpu name for builtin">; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; def err_function_needs_feature : Error<"always_inline function %1 requires target feature '%2', but would " @@ -712,6 +736,19 @@ def err_pragma_options_align_mac68k_target_unsupported : Error< def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, InGroup<IgnoredPragmas>; +def warn_pragma_pack_non_default_at_include : Warning< + "non-default #pragma pack value changes the alignment of struct or union " + "members in the included file">, InGroup<PragmaPackSuspiciousInclude>, + DefaultIgnore; +def warn_pragma_pack_modified_after_include : Warning< + "the current #pragma pack aligment value is modified in the included " + "file">, InGroup<PragmaPack>; +def warn_pragma_pack_no_pop_eof : Warning<"unterminated " + "'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>; +def note_pragma_pack_here : Note< + "previous '#pragma pack' directive that modifies alignment is here">; +def note_pragma_pack_pop_instead_reset : Note< + "did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?">; // Follow the Microsoft implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; def warn_pragma_pack_pop_identifer_and_alignment : Warning< @@ -1195,21 +1232,27 @@ def err_objc_method_unsupported_param_ret_type : Error< "%0 %select{parameter|return}1 type is unsupported; " "support for vector types for this target is introduced in %2">; +def warn_messaging_unqualified_id : Warning< + "messaging unqualified id">, DefaultIgnore, + InGroup<DiagGroup<"objc-messaging-id">>; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; +def err_static_assert_requirement_failed : Error< + "static_assert failed due to requirement '%0'%select{ %2|}1">; def ext_static_assert_no_message : ExtWarn< "static_assert with no message is a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_static_assert_no_message : Warning< "static_assert with no message is incompatible with C++ standards before C++17">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + DefaultIgnore, InGroup<CXXPre17Compat>; def ext_inline_variable : ExtWarn< "inline variables are a C++17 extension">, InGroup<CXX17>; def warn_cxx14_compat_inline_variable : Warning< "inline variables are incompatible with C++ standards before C++17">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + DefaultIgnore, InGroup<CXXPre17Compat>; def warn_inline_namespace_reopened_noninline : Warning< "inline namespace reopened as a non-inline namespace">; @@ -1313,6 +1356,8 @@ def err_type_defined_in_alias_template : Error< "%0 cannot be defined in a type alias template">; def err_type_defined_in_condition : Error< "%0 cannot be defined in a condition">; +def err_type_defined_in_enum : Error< + "%0 cannot be defined in an enumeration">; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; @@ -1637,6 +1682,11 @@ def err_conflicting_overriding_cc_attributes : Error< "virtual function %0 has different calling convention attributes " "%diff{($) than the function it overrides (which has calling convention $)|" "than the function it overrides}1,2">; +def warn_overriding_method_missing_noescape : Warning< + "parameter of overriding method should be annotated with " + "__attribute__((noescape))">, InGroup<MissingNoEscape>; +def note_overridden_marked_noescape : Note< + "parameter of overridden method is annotated with __attribute__((noescape))">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " @@ -1938,8 +1988,9 @@ def err_auto_var_requires_init : Error< "declaration of variable %0 with deduced type %1 requires an initializer">; def err_auto_new_requires_ctor_arg : Error< "new expression for type %0 requires a constructor argument">; -def err_auto_new_list_init : Error< - "new expression for type %0 cannot use list-initialization">; +def ext_auto_new_list_init : Extension< + "ISO C++ standards before C++17 do not allow new expression for " + "type %0 to use list-initialization">, InGroup<CXX17>; def err_auto_var_init_no_expression : Error< "initializer for variable %0 with type %1 is empty">; def err_auto_var_init_multiple_expressions : Error< @@ -1964,6 +2015,9 @@ def err_auto_var_deduction_failure_from_init_list : Error< "cannot deduce actual type for variable %0 with type %1 from initializer list">; def err_auto_new_deduction_failure : Error< "new expression for type %0 has incompatible constructor argument of type %1">; +def err_auto_inconsistent_deduction : Error< + "deduced conflicting types %diff{($ vs $) |}0,1" + "for initializer list element type">; def err_auto_different_deductions : Error< "%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 " "deduced as %1 in declaration of %2 and " @@ -1999,7 +2053,7 @@ def err_decltype_auto_compound_type : Error< def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; -// C++1z deduced class template specialization types +// C++17 deduced class template specialization types def err_deduced_class_template_compound_type : Error< "cannot %select{form pointer to|form reference to|form array of|" "form function returning|use parentheses when declaring variable with}0 " @@ -2151,7 +2205,7 @@ def ext_for_range_begin_end_types_differ : ExtWarn< InGroup<CXX17>; def warn_for_range_begin_end_types_differ : Warning< "'begin' and 'end' returning different types (%0 and %1) is incompatible " - "with C++ standards before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore; + "with C++ standards before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore; def note_in_for_range: Note< "when looking up '%select{begin|end}0' function for range expression " "of type %1">; @@ -2387,8 +2441,9 @@ def err_attribute_requires_positive_integer : Error< def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; def warn_unsupported_target_attribute - : Warning<"Ignoring unsupported '%0' in the target attribute string">, - InGroup<IgnoredAttributes>; + : Warning<"ignoring %select{unsupported|duplicate}0" + "%select{| architecture}1 '%2' in the target attribute string">, + InGroup<IgnoredAttributes>; def err_attribute_unsupported : Error<"%0 attribute is not supported for this target">; // The err_*_attribute_argument_not_int are separate because they're used by @@ -2587,6 +2642,8 @@ def err_attribute_section_invalid_for_target : Error< "argument to 'section' attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup<Section>; +def warn_attribute_section_on_redeclaration : Warning< + "section attribute is specified on redeclared variable">, InGroup<Section>; def err_anonymous_property: Error< "anonymous property is not supported">; @@ -2729,7 +2786,7 @@ def err_attribute_weakref_not_global_context : Error< def err_attribute_weakref_without_alias : Error< "weakref declaration of %0 must also have an alias attribute">; def err_alias_not_supported_on_darwin : Error < - "only weak aliases are supported on darwin">; + "aliases are not supported on darwin">; def err_alias_to_undefined : Error< "%select{alias|ifunc}0 must point to a defined %select{variable or |}1function">; def warn_alias_to_weak_alias : Warning< @@ -2746,55 +2803,26 @@ def err_ifunc_resolver_return : Error< "ifunc resolver function must return a pointer">; def err_ifunc_resolver_params : Error< "ifunc resolver function must have no parameters">; +def warn_attribute_wrong_decl_type_str : Warning< + "%0 attribute only applies to %1">, InGroup<IgnoredAttributes>; +def err_attribute_wrong_decl_type_str : Error< + warn_attribute_wrong_decl_type_str.Text>; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{" "functions" "|unions" "|variables and functions" - "|functions and global variables" - "|functions, variables, and Objective-C interfaces" "|functions and methods" - "|parameters" "|functions, methods and blocks" - "|functions, methods, and classes" "|functions, methods, and parameters" - "|functions, methods, and global variables" - "|classes" - "|enums" "|variables" - "|methods" - "|fields and global variables" - "|structs" - "|parameters and typedefs" - "|variables and typedefs" - "|thread-local variables" "|variables and fields" "|variables, data members and tag types" "|types and namespaces" - "|Objective-C interfaces" - "|methods and properties" - "|functions, methods, and properties" - "|struct or union" - "|struct, union or class" - "|types" - "|Objective-C instance methods" - "|init methods of interface or class extension declarations" "|variables, functions and classes" - "|functions, variables, classes, and Objective-C interfaces" - "|Objective-C protocols" - "|variables with static or thread storage duration" - "|functions, methods, properties, and global variables" - "|structs, unions, and typedefs" - "|structs and typedefs" - "|interface or protocol declarations" "|kernel functions" "|non-K&R-style functions" - "|variables, enums, fields and typedefs" - "|functions, methods, enums, and classes" - "|structs, classes, variables, functions, and inline namespaces" - "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members" - "|classes and enumerations" - "|named declarations}1">, + "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">, InGroup<IgnoredAttributes>; def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>; def warn_type_attribute_wrong_type : Warning< @@ -2879,25 +2907,11 @@ def warn_unguarded_availability : def warn_unguarded_availability_new : Warning<warn_unguarded_availability.Text>, InGroup<UnguardedAvailabilityNew>; -def warn_partial_availability : Warning<"%0 is only available conditionally">, - InGroup<UnguardedAvailability>, DefaultIgnore; -def warn_partial_availability_new : Warning<warn_partial_availability.Text>, - InGroup<UnguardedAvailabilityNew>; -def note_partial_availability_silence : Note< - "annotate %select{%1|anonymous %1}0 with an availability attribute to silence">; +def note_decl_unguarded_availability_silence : Note< + "annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">; def note_unguarded_available_silence : Note< "enclose %0 in %select{an @available|a __builtin_available}1 check to silence" " this warning">; -def warn_partial_message : Warning<"%0 is partial: %1">, - InGroup<UnguardedAvailability>, DefaultIgnore; -def warn_partial_message_new : Warning<warn_partial_message.Text>, - InGroup<UnguardedAvailabilityNew>; -def warn_partial_fwdclass_message : Warning< - "%0 may be partial because the receiver type is unknown">, - InGroup<UnguardedAvailability>, DefaultIgnore; -def warn_partial_fwdclass_message_new : - Warning<warn_partial_fwdclass_message.Text>, - InGroup<UnguardedAvailabilityNew>; def warn_at_available_unchecked_use : Warning< "%select{@available|__builtin_available}0 does not guard availability here; " "use if (%select{@available|__builtin_available}0) instead">, @@ -3063,6 +3077,8 @@ def warn_impcast_vector_scalar : Warning< def warn_impcast_complex_scalar : Warning< "implicit conversion discards imaginary component: %0 to %1">, InGroup<Conversion>, DefaultIgnore; +def err_impcast_complex_scalar : Error< + "implicit conversion from %0 to %1 is not permitted in C++">; def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup<Conversion>, DefaultIgnore; @@ -3188,6 +3204,9 @@ def warn_int_to_void_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup<IntToVoidPointerCast>; +def warn_attribute_ignored_for_field_of_type : Warning< + "%0 attribute ignored for field of type %1">, + InGroup<IgnoredAttributes>; def warn_no_underlying_type_specified_for_enum_bitfield : Warning< "enums in the Microsoft ABI are signed integers by default; consider giving " "the enum %0 an unsigned underlying type to make this code portable">, @@ -3906,7 +3925,7 @@ def err_template_nontype_parm_bad_type : Error< def warn_cxx14_compat_template_nontype_parm_auto_type : Warning< "non-type template parameters declared with %0 are incompatible with C++ " "standards before C++17">, - DefaultIgnore, InGroup<CXXPre1zCompat>; + DefaultIgnore, InGroup<CXXPre17Compat>; def err_template_param_default_arg_redefinition : Error< "template parameter redefines default argument">; def note_template_param_prev_default_arg : Note< @@ -4080,6 +4099,13 @@ def err_pointer_to_member_call_drops_quals : Error< def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; +def ext_pointer_to_const_ref_member_on_rvalue : Extension< + "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">, + InGroup<CXX2a>, SFINAEFailure; +def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning< + "invoking a pointer to a 'const &' member function on an rvalue is " + "incompatible with C++ standards before C++2a">, + InGroup<CXXPre2aCompatPedantic>, DefaultIgnore; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup<MicrosoftTemplate>; @@ -4681,6 +4707,14 @@ def note_deleted_assign_field : Note< def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, InGroup<DiagGroup<"undefined-internal">>; +def err_undefined_internal_type : Error< + "%select{function|variable}0 %q1 is used but not defined in this " + "translation unit, and cannot be defined in any other translation unit " + "because its type does not have linkage">; +def ext_undefined_internal_type : Extension< + "ISO C++ requires a definition in this translation unit for " + "%select{function|variable}0 %q1 because its type does not have linkage">, + InGroup<DiagGroup<"undefined-internal-type">>; def warn_undefined_inline : Warning<"inline function %q0 is not defined">, InGroup<DiagGroup<"undefined-inline">>; def err_undefined_inline_var : Error<"inline variable %q0 is not defined">; @@ -4746,6 +4780,9 @@ def err_thread_non_thread : Error< def err_thread_thread_different_kind : Error< "thread-local declaration of %0 with %select{static|dynamic}1 initialization " "follows declaration with %select{dynamic|static}1 initialization">; +def err_mismatched_owning_module : Error< + "declaration of %0 in %select{the global module|module %2}1 follows " + "declaration in %select{the global module|module %4}3">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< @@ -5164,6 +5201,28 @@ def ext_flexible_array_empty_aggregate_gnu : Extension< def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>; +def err_flexible_array_not_at_end : Error< + "flexible array member %0 with type %1 is not at the end of" + " %select{struct|interface|union|class|enum}2">; +def err_objc_variable_sized_type_not_at_end : Error< + "field %0 with variable sized type %1 is not at the end of class">; +def note_next_field_declaration : Note< + "next field declaration is here">; +def note_next_ivar_declaration : Note< + "next %select{instance variable declaration|synthesized instance variable}0" + " is here">; +def err_synthesize_variable_sized_ivar : Error< + "synthesized property with variable size type %0" + " requires an existing instance variable">; +def err_flexible_array_arc_retainable : Error< + "ARC forbids flexible array members with retainable object type">; +def warn_variable_sized_ivar_visibility : Warning< + "field %0 with variable sized type %1 is not visible to subclasses and" + " can conflict with their instance variables">, InGroup<ObjCFlexibleArray>; +def warn_superclass_variable_sized_type_not_at_end : Warning< + "field %0 can overwrite instance variable %1 with variable sized type %2" + " in superclass %3">, InGroup<ObjCFlexibleArray>; + let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. @@ -5462,9 +5521,6 @@ def err_offsetof_incomplete_type : Error< def err_offsetof_record_type : Error< "offsetof requires struct, union, or class type, %0 invalid">; def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; -def ext_offsetof_extended_field_designator : Extension< - "using extended field designator is an extension">, - InGroup<DiagGroup<"extended-offsetof">>; def ext_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, InGroup<InvalidOffsetof>; def ext_offsetof_non_standardlayout_type : ExtWarn< @@ -5475,6 +5531,12 @@ def err_offsetof_field_of_virtual_base : Error< def warn_sub_ptr_zero_size_types : Warning< "subtraction of pointers to type %0 of zero size has undefined behavior">, InGroup<PointerArith>; +def warn_pointer_arith_null_ptr : Warning< + "performing pointer arithmetic on a null pointer has undefined behavior%select{| if the offset is nonzero}0">, + InGroup<NullPointerArithmetic>, DefaultIgnore; +def warn_gnu_null_ptr_arith : Warning< + "arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">, + InGroup<NullPointerArithmetic>, DefaultIgnore; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, @@ -5862,6 +5924,8 @@ def err_typecheck_assign_const : Error< "cannot assign to %select{non-|}1static data member %2 " "with const-qualified type %3|" "cannot assign to non-static data member within const member function %1|" + "cannot assign to %select{variable %2|non-static data member %2|lvalue}1 " + "with %select{|nested }3const-qualified data member %4|" "read-only variable is not assignable}0">; def note_typecheck_assign_const : Note< @@ -5869,25 +5933,39 @@ def note_typecheck_assign_const : Note< "function %1 which returns const-qualified type %2 declared here|" "variable %1 declared const here|" "%select{non-|}1static data member %2 declared const here|" - "member function %q1 is declared const here}0">; + "member function %q1 is declared const here|" + "%select{|nested }1data member %2 declared const here}0">; + +def warn_unsigned_always_true_comparison : Warning< + "result of comparison of %select{%3|unsigned expression}0 %2 " + "%select{unsigned expression|%3}0 is always %4">, + InGroup<TautologicalUnsignedZeroCompare>; +def warn_unsigned_enum_always_true_comparison : Warning< + "result of comparison of %select{%3|unsigned enum expression}0 %2 " + "%select{unsigned enum expression|%3}0 is always %4">, + InGroup<TautologicalUnsignedEnumZeroCompare>; +def warn_tautological_constant_compare : Warning< + "result of comparison %select{%3|%1}0 %2 " + "%select{%1|%3}0 is always %4">, + InGroup<TautologicalConstantCompare>; def warn_mixed_sign_comparison : Warning< "comparison of integers of different signs: %0 and %1">, InGroup<SignCompare>, DefaultIgnore; -def warn_lunsigned_always_true_comparison : Warning< - "comparison of unsigned%select{| enum}2 expression %0 is always %1">, - InGroup<TautologicalCompare>; def warn_out_of_range_compare : Warning< - "comparison of %select{constant %0|true|false}1 with " - "%select{expression of type %2|boolean expression}3 is always " - "%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>; -def warn_runsigned_always_true_comparison : Warning< - "comparison of %0 unsigned%select{| enum}2 expression is always %1">, - InGroup<TautologicalCompare>; + "result of comparison of %select{constant %0|true|false}1 with " + "%select{expression of type %2|boolean expression}3 is always %4">, + InGroup<TautologicalOutOfRangeCompare>; +def warn_tautological_bool_compare : Warning<warn_out_of_range_compare.Text>, + InGroup<TautologicalConstantCompare>; def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types" "%diff{ ($ and $)|}0,1">, - InGroup<DiagGroup<"enum-compare">>; + InGroup<EnumCompare>; +def warn_comparison_of_mixed_enum_types_switch : Warning< + "comparison of two values with different enumeration types in switch statement" + "%diff{ ($ and $)|}0,1">, + InGroup<EnumCompareSwitch>; def warn_null_in_arithmetic_operation : Warning< "use of NULL in arithmetic operation">, InGroup<NullArithmetic>; @@ -6391,12 +6469,12 @@ def warn_non_virtual_dtor : Warning< def warn_delete_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on non-final %1 that has " "virtual functions but non-virtual destructor">, - InGroup<DeleteNonVirtualDtor>, DefaultIgnore; + InGroup<DeleteNonVirtualDtor>, DefaultIgnore, ShowInSystemHeader; def note_delete_non_virtual : Note< "qualify call to silence this warning">; def warn_delete_abstract_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on %1 that is abstract but has " - "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>; + "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>, ShowInSystemHeader; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup<OverloadedVirtual>, DefaultIgnore; @@ -6420,8 +6498,8 @@ def warn_overaligned_type : Warning< "guarantees %2 bytes">, InGroup<OveralignedType>, DefaultIgnore; def warn_aligned_allocation_unavailable :Warning< - "aligned %select{allocation|deallocation}0 function of type '%1' possibly " - "unavailable on %2">, InGroup<AlignedAllocationUnavailable>, DefaultError; + "aligned %select{allocation|deallocation}0 function of type '%1' is only " + "available on %2 %3 or newer">, InGroup<AlignedAllocationUnavailable>, DefaultError; def note_silence_unligned_allocation_unavailable : Note< "if you supply your own aligned allocation functions, use " "-Wno-aligned-allocation-unavailable to silence this diagnostic">; @@ -6458,8 +6536,6 @@ let CategoryName = "Lambda Issue" in { "%0 can appear only once in a capture list">; def err_reference_capture_with_reference_default : Error< "'&' cannot precede a capture when the capture default is '&'">; - def err_this_capture_with_copy_default : Error< - "'this' cannot be explicitly captured when the capture default is '='">; def err_copy_capture_with_copy_default : Error< "'&' must precede a capture when the capture default is '='">; def err_capture_does_not_name_variable : Error< @@ -6526,12 +6602,20 @@ let CategoryName = "Lambda Issue" in { def err_init_capture_deduction_failure_from_init_list : Error< "cannot deduce type for lambda capture %0 from initializer list">; - // C++1z '*this' captures. + // C++17 '*this' captures. def warn_cxx14_compat_star_this_lambda_capture : Warning< "by value capture of '*this' is incompatible with C++ standards before C++17">, - InGroup<CXXPre1zCompat>, DefaultIgnore; - def ext_star_this_lambda_capture_cxx1z : ExtWarn< + InGroup<CXXPre17Compat>, DefaultIgnore; + def ext_star_this_lambda_capture_cxx17 : ExtWarn< "capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>; + + // C++2a [=, this] captures. + def warn_cxx17_compat_equals_this_lambda_capture : Warning< + "explicit capture of 'this' with a capture default of '=' is incompatible " + "with C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; + def ext_equals_this_lambda_capture_cxx2a : ExtWarn< + "explicit capture of 'this' with a capture default of '=' " + "is a C++2a extension">, InGroup<CXX2a>; } def err_return_in_captured_stmt : Error< @@ -6981,8 +7065,8 @@ def err_atomic_op_needs_atomic : Error< "address argument to atomic operation must be a pointer to _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_non_const_atomic : Error< - "address argument to atomic operation must be a pointer to non-const _Atomic " - "type (%0 invalid)">; + "address argument to atomic operation must be a pointer to non-%select{const|constant}0 _Atomic " + "type (%1 invalid)">; def err_atomic_op_needs_non_const_pointer : Error< "address argument to atomic operation must be a pointer to non-const " "type (%0 invalid)">; @@ -6998,6 +7082,8 @@ def err_atomic_op_bitwise_needs_atomic_int : Error< def warn_atomic_op_has_invalid_memory_order : Warning< "memory order argument to atomic operation is invalid">, InGroup<DiagGroup<"atomic-memory-ordering">>; +def err_atomic_op_has_invalid_synch_scope : Error< + "synchronization scope argument to atomic operation is invalid">; def err_overflow_builtin_must_be_int : Error< "operand argument to overflow builtin must be an integer (%0 invalid)">; @@ -7199,11 +7285,11 @@ def warn_unused_volatile : Warning< def ext_cxx14_attr : Extension< "use of the %0 attribute is a C++14 extension">, InGroup<CXX14>; -def ext_cxx1z_attr : Extension< +def ext_cxx17_attr : Extension< "use of the %0 attribute is a C++17 extension">, InGroup<CXX17>; def warn_unused_comparison : Warning< - "%select{%select{|in}1equality|relational}0 comparison result unused">, + "%select{equality|inequality|relational|three-way}0 comparison result unused">, InGroup<UnusedComparison>; def note_inequality_comparison_to_or_assign : Note< "use '|=' to turn this inequality comparison into an or-assignment">; @@ -7315,8 +7401,8 @@ def err_invalid_conversion_between_vector_and_integer : Error< def err_opencl_function_pointer : Error< "pointers to functions are not allowed">; -def err_opencl_taking_function_address : Error< - "taking address of function is not allowed">; +def err_opencl_taking_address_capture : Error< + "taking address of a capture is not allowed">; def err_invalid_conversion_between_vector_and_scalar : Error< "invalid conversion between vector type %0 and scalar type %1">; @@ -7457,6 +7543,9 @@ def err_ambiguous_derived_to_base_conv : Error< def err_ambiguous_memptr_conv : Error< "ambiguous conversion from pointer to member of %select{base|derived}0 " "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; +def ext_ms_ambiguous_direct_base : ExtWarn< + "accessing inaccessible direct base %0 of %1 is a Microsoft extension">, + InGroup<MicrosoftInaccessibleBase>; def err_memptr_conv_via_virtual : Error< "conversion from pointer to member of class %0 to pointer to member " @@ -7526,6 +7615,11 @@ def err_operator_delete_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; use %1 instead">; def err_operator_delete_param_type : Error< "first parameter of %0 must have type %1">; +def err_destroying_operator_delete_not_usual : Error< + "destroying operator delete can have only an optional size and optional " + "alignment parameter">; +def note_implicit_delete_this_in_destructor_here : Note< + "while checking implicit 'delete this' for virtual destructor">; // C++ literal operators def err_literal_operator_outside_namespace : Error< @@ -7831,6 +7925,8 @@ def err_type_tag_for_datatype_too_large : Error< "'type_tag_for_datatype' attribute requires the initializer to be " "an %select{integer|integral}0 constant expression " "that can be represented by a 64 bit integer">; +def err_tag_index_out_of_range : Error< + "%select{type tag|argument}0 index %1 is greater than the number of arguments specified">; def warn_type_tag_for_datatype_wrong_kind : Warning< "this type tag was not designed to be used with this function">, InGroup<TypeSafety>; @@ -7868,6 +7964,8 @@ def err_builtin_annotation_first_arg : Error< "first argument to __builtin_annotation must be an integer">; def err_builtin_annotation_second_arg : Error< "second argument to __builtin_annotation must be a non-wide string constant">; +def err_msvc_annotation_wide_str : Error< + "arguments to __annotation must be wide string constants">; // CFString checking def err_cfstring_literal_not_string_constant : Error< @@ -8195,12 +8293,12 @@ def err_c99_array_usage_cxx : Error< "feature, not permitted in C++">; def err_type_unsupported : Error< "%0 is not supported on this target">; -def err_nsconsumed_attribute_mismatch : Error< +def warn_nsconsumed_attribute_mismatch : Warning< "overriding method has mismatched ns_consumed attribute on its" - " parameter">; -def err_nsreturns_retained_attribute_mismatch : Error< + " parameter">, InGroup<NSConsumedMismatch>; +def warn_nsreturns_retained_attribute_mismatch : Warning< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" - " attributes">; + " attributes">, InGroup<NSReturnsMismatch>; def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; @@ -8364,8 +8462,6 @@ def err_opencl_scalar_type_rank_greater_than_vector_type : Error< "element. (%0 and %1)">; def err_bad_kernel_param_type : Error< "%0 cannot be used as the type of a kernel parameter">; -def err_opencl_implicit_function_decl : Error< - "implicit declaration of function %0 is invalid in OpenCL">; def err_record_with_pointers_kernel_param : Error< "%select{struct|union}0 kernel parameters may not contain pointers">; def note_within_field_of_type : Note< @@ -8518,6 +8614,8 @@ def err_omp_expected_var_name_member_expr : Error< "expected variable name%select{| or data member of current class}0">; def err_omp_expected_var_name_member_expr_or_array_item : Error< "expected variable name%select{|, data member of current class}0, array element or array section">; +def err_omp_expected_addressable_lvalue_or_array_item : Error< + "expected addressable lvalue expression, array element or array section">; def err_omp_expected_named_var_member_or_array_expression: Error< "expected expression containing only member accesses and/or array sections based on named variables">; def err_omp_bit_fields_forbidden_in_clause : Error< @@ -8525,7 +8623,7 @@ def err_omp_bit_fields_forbidden_in_clause : Error< def err_array_section_does_not_specify_contiguous_storage : Error< "array section does not specify contiguous storage">; def err_omp_union_type_not_allowed : Error< - "mapped storage cannot be derived from a union">; + "mapping of union members is not allowed">; def err_omp_expected_access_to_data_field : Error< "expected access to data field">; def err_omp_multiple_array_items_in_map_clause : Error< @@ -8612,6 +8710,8 @@ def err_omp_declare_target_to_and_link : Error< def warn_omp_not_in_target_context : Warning< "declaration is not declared in any declare target region">, InGroup<OpenMPTarget>; +def err_omp_function_in_link_clause : Error< + "function name is not allowed in 'link' clause">; def err_omp_aligned_expected_array_or_ptr : Error< "argument of aligned clause should be array" "%select{ or pointer|, pointer, reference to array or reference to pointer}1" @@ -8670,6 +8770,12 @@ def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< "list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; +def err_omp_in_reduction_not_task_reduction : Error< + "in_reduction variable must appear in a task_reduction clause">; +def err_omp_reduction_identifier_mismatch : Error< + "in_reduction variable must have the same reduction operation as in a task_reduction clause">; +def note_omp_previous_reduction_identifier : Note< + "previously marked as task_reduction with different reduction operation">; def err_omp_prohibited_region : Error< "region cannot be%select{| closely}0 nested inside '%1' region" "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" @@ -8746,9 +8852,9 @@ def err_omp_function_expected : Error< def err_omp_wrong_cancel_region : Error< "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">; def err_omp_parent_cancel_region_nowait : Error< - "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be nowait">; + "parent region for 'omp %select{cancellation point|cancel}0' construct cannot be nowait">; def err_omp_parent_cancel_region_ordered : Error< - "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be ordered">; + "parent region for 'omp %select{cancellation point|cancel}0' construct cannot be ordered">; def err_omp_reduction_wrong_type : Error<"reduction type cannot be %select{qualified with 'const', 'volatile' or 'restrict'|a function|a reference|an array}0 type">; def err_omp_wrong_var_in_declare_reduction : Error<"only %select{'omp_priv' or 'omp_orig'|'omp_in' or 'omp_out'}0 variables are allowed in %select{initializer|combiner}0 expression">; def err_omp_declare_reduction_redefinition : Error<"redefinition of user-defined reduction for type %0">; @@ -8793,16 +8899,10 @@ def err_omp_expected_base_var_name : Error< "expected variable name as a base of the array %select{subscript|section}0">; def err_omp_map_shared_storage : Error< "variable already marked as mapped in current construct">; -def err_omp_not_mappable_type : Error< - "type %0 is not mappable to target">; def err_omp_invalid_map_type_for_directive : Error< "%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">; def err_omp_no_clause_for_directive : Error< "expected at least one %0 clause for '#pragma omp %1'">; -def note_omp_polymorphic_in_target : Note< - "mappable type cannot be polymorphic">; -def note_omp_static_member_in_target : Note< - "mappable type cannot contain static members">; def err_omp_threadprivate_in_clause : Error< "threadprivate variables are not allowed in '%0' clause">; def err_omp_wrong_ordered_loop_count : Error< @@ -8821,12 +8921,6 @@ def note_omp_critical_hint_here : Note< "%select{|previous }0'hint' clause with value '%1'">; def note_omp_critical_no_hint : Note< "%select{|previous }0directive with no 'hint' clause specified">; -def err_omp_firstprivate_distribute_private_teams : Error< - "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; -def err_omp_firstprivate_and_lastprivate_in_distribute : Error< - "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">; -def err_omp_firstprivate_distribute_in_teams_reduction : Error< - "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; def err_omp_depend_clause_thread_simd : Error< "'depend' clauses cannot be mixed with '%0' clause">; def err_omp_depend_sink_expected_loop_iteration : Error< @@ -8871,6 +8965,10 @@ def err_omp_reduction_non_addressable_expression : Error< "expected addressable reduction item for the task-based directives">; def err_omp_reduction_with_nogroup : Error< "'reduction' clause cannot be used with 'nogroup' clause">; +def err_omp_reduction_vla_unsupported : Error< + "cannot generate code for reduction on %select{|array section, which requires a }0variable length array">; +def err_omp_linear_distribute_var_non_loop_iteration : Error< + "only loop iteration variables are allowed in 'linear' clause in distribute directives">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { @@ -8912,6 +9010,14 @@ def err_module_redefinition : Error< "redefinition of module '%0'">; def note_prev_module_definition : Note<"previously defined here">; def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">; +def err_module_not_defined : Error< + "definition of module '%0' is not available; use -fmodule-file= to specify " + "path to precompiled module interface">; +def err_module_redeclaration : Error< + "translation unit contains multiple module declarations">; +def note_prev_module_declaration : Note<"previous module declaration is here">; +def err_module_declaration_missing : Error< + "missing 'export module' declaration in module interface unit">; def err_module_private_specialization : Error< "%select{template|partial|member}0 specialization cannot be " "declared __module_private__">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 420ccebbfaf03..3949bc2146f6b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -77,6 +77,8 @@ def err_imported_module_not_found : Error< "module '%0' in AST file '%1' (imported by AST file '%2') " "is not defined in any loaded module map file; " "maybe you need to load '%3'?">, DefaultFatal; +def note_imported_by_pch_module_not_found : Note< + "consider adding '%0' to the header search path">; def err_imported_module_modmap_changed : Error< "module '%0' imported by AST file '%1' found in a different module map file" " (%2) than when the importing AST file was built (%3)">, DefaultFatal; @@ -122,6 +124,45 @@ def note_second_module_difference : Note< def err_module_odr_violation_different_instantiations : Error< "instantiation of %q0 is different in different modules">; +def err_module_odr_violation_definition_data : Error < + "%q0 has different definitions in different modules; first difference is " + "%select{definition in module '%2'|defined here}1 found " + "%select{" + "%4 base %plural{1:class|:classes}4|" + "%4 virtual base %plural{1:class|:classes}4|" + "%ordinal4 base class with type %5|" + "%ordinal4 %select{non-virtual|virtual}5 base class %6|" + "%ordinal4 base class %5 with " + "%select{public|protected|private|no}6 access specifier}3">; + +def note_module_odr_violation_definition_data : Note < + "but in '%0' found " + "%select{" + "%2 base %plural{1:class|:classes}2|" + "%2 virtual base %plural{1:class|:classes}2|" + "%ordinal2 base class with different type %3|" + "%ordinal2 %select{non-virtual|virtual}3 base class %4|" + "%ordinal2 base class %3 with " + "%select{public|protected|private|no}4 access specifier}1">; + +def err_module_odr_violation_template_parameter : Error < + "%q0 has different definitions in different modules; first difference is " + "%select{definition in module '%2'|defined here}1 found " + "%select{" + "unnamed template parameter|" + "template parameter %4|" + "template parameter with %select{no |}4default argument|" + "template parameter with default argument}3">; + + +def note_module_odr_violation_template_parameter : Note < + "but in '%0' found " + "%select{" + "unnamed template parameter %2|" + "template parameter %2|" + "template parameter with %select{no |}2default argument|" + "template parameter with different default argument}1">; + def err_module_odr_violation_mismatch_decl : Error< "%q0 has different definitions in different modules; first difference is " "%select{definition in module '%2'|defined here}1 found " diff --git a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h index f94b2c9b2f420..8e3c15afbfcd4 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h @@ -1,4 +1,4 @@ -//===--- IdentifierTable.h - Hash table for identifier lookup ---*- C++ -*-===// +//===- IdentifierTable.h - Hash table for identifier lookup -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,11 +6,11 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::IdentifierInfo, clang::IdentifierTable, and /// clang::Selector interfaces. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H @@ -18,35 +18,29 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/type_traits.h" #include <cassert> #include <cstddef> #include <cstdint> #include <cstring> -#include <new> #include <string> #include <utility> -namespace llvm { - - template <typename T> struct DenseMapInfo; - -} // end namespace llvm - namespace clang { - class LangOptions; - class IdentifierInfo; - class IdentifierTable; - class SourceLocation; - class MultiKeywordSelector; // private class used by Selector - class DeclarationName; // AST class that stores declaration names +class IdentifierInfo; +class LangOptions; +class MultiKeywordSelector; +class SourceLocation; - /// \brief A simple pair of identifier info and location. - typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair; +/// \brief A simple pair of identifier info and location. +using IdentifierLocPair = std::pair<IdentifierInfo *, SourceLocation>; /// One of these records is kept for each identifier that /// is lexed. This contains information about whether the token was \#define'd, @@ -85,8 +79,10 @@ class IdentifierInfo { // keyword. // 29 bit left in 64-bit word. - void *FETokenInfo; // Managed by the language front-end. - llvm::StringMapEntry<IdentifierInfo*> *Entry; + // Managed by the language front-end. + void *FETokenInfo = nullptr; + + llvm::StringMapEntry<IdentifierInfo *> *Entry = nullptr; public: IdentifierInfo(); @@ -104,7 +100,6 @@ public: /// \brief Return the beginning of the actual null-terminated string for this /// identifier. - /// const char *getNameStart() const { if (Entry) return Entry->getKeyData(); // FIXME: This is gross. It would be best not to embed specific details @@ -112,12 +107,12 @@ public: // The 'this' pointer really points to a // std::pair<IdentifierInfo, const char*>, where internal pointer // points to the external string data. - typedef std::pair<IdentifierInfo, const char*> actualtype; + using actualtype = std::pair<IdentifierInfo, const char *>; + return ((const actualtype*) this)->second; } /// \brief Efficiently return the length of this identifier info. - /// unsigned getLength() const { if (Entry) return Entry->getKeyLength(); // FIXME: This is gross. It would be best not to embed specific details @@ -125,7 +120,8 @@ public: // The 'this' pointer really points to a // std::pair<IdentifierInfo, const char*>, where internal pointer // points to the external string data. - typedef std::pair<IdentifierInfo, const char*> actualtype; + using actualtype = std::pair<IdentifierInfo, const char *>; + const char* p = ((const actualtype*) this)->second - 2; return (((unsigned) p[0]) | (((unsigned) p[1]) << 8)) - 1; } @@ -465,7 +461,7 @@ public: class IdentifierTable { // Shark shows that using MallocAllocator is *much* slower than using this // BumpPtrAllocator! - typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy; + using HashTableTy = llvm::StringMap<IdentifierInfo *, llvm::BumpPtrAllocator>; HashTableTy HashTable; IdentifierInfoLookup* ExternalLookup; @@ -551,8 +547,8 @@ public: return *II; } - typedef HashTableTy::const_iterator iterator; - typedef HashTableTy::const_iterator const_iterator; + using iterator = HashTableTy::const_iterator; + using const_iterator = HashTableTy::const_iterator; iterator begin() const { return HashTable.begin(); } iterator end() const { return HashTable.end(); } @@ -654,7 +650,9 @@ class Selector { MultiArg = 0x3, ArgFlags = ZeroArg|OneArg }; - uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. + + // a pointer to the MultiKeywordSelector or IdentifierInfo. + uintptr_t InfoPtr = 0; Selector(IdentifierInfo *II, unsigned nArgs) { InfoPtr = reinterpret_cast<uintptr_t>(II); @@ -662,6 +660,7 @@ class Selector { assert(nArgs < 2 && "nArgs not equal to 0/1"); InfoPtr |= nArgs+1; } + Selector(MultiKeywordSelector *SI) { InfoPtr = reinterpret_cast<uintptr_t>(SI); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); @@ -692,7 +691,7 @@ public: /// The default ctor should only be used when creating data structures that /// will contain selectors. - Selector() : InfoPtr(0) {} + Selector() = default; Selector(uintptr_t V) : InfoPtr(V) {} /// operator==/!= - Indicate whether the specified selectors are identical. @@ -776,7 +775,8 @@ public: /// \brief This table allows us to fully hide how we implement /// multi-keyword caching. class SelectorTable { - void *Impl; // Actually a SelectorTableImpl + // Actually a SelectorTableImpl + void *Impl; public: SelectorTable(); @@ -793,6 +793,7 @@ public: Selector getUnarySelector(IdentifierInfo *ID) { return Selector(ID, 1); } + Selector getNullarySelector(IdentifierInfo *ID) { return Selector(ID, 0); } @@ -848,7 +849,7 @@ public: unsigned ExtraKindOrNumArgs; }; -} // end namespace clang +} // namespace clang namespace llvm { @@ -856,11 +857,11 @@ namespace llvm { /// DenseSets. template <> struct DenseMapInfo<clang::Selector> { - static inline clang::Selector getEmptyKey() { + static clang::Selector getEmptyKey() { return clang::Selector::getEmptyMarker(); } - static inline clang::Selector getTombstoneKey() { + static clang::Selector getTombstoneKey() { return clang::Selector::getTombstoneMarker(); } @@ -874,16 +875,13 @@ struct DenseMapInfo<clang::Selector> { template <> struct isPodLike<clang::Selector> { static const bool value = true; }; -template <typename T> class PointerLikeTypeTraits; - template<> -class PointerLikeTypeTraits<clang::Selector> { -public: - static inline const void *getAsVoidPointer(clang::Selector P) { +struct PointerLikeTypeTraits<clang::Selector> { + static const void *getAsVoidPointer(clang::Selector P) { return P.getAsOpaquePtr(); } - static inline clang::Selector getFromVoidPointer(const void *P) { + static clang::Selector getFromVoidPointer(const void *P) { return clang::Selector(reinterpret_cast<uintptr_t>(P)); } @@ -893,13 +891,12 @@ public: // Provide PointerLikeTypeTraits for IdentifierInfo pointers, which // are not guaranteed to be 8-byte aligned. template<> -class PointerLikeTypeTraits<clang::IdentifierInfo*> { -public: - static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { +struct PointerLikeTypeTraits<clang::IdentifierInfo*> { + static void *getAsVoidPointer(clang::IdentifierInfo* P) { return P; } - static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { + static clang::IdentifierInfo *getFromVoidPointer(void *P) { return static_cast<clang::IdentifierInfo*>(P); } @@ -907,19 +904,18 @@ public: }; template<> -class PointerLikeTypeTraits<const clang::IdentifierInfo*> { -public: - static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { +struct PointerLikeTypeTraits<const clang::IdentifierInfo*> { + static const void *getAsVoidPointer(const clang::IdentifierInfo* P) { return P; } - static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) { + static const clang::IdentifierInfo *getFromVoidPointer(const void *P) { return static_cast<const clang::IdentifierInfo*>(P); } enum { NumLowBitsAvailable = 1 }; }; -} // end namespace llvm +} // namespace llvm #endif // LLVM_CLANG_BASIC_IDENTIFIERTABLE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h b/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h index f32ab5e11bd4a..e60284d1b4459 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h @@ -35,6 +35,7 @@ namespace llvm { template<typename T, unsigned N> class SmallVector; template<typename T> class SmallVectorImpl; template<typename T> class Optional; + template <class T> class Expected; template<typename T> struct SaveAndRestore; @@ -71,6 +72,9 @@ namespace clang { using llvm::SmallVectorImpl; using llvm::SaveAndRestore; + // Error handling. + using llvm::Expected; + // Reference counting. using llvm::IntrusiveRefCntPtr; using llvm::IntrusiveRefCntPtrInfo; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def index c9230e0aaa6f3..ca3a0e349d62f 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def @@ -82,6 +82,7 @@ // FIXME: A lot of the BENIGN_ options should be COMPATIBLE_ instead. LANGOPT(C99 , 1, 0, "C99") LANGOPT(C11 , 1, 0, "C11") +LANGOPT(C17 , 1, 0, "C17") LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode") LANGOPT(MicrosoftExt , 1, 0, "Microsoft C++ extensions") LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks") @@ -89,7 +90,7 @@ LANGOPT(Borland , 1, 0, "Borland extensions") LANGOPT(CPlusPlus , 1, 0, "C++") LANGOPT(CPlusPlus11 , 1, 0, "C++11") LANGOPT(CPlusPlus14 , 1, 0, "C++14") -LANGOPT(CPlusPlus1z , 1, 0, "C++1z") +LANGOPT(CPlusPlus17 , 1, 0, "C++17") LANGOPT(CPlusPlus2a , 1, 0, "C++2a") LANGOPT(ObjC1 , 1, 0, "Objective-C 1") LANGOPT(ObjC2 , 1, 0, "Objective-C 2") @@ -124,7 +125,9 @@ LANGOPT(ZVector , 1, 0, "System z vector extensions") LANGOPT(Exceptions , 1, 0, "exception handling") LANGOPT(ObjCExceptions , 1, 0, "Objective-C exceptions") LANGOPT(CXXExceptions , 1, 0, "C++ exceptions") +LANGOPT(DWARFExceptions , 1, 0, "dwarf exception handling") LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling") +LANGOPT(SEHExceptions , 1, 0, "SEH .xdata exception handling") LANGOPT(ExternCNoUnwind , 1, 0, "Assume extern C functions don't unwind") LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation") LANGOPT(RTTI , 1, 1, "run-time type information") @@ -137,6 +140,8 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly") LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS") LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") +LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") + BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") LANGOPT(Blocks , 1, 0, "blocks extension to C") @@ -175,7 +180,8 @@ BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __w BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control") LANGOPT(CharIsSigned , 1, 1, "signed char") -LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t") +LANGOPT(WCharSize , 4, 0, "width of wchar_t") +LANGOPT(WCharIsSigned , 1, 0, "signed or unsigned wchar_t") ENUM_LANGOPT(MSPointerToMemberRepresentationMethod, PragmaMSPointersToMembersKind, 2, PPTMK_BestCase, "member-pointer representation method") ENUM_LANGOPT(DefaultCallingConv, DefaultCallingConvention, 3, DCC_None, "default calling convention") @@ -267,6 +273,9 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " "aggressive, 2: more aggressive)") LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") +LANGOPT(XRayAlwaysEmitCustomEvents, 1, 0, + "controls whether to always emit intrinsic calls to " + "__xray_customevent(...) builtin.") BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h index 8488515d2b677..f7a43adefad0c 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h @@ -77,7 +77,8 @@ public: DCC_CDecl, DCC_FastCall, DCC_StdCall, - DCC_VectorCall + DCC_VectorCall, + DCC_RegCall }; enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off }; @@ -197,6 +198,10 @@ public: bool allowsNonTrivialObjCLifetimeQualifiers() const { return ObjCAutoRefCount || ObjCWeak; } + + bool assumeFunctionsAreConvergent() const { + return (CUDA && CUDAIsDevice) || OpenCL; + } }; /// \brief Floating point control options diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Module.h b/contrib/llvm/tools/clang/include/clang/Basic/Module.h index 177175eae9650..6631721e35314 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Module.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Module.h @@ -1,4 +1,4 @@ -//===--- Module.h - Describe a module ---------------------------*- C++ -*-===// +//===- Module.h - Describe a module -----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,12 +6,13 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::Module class, which describes a module in the /// source code. -/// +// //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_BASIC_MODULE_H #define LLVM_CLANG_BASIC_MODULE_H @@ -19,6 +20,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SetVector.h" @@ -26,22 +28,28 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include <array> +#include <cassert> +#include <cstdint> +#include <ctime> #include <string> #include <utility> #include <vector> namespace llvm { - class raw_ostream; -} + +class raw_ostream; + +} // namespace llvm namespace clang { class LangOptions; class TargetInfo; -class IdentifierInfo; - + /// \brief Describes the name of a module. -typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId; +using ModuleId = SmallVector<std::pair<std::string, SourceLocation>, 2>; /// The signature of a module, which is a hash of the AST content. struct ASTFileSignature : std::array<uint32_t, 5> { @@ -68,7 +76,11 @@ public: ModuleMapModule, /// \brief This is a C++ Modules TS module interface unit. - ModuleInterfaceUnit + ModuleInterfaceUnit, + + /// \brief This is a fragment of the global module within some C++ Modules + /// TS module. + GlobalModuleFragment, }; /// \brief The kind of this module. @@ -81,7 +93,7 @@ public: /// \brief The build directory of this module. This is the directory in /// which the module is notionally built, and relative to which its headers /// are found. - const DirectoryEntry *Directory; + const DirectoryEntry *Directory = nullptr; /// \brief The presumed file name for the module map defining this module. /// Only non-empty when building from preprocessed source. @@ -95,6 +107,10 @@ public: /// \brief The name of the umbrella entry, as written in the module map. std::string UmbrellaAsWritten; + + /// \brief The module through which entities defined in this module will + /// eventually be exposed, for use in "private" modules. + std::string ExportAsModule; private: /// \brief The submodules of this module, indexed by name. @@ -106,7 +122,7 @@ private: /// \brief The AST file if this is a top-level module which has a /// corresponding serialized AST file, or null otherwise. - const FileEntry *ASTFile; + const FileEntry *ASTFile = nullptr; /// \brief The top-level headers associated with this module. llvm::SmallSetVector<const FileEntry *, 2> TopHeaders; @@ -173,7 +189,7 @@ public: /// \brief An individual requirement: a feature name and a flag indicating /// the required state of that feature. - typedef std::pair<std::string, bool> Requirement; + using Requirement = std::pair<std::string, bool>; /// \brief The set of language features required to use this module. /// @@ -262,7 +278,7 @@ public: /// /// The pointer is the module being re-exported, while the bit will be true /// to indicate that this is a wildcard export. - typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl; + using ExportDecl = llvm::PointerIntPair<Module *, 1, bool>; /// \brief The set of export declarations. SmallVector<ExportDecl, 2> Exports; @@ -294,9 +310,9 @@ public: /// \brief A library or framework to link against when an entity from this /// module is used. struct LinkLibrary { - LinkLibrary() : IsFramework(false) { } + LinkLibrary() = default; LinkLibrary(const std::string &Library, bool IsFramework) - : Library(Library), IsFramework(IsFramework) { } + : Library(Library), IsFramework(IsFramework) {} /// \brief The library to link against. /// @@ -305,7 +321,7 @@ public: std::string Library; /// \brief Whether this is a framework rather than a library. - bool IsFramework; + bool IsFramework = false; }; /// \brief The set of libraries or frameworks to link against when @@ -391,6 +407,15 @@ public: return IsFramework && Parent && Parent->isPartOfFramework(); } + /// Set the parent of this module. This should only be used if the parent + /// could not be set during module creation. + void setParent(Module *M) { + assert(!Parent); + Parent = M; + Parent->SubModuleIndex[Name] = Parent->SubModules.size(); + Parent->SubModules.push_back(this); + } + /// \brief Retrieve the full name of this module, including the path from /// its top-level module. /// \param AllowStringLiterals If \c true, components that might not be @@ -415,7 +440,6 @@ public: const Module *getTopLevelModule() const; /// \brief Retrieve the name of the top-level module. - /// StringRef getTopLevelModuleName() const { return getTopLevelModule()->Name; } @@ -508,8 +532,8 @@ public: unsigned getVisibilityID() const { return VisibilityID; } - typedef std::vector<Module *>::iterator submodule_iterator; - typedef std::vector<Module *>::const_iterator submodule_const_iterator; + using submodule_iterator = std::vector<Module *>::iterator; + using submodule_const_iterator = std::vector<Module *>::const_iterator; submodule_iterator submodule_begin() { return SubModules.begin(); } submodule_const_iterator submodule_begin() const {return SubModules.begin();} @@ -534,7 +558,6 @@ public: } /// \brief Print the module map for this module to the given stream. - /// void print(raw_ostream &OS, unsigned Indent = 0) const; /// \brief Dump the contents of this module to the given output stream. @@ -547,7 +570,7 @@ private: /// \brief A set of visible modules. class VisibleModuleSet { public: - VisibleModuleSet() : Generation(0) {} + VisibleModuleSet() = default; VisibleModuleSet(VisibleModuleSet &&O) : ImportLocs(std::move(O.ImportLocs)), Generation(O.Generation ? 1 : 0) { O.ImportLocs.clear(); @@ -582,13 +605,15 @@ public: /// \brief A callback to call when a module is made visible (directly or /// indirectly) by a call to \ref setVisible. - typedef llvm::function_ref<void(Module *M)> VisibleCallback; + using VisibleCallback = llvm::function_ref<void(Module *M)>; + /// \brief A callback to call when a module conflict is found. \p Path /// consists of a sequence of modules from the conflicting module to the one /// made visible, where each was exported by the next. - typedef llvm::function_ref<void(ArrayRef<Module *> Path, - Module *Conflict, StringRef Message)> - ConflictCallback; + using ConflictCallback = + llvm::function_ref<void(ArrayRef<Module *> Path, Module *Conflict, + StringRef Message)>; + /// \brief Make a specific module visible. void setVisible(Module *M, SourceLocation Loc, VisibleCallback Vis = [](Module *) {}, @@ -599,11 +624,11 @@ private: /// Import locations for each visible module. Indexed by the module's /// VisibilityID. std::vector<SourceLocation> ImportLocs; + /// Visibility generation, bumped every time the visibility state changes. - unsigned Generation; + unsigned Generation = 0; }; -} // end namespace clang - +} // namespace clang #endif // LLVM_CLANG_BASIC_MODULE_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def index 360fec4281ac1..c3319d2d808b9 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLExtensions.def @@ -79,6 +79,10 @@ OPENCLEXT_INTERNAL(cl_clang_storage_class_specifiers, 100, ~0U) OPENCLEXT_INTERNAL(cl_amd_media_ops, 100, ~0U) OPENCLEXT_INTERNAL(cl_amd_media_ops2, 100, ~0U) +// Intel OpenCL extensions +OPENCLEXT_INTERNAL(cl_intel_subgroups, 120, ~0U) +OPENCLEXT_INTERNAL(cl_intel_subgroups_short, 120, ~0U) + #undef OPENCLEXT_INTERNAL #ifdef OPENCLEXT diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def index 645ed52b59cab..6a0bed7ab15fc 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def @@ -274,6 +274,7 @@ OPENMP_CLAUSE(from, OMPFromClause) OPENMP_CLAUSE(use_device_ptr, OMPUseDevicePtrClause) OPENMP_CLAUSE(is_device_ptr, OMPIsDevicePtrClause) OPENMP_CLAUSE(task_reduction, OMPTaskReductionClause) +OPENMP_CLAUSE(in_reduction, OMPInReductionClause) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -434,6 +435,7 @@ OPENMP_TASK_CLAUSE(untied) OPENMP_TASK_CLAUSE(mergeable) OPENMP_TASK_CLAUSE(depend) OPENMP_TASK_CLAUSE(priority) +OPENMP_TASK_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'atomic'. OPENMP_ATOMIC_CLAUSE(read) @@ -452,6 +454,7 @@ OPENMP_TARGET_CLAUSE(depend) OPENMP_TARGET_CLAUSE(defaultmap) OPENMP_TARGET_CLAUSE(firstprivate) OPENMP_TARGET_CLAUSE(is_device_ptr) +OPENMP_TARGET_CLAUSE(reduction) // Clauses allowed for OpenMP directive 'target data'. OPENMP_TARGET_DATA_CLAUSE(if) @@ -557,6 +560,7 @@ OPENMP_TASKLOOP_CLAUSE(grainsize) OPENMP_TASKLOOP_CLAUSE(nogroup) OPENMP_TASKLOOP_CLAUSE(num_tasks) OPENMP_TASKLOOP_CLAUSE(reduction) +OPENMP_TASKLOOP_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'taskloop simd'. OPENMP_TASKLOOP_SIMD_CLAUSE(if) @@ -578,6 +582,7 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize) OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup) OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks) OPENMP_TASKLOOP_SIMD_CLAUSE(reduction) +OPENMP_TASKLOOP_SIMD_CLAUSE(in_reduction) // Clauses allowed for OpenMP directive 'critical'. OPENMP_CRITICAL_CLAUSE(hint) @@ -741,9 +746,9 @@ OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(private) OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(shared) OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(reduction) OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(schedule) -OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(linear) OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(num_teams) OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(thread_limit) +OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(copyin) // Clauses allowed for OpenMP directive 'target teams'. OPENMP_TARGET_TEAMS_CLAUSE(if) @@ -801,7 +806,6 @@ OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(dist_schedule) OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(num_threads) OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(proc_bind) OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(schedule) -OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(linear) // Clauses allowed for OpenMP directive // 'target teams distribute parallel for simd'. diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def index 34ad7644cd2ba..d86294bac9020 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/OperatorKinds.def @@ -89,6 +89,7 @@ OVERLOADED_OPERATOR(EqualEqual , "==" , equalequal , false, t OVERLOADED_OPERATOR(ExclaimEqual , "!=" , exclaimequal , false, true , false) OVERLOADED_OPERATOR(LessEqual , "<=" , lessequal , false, true , false) OVERLOADED_OPERATOR(GreaterEqual , ">=" , greaterequal , false, true , false) +OVERLOADED_OPERATOR(Spaceship , "<=>" , spaceship , false, true , false) OVERLOADED_OPERATOR(AmpAmp , "&&" , ampamp , false, true , false) OVERLOADED_OPERATOR(PipePipe , "||" , pipepipe , false, true , false) OVERLOADED_OPERATOR(PlusPlus , "++" , plusplus , true , true , false) diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h b/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h index 640749fdd10d5..94978f81e543a 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/OperatorPrecedence.h @@ -36,10 +36,11 @@ namespace prec { And = 8, // & Equality = 9, // ==, != Relational = 10, // >=, <=, >, < - Shift = 11, // <<, >> - Additive = 12, // -, + - Multiplicative = 13, // *, /, % - PointerToMember = 14 // .*, ->* + Spaceship = 11, // <=> + Shift = 12, // <<, >> + Additive = 13, // -, + + Multiplicative = 14, // *, /, % + PointerToMember = 15 // .*, ->* }; } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h index e651e18316833..1ae5c36eea99a 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerBlacklist.h @@ -15,29 +15,30 @@ #define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H #include "clang/Basic/LLVM.h" +#include "clang/Basic/SanitizerSpecialCaseList.h" +#include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/SpecialCaseList.h" #include <memory> namespace clang { class SanitizerBlacklist { - std::unique_ptr<llvm::SpecialCaseList> SCL; + std::unique_ptr<SanitizerSpecialCaseList> SSCL; SourceManager &SM; public: SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths, SourceManager &SM); - bool isBlacklistedGlobal(StringRef GlobalName, + bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName, StringRef Category = StringRef()) const; - bool isBlacklistedType(StringRef MangledTypeName, + bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName, StringRef Category = StringRef()) const; - bool isBlacklistedFunction(StringRef FunctionName) const; - bool isBlacklistedFile(StringRef FileName, + bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const; + bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName, StringRef Category = StringRef()) const; - bool isBlacklistedLocation(SourceLocation Loc, + bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc, StringRef Category = StringRef()) const; }; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SanitizerSpecialCaseList.h b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerSpecialCaseList.h new file mode 100644 index 0000000000000..e3252022a44f1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SanitizerSpecialCaseList.h @@ -0,0 +1,54 @@ +//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H +#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SpecialCaseList.h" +#include <memory> + +namespace clang { + +class SanitizerSpecialCaseList : public llvm::SpecialCaseList { +public: + static std::unique_ptr<SanitizerSpecialCaseList> + create(const std::vector<std::string> &Paths, std::string &Error); + + static std::unique_ptr<SanitizerSpecialCaseList> + createOrDie(const std::vector<std::string> &Paths); + + // Query blacklisted entries if any bit in Mask matches the entry's section. + bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, + StringRef Category = StringRef()) const; + +protected: + // Initialize SanitizerSections. + void createSanitizerSections(); + + struct SanitizerSection { + SanitizerSection(SanitizerMask SM, SectionEntries &E) + : Mask(SM), Entries(E){}; + + SanitizerMask Mask; + SectionEntries &Entries; + }; + + std::vector<SanitizerSection> SanitizerSections; +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def index 71b11974dbfde..30d5cc8166dc6 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def @@ -44,12 +44,17 @@ SANITIZER("address", Address) // Kernel AddressSanitizer (KASan) SANITIZER("kernel-address", KernelAddress) +SANITIZER("hwaddress", HWAddress) + // MemorySanitizer SANITIZER("memory", Memory) // libFuzzer SANITIZER("fuzzer", Fuzzer) +// libFuzzer-required instrumentation, no linking. +SANITIZER("fuzzer-no-link", FuzzerNoLink) + // ThreadSanitizer SANITIZER("thread", Thread) @@ -60,6 +65,7 @@ SANITIZER("leak", Leak) SANITIZER("alignment", Alignment) SANITIZER("array-bounds", ArrayBounds) SANITIZER("bool", Bool) +SANITIZER("builtin", Builtin) SANITIZER("enum", Enum) SANITIZER("float-cast-overflow", FloatCastOverflow) SANITIZER("float-divide-by-zero", FloatDivideByZero) @@ -107,11 +113,12 @@ SANITIZER("safe-stack", SafeStack) // -fsanitize=undefined includes all the sanitizers which have low overhead, no // ABI or address space layout implications, and only catch undefined behavior. SANITIZER_GROUP("undefined", Undefined, - Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow | - FloatDivideByZero | IntegerDivideByZero | NonnullAttribute | - Null | ObjectSize | PointerOverflow | Return | - ReturnsNonnullAttribute | Shift | SignedIntegerOverflow | - Unreachable | VLABound | Function | Vptr) + Alignment | Bool | Builtin | ArrayBounds | Enum | + FloatCastOverflow | FloatDivideByZero | + IntegerDivideByZero | NonnullAttribute | Null | ObjectSize | + PointerOverflow | Return | ReturnsNonnullAttribute | Shift | + SignedIntegerOverflow | Unreachable | VLABound | Function | + Vptr) // -fsanitize=undefined-trap is an alias for -fsanitize=undefined. SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined) @@ -130,6 +137,9 @@ SANITIZER("efficiency-working-set", EfficiencyWorkingSet) SANITIZER_GROUP("efficiency-all", Efficiency, EfficiencyCacheFrag | EfficiencyWorkingSet) +// Scudo hardened allocator +SANITIZER("scudo", Scudo) + // Magic group, containing all sanitizers. For example, "-fno-sanitize=all" // can be used to disable all the sanitizers. SANITIZER_GROUP("all", All, ~0ULL) diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h index 5317720095e06..1b936c7d115cf 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h @@ -80,7 +80,7 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); /// Return the sanitizers which do not affect preprocessing. -static inline SanitizerMask getPPTransparentSanitizers() { +inline SanitizerMask getPPTransparentSanitizers() { return SanitizerKind::CFI | SanitizerKind::Integer | SanitizerKind::Nullability | SanitizerKind::Undefined; } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h index 12aa0e4f57170..7418b50f9d83b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h @@ -39,10 +39,9 @@ class SourceManager; class FileID { /// \brief A mostly-opaque identifier, where 0 is "invalid", >0 is /// this module, and <-1 is something loaded from another module. - int ID; -public: - FileID() : ID(0) {} + int ID = 0; +public: bool isValid() const { return ID != 0; } bool isInvalid() const { return ID == 0; } @@ -86,17 +85,15 @@ private: /// /// It is important that this type remains small. It is currently 32 bits wide. class SourceLocation { - unsigned ID; + unsigned ID = 0; friend class SourceManager; friend class ASTReader; friend class ASTWriter; enum : unsigned { MacroIDBit = 1U << 31 }; -public: - - SourceLocation() : ID(0) {} +public: bool isFileID() const { return (ID & MacroIDBit) == 0; } bool isMacroID() const { return (ID & MacroIDBit) != 0; } @@ -172,6 +169,11 @@ public: return getFromRawEncoding((unsigned)(uintptr_t)Encoding); } + static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { + return Start.isValid() && Start.isFileID() && End.isValid() && + End.isFileID(); + } + void print(raw_ostream &OS, const SourceManager &SM) const; std::string printToString(const SourceManager &SM) const; void dump(const SourceManager &SM) const; @@ -193,8 +195,9 @@ inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { class SourceRange { SourceLocation B; SourceLocation E; + public: - SourceRange(): B(SourceLocation()), E(SourceLocation()) {} + SourceRange() = default; SourceRange(SourceLocation loc) : B(loc), E(loc) {} SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} @@ -225,9 +228,10 @@ public: /// range. class CharSourceRange { SourceRange Range; - bool IsTokenRange; + bool IsTokenRange = false; + public: - CharSourceRange() : IsTokenRange(false) {} + CharSourceRange() = default; CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} static CharSourceRange getTokenRange(SourceRange R) { @@ -325,10 +329,11 @@ class FileEntry; /// /// This is useful for argument passing to functions that expect both objects. class FullSourceLoc : public SourceLocation { - const SourceManager *SrcMgr; + const SourceManager *SrcMgr = nullptr; + public: /// \brief Creates a FullSourceLoc where isValid() returns \c false. - explicit FullSourceLoc() : SrcMgr(nullptr) {} + FullSourceLoc() = default; explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} @@ -455,8 +460,7 @@ namespace llvm { // Teach SmallPtrSet how to handle SourceLocation. template<> - class PointerLikeTypeTraits<clang::SourceLocation> { - public: + struct PointerLikeTypeTraits<clang::SourceLocation> { static inline void *getAsVoidPointer(clang::SourceLocation L) { return L.getPtrEncoding(); } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h index ed3f8dfa86e74..397ad2e77fb5e 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h @@ -1,4 +1,4 @@ -//===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===// +//===- SourceManager.h - Track and cache source files -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,7 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the SourceManager interface. /// @@ -29,14 +29,13 @@ /// location in the source where the macro was originally defined, /// and the presumed location is where the line directive states that /// the line is 17, or any other line. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H #define LLVM_CLANG_BASIC_SOURCEMANAGER_H #include "clang/Basic/FileManager.h" -#include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" @@ -49,10 +48,8 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" -#include <algorithm> #include <cassert> #include <cstddef> -#include <cstdint> #include <map> #include <memory> #include <string> @@ -69,7 +66,6 @@ class SourceManager; /// \brief Public enums and private classes that are part of the /// SourceManager implementation. -/// namespace SrcMgr { /// \brief Indicates whether a file or directory holds normal user code, @@ -100,6 +96,7 @@ namespace SrcMgr { enum CCFlags { /// \brief Whether the buffer is invalid. InvalidFlag = 0x01, + /// \brief Whether the buffer should not be freed on destruction. DoNotFreeFlag = 0x02 }; @@ -130,12 +127,12 @@ namespace SrcMgr { /// /// This is lazily computed. This is owned by the SourceManager /// BumpPointerAllocator object. - unsigned *SourceLineCache; + unsigned *SourceLineCache = nullptr; /// \brief The number of lines in this ContentCache. /// /// This is only valid if SourceLineCache is non-null. - unsigned NumLines; + unsigned NumLines = 0; /// \brief Indicates whether the buffer itself was provided to override /// the actual file contents. @@ -157,15 +154,14 @@ namespace SrcMgr { ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt), - SourceLineCache(nullptr), NumLines(0), BufferOverridden(false), - IsSystemFile(false), IsTransient(false) {} + BufferOverridden(false), IsSystemFile(false), IsTransient(false) {} /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transferred, so this is a logical error. ContentCache(const ContentCache &RHS) - : Buffer(nullptr, false), SourceLineCache(nullptr), - BufferOverridden(false), IsSystemFile(false), IsTransient(false) { + : Buffer(nullptr, false), BufferOverridden(false), IsSystemFile(false), + IsTransient(false) { OrigEntry = RHS.OrigEntry; ContentsEntry = RHS.ContentsEntry; @@ -212,12 +208,6 @@ namespace SrcMgr { /// this content cache. This is used for performance analysis. llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const; - void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) { - assert(!Buffer.getPointer() && "MemoryBuffer already set."); - Buffer.setPointer(B.release()); - Buffer.setInt(0); - } - /// \brief Get the underlying buffer, returning NULL if the buffer is not /// yet available. llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); } @@ -252,6 +242,10 @@ namespace SrcMgr { /// FileInfos contain a "ContentCache *", with the contents of the file. /// class FileInfo { + friend class clang::SourceManager; + friend class clang::ASTWriter; + friend class clang::ASTReader; + /// \brief The location of the \#include that brought in this file. /// /// This is an invalid SLOC for the main file (top of the \#include chain). @@ -270,10 +264,6 @@ namespace SrcMgr { llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind> ContentAndKind; - friend class clang::SourceManager; - friend class clang::ASTWriter; - friend class clang::ASTReader; - public: /// \brief Return a FileInfo object. static FileInfo get(SourceLocation IL, const ContentCache *Con, @@ -454,7 +444,7 @@ namespace SrcMgr { } }; -} // end SrcMgr namespace. +} // namespace SrcMgr /// \brief External source of source location entries. class ExternalSLocEntrySource { @@ -552,7 +542,7 @@ public: /// \brief The stack used when building modules on demand, which is used /// to provide a link between the source managers of the different compiler /// instances. -typedef ArrayRef<std::pair<std::string, FullSourceLoc>> ModuleBuildStack; +using ModuleBuildStack = ArrayRef<std::pair<std::string, FullSourceLoc>>; /// \brief This class handles loading and caching of source files into memory. /// @@ -584,7 +574,7 @@ class SourceManager : public RefCountedBase<SourceManager> { /// \brief True if the ContentCache for files that are overridden by other /// files, should report the original file name. Defaults to true. - bool OverridenFilesKeepOriginalName; + bool OverridenFilesKeepOriginalName = true; /// \brief True if non-system source files should be treated as volatile /// (likely to change while trying to use them). Defaults to false. @@ -593,12 +583,13 @@ class SourceManager : public RefCountedBase<SourceManager> { /// \brief True if all files read during this compilation should be treated /// as transient (may not be present in later compilations using a module /// file created from this compilation). Defaults to false. - bool FilesAreTransient; + bool FilesAreTransient = false; struct OverriddenFilesInfoTy { /// \brief Files that have been overridden with the contents from another /// file. llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles; + /// \brief Files that were overridden with a memory buffer. llvm::DenseSet<const FileEntry *> OverriddenFilesWithBuffer; }; @@ -653,7 +644,7 @@ class SourceManager : public RefCountedBase<SourceManager> { llvm::BitVector SLocEntryLoaded; /// \brief An external source for source location entries. - ExternalSLocEntrySource *ExternalSLocEntries; + ExternalSLocEntrySource *ExternalSLocEntries = nullptr; /// \brief A one-entry cache to speed up getFileID. /// @@ -664,7 +655,7 @@ class SourceManager : public RefCountedBase<SourceManager> { /// \brief Holds information for \#line directives. /// /// This is referenced by indices from SLocEntryTable. - LineTableInfo *LineTable; + LineTableInfo *LineTable = nullptr; /// \brief These ivars serve as a cache used in the getLineNumber /// method which is used to speedup getLineNumber calls to nearby locations. @@ -680,7 +671,8 @@ class SourceManager : public RefCountedBase<SourceManager> { FileID PreambleFileID; // Statistics for -print-stats. - mutable unsigned NumLinearScans, NumBinaryProbes; + mutable unsigned NumLinearScans = 0; + mutable unsigned NumBinaryProbes = 0; /// \brief Associates a FileID with its "included/expanded in" decomposed /// location. @@ -690,12 +682,12 @@ class SourceManager : public RefCountedBase<SourceManager> { mutable llvm::DenseMap<FileID, std::pair<FileID, unsigned>> IncludedLocMap; /// The key value into the IsBeforeInTUCache table. - typedef std::pair<FileID, FileID> IsBeforeInTUCacheKey; + using IsBeforeInTUCacheKey = std::pair<FileID, FileID>; /// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs /// to cache results. - typedef llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry> - InBeforeInTUCache; + using InBeforeInTUCache = + llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry>; /// Cache results for the isBeforeInTranslationUnit method. mutable InBeforeInTUCache IBTUCache; @@ -712,7 +704,7 @@ class SourceManager : public RefCountedBase<SourceManager> { /// \brief Lazily computed map of macro argument chunks to their expanded /// source location. - typedef std::map<unsigned, SourceLocation> MacroArgsMap; + using MacroArgsMap = std::map<unsigned, SourceLocation>; mutable llvm::DenseMap<FileID, std::unique_ptr<MacroArgsMap>> MacroArgsCacheMap; @@ -816,7 +808,22 @@ public: SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { - return createFileID(createMemBufferContentCache(std::move(Buffer)), + return createFileID( + createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false), + IncludeLoc, FileCharacter, LoadedID, LoadedOffset); + } + + enum UnownedTag { Unowned }; + + /// \brief Create a new FileID that represents the specified memory buffer. + /// + /// This does no caching of the buffer and takes ownership of the + /// MemoryBuffer, so only pass a MemoryBuffer to this once. + FileID createFileID(UnownedTag, llvm::MemoryBuffer *Buffer, + SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, + int LoadedID = 0, unsigned LoadedOffset = 0, + SourceLocation IncludeLoc = SourceLocation()) { + return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true), IncludeLoc, FileCharacter, LoadedID, LoadedOffset); } @@ -1408,7 +1415,6 @@ public: //===--------------------------------------------------------------------===// /// \brief Return the uniqued ID for the specified filename. - /// unsigned getLineTableFilenameID(StringRef Str); /// \brief Add a line note to the line table for the FileID and offset @@ -1520,9 +1526,18 @@ public: return LHSLoaded; } + /// Return true if the Point is within Start and End. + bool isPointWithin(SourceLocation Location, SourceLocation Start, + SourceLocation End) const { + return Location == Start || Location == End || + (isBeforeInTranslationUnit(Start, Location) && + isBeforeInTranslationUnit(Location, End)); + } + // Iterators over FileInfos. - typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> - ::const_iterator fileinfo_iterator; + using fileinfo_iterator = + llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::const_iterator; + fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } bool hasFileInfo(const FileEntry *File) const { @@ -1530,7 +1545,6 @@ public: } /// \brief Print statistics to stderr. - /// void PrintStats() const; void dump() const; @@ -1621,6 +1635,9 @@ public: } private: + friend class ASTReader; + friend class ASTWriter; + llvm::MemoryBuffer *getFakeBufferForRecovery() const; const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const; @@ -1691,7 +1708,7 @@ private: /// \brief Create a new ContentCache for the specified memory buffer. const SrcMgr::ContentCache * - createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf); + createMemBufferContentCache(llvm::MemoryBuffer *Buf, bool DoNotFree); FileID getFileIDSlow(unsigned SLocOffset) const; FileID getFileIDLocal(unsigned SLocOffset) const; @@ -1712,8 +1729,6 @@ private: SourceLocation SpellLoc, SourceLocation ExpansionLoc, unsigned ExpansionLength) const; - friend class ASTReader; - friend class ASTWriter; }; /// \brief Comparison function object. @@ -1726,7 +1741,7 @@ class BeforeThanCompare<SourceLocation> { SourceManager &SM; public: - explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } + explicit BeforeThanCompare(SourceManager &SM) : SM(SM) {} bool operator()(SourceLocation LHS, SourceLocation RHS) const { return SM.isBeforeInTranslationUnit(LHS, RHS); @@ -1739,13 +1754,13 @@ class BeforeThanCompare<SourceRange> { SourceManager &SM; public: - explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } + explicit BeforeThanCompare(SourceManager &SM) : SM(SM) {} bool operator()(SourceRange LHS, SourceRange RHS) const { return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin()); } }; -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_BASIC_SOURCEMANAGER_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h index 9403dea8889c2..edd910e704128 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h @@ -1,4 +1,4 @@ -//===--- SourceManagerInternals.h - SourceManager Internals -----*- C++ -*-===// +//===- SourceManagerInternals.h - SourceManager Internals -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines implementation details of the clang::SourceManager class. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H @@ -18,7 +18,11 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include <cassert> #include <map> +#include <vector> namespace clang { @@ -86,7 +90,8 @@ class LineTableInfo { /// \brief Map from FileIDs to a list of line entries (sorted by the offset /// at which they occur in the file). - std::map<FileID, std::vector<LineEntry> > LineEntries; + std::map<FileID, std::vector<LineEntry>> LineEntries; + public: void clear() { FilenameIDs.clear(); @@ -95,10 +100,12 @@ public: } unsigned getLineTableFilenameID(StringRef Str); + StringRef getFilename(unsigned ID) const { assert(ID < FilenamesByID.size() && "Invalid FilenameID"); return FilenamesByID[ID]->getKey(); } + unsigned getNumFilenames() const { return FilenamesByID.size(); } void AddLineNote(FileID FID, unsigned Offset, @@ -112,7 +119,8 @@ public: const LineEntry *FindNearestLineEntry(FileID FID, unsigned Offset); // Low-level access - typedef std::map<FileID, std::vector<LineEntry> >::iterator iterator; + using iterator = std::map<FileID, std::vector<LineEntry>>::iterator; + iterator begin() { return LineEntries.begin(); } iterator end() { return LineEntries.end(); } @@ -121,6 +129,6 @@ public: void AddEntry(FileID FID, const std::vector<LineEntry> &Entries); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_SOURCEMANAGERINTERNALS_H diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h index 50fb936e01d1f..377534baab06b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h @@ -52,6 +52,7 @@ namespace clang { TST_int, TST_int128, TST_half, // OpenCL half, ARM NEON __fp16 + TST_Float16, // C11 extension ISO/IEC TS 18661-3 TST_float, TST_double, TST_float128, diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SyncScope.h b/contrib/llvm/tools/clang/include/clang/Basic/SyncScope.h new file mode 100644 index 0000000000000..09ac0052185af --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/SyncScope.h @@ -0,0 +1,154 @@ +//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides definitions for the atomic synchronization scopes. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H +#define LLVM_CLANG_BASIC_SYNCSCOPE_H + +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <memory> + +namespace clang { + +/// \brief Defines synch scope values used internally by clang. +/// +/// The enum values start from 0 and are contiguous. They are mainly used for +/// enumerating all supported synch scope values and mapping them to LLVM +/// synch scopes. Their numerical values may be different from the corresponding +/// synch scope enums used in source languages. +/// +/// In atomic builtin and expressions, language-specific synch scope enums are +/// used. Currently only OpenCL memory scope enums are supported and assumed +/// to be used by all languages. However, in the future, other languages may +/// define their own set of synch scope enums. The language-specific synch scope +/// values are represented by class AtomicScopeModel and its derived classes. +/// +/// To add a new enum value: +/// Add the enum value to enum class SyncScope. +/// Update enum value Last if necessary. +/// Update getAsString. +/// +enum class SyncScope { + OpenCLWorkGroup, + OpenCLDevice, + OpenCLAllSVMDevices, + OpenCLSubGroup, + Last = OpenCLSubGroup +}; + +inline llvm::StringRef getAsString(SyncScope S) { + switch (S) { + case SyncScope::OpenCLWorkGroup: + return "opencl_workgroup"; + case SyncScope::OpenCLDevice: + return "opencl_device"; + case SyncScope::OpenCLAllSVMDevices: + return "opencl_allsvmdevices"; + case SyncScope::OpenCLSubGroup: + return "opencl_subgroup"; + } + llvm_unreachable("Invalid synch scope"); +} + +/// \brief Defines the kind of atomic scope models. +enum class AtomicScopeModelKind { None, OpenCL }; + +/// \brief Defines the interface for synch scope model. +class AtomicScopeModel { +public: + virtual ~AtomicScopeModel() {} + /// \brief Maps language specific synch scope values to internal + /// SyncScope enum. + virtual SyncScope map(unsigned S) const = 0; + + /// \brief Check if the compile-time constant synch scope value + /// is valid. + virtual bool isValid(unsigned S) const = 0; + + /// \brief Get all possible synch scope values that might be + /// encountered at runtime for the current language. + virtual ArrayRef<unsigned> getRuntimeValues() const = 0; + + /// \brief If atomic builtin function is called with invalid + /// synch scope value at runtime, it will fall back to a valid + /// synch scope value returned by this function. + virtual unsigned getFallBackValue() const = 0; + + /// \brief Create an atomic scope model by AtomicScopeModelKind. + /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. + static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K); +}; + +/// \brief Defines the synch scope model for OpenCL. +class AtomicScopeOpenCLModel : public AtomicScopeModel { +public: + /// The enum values match the pre-defined macros + /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* + /// enums in opencl-c.h. + enum ID { + WorkGroup = 1, + Device = 2, + AllSVMDevices = 3, + SubGroup = 4, + Last = SubGroup + }; + + AtomicScopeOpenCLModel() {} + + SyncScope map(unsigned S) const override { + switch (static_cast<ID>(S)) { + case WorkGroup: + return SyncScope::OpenCLWorkGroup; + case Device: + return SyncScope::OpenCLDevice; + case AllSVMDevices: + return SyncScope::OpenCLAllSVMDevices; + case SubGroup: + return SyncScope::OpenCLSubGroup; + } + llvm_unreachable("Invalid language synch scope value"); + } + + bool isValid(unsigned S) const override { + return S >= static_cast<unsigned>(WorkGroup) && + S <= static_cast<unsigned>(Last); + } + + ArrayRef<unsigned> getRuntimeValues() const override { + static_assert(Last == SubGroup, "Does not include all synch scopes"); + static const unsigned Scopes[] = { + static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device), + static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)}; + return llvm::makeArrayRef(Scopes); + } + + unsigned getFallBackValue() const override { + return static_cast<unsigned>(AllSVMDevices); + } +}; + +inline std::unique_ptr<AtomicScopeModel> +AtomicScopeModel::create(AtomicScopeModelKind K) { + switch (K) { + case AtomicScopeModelKind::None: + return std::unique_ptr<AtomicScopeModel>{}; + case AtomicScopeModelKind::OpenCL: + return llvm::make_unique<AtomicScopeOpenCLModel>(); + } + llvm_unreachable("Invalid atomic scope model kind"); +} +} + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h index d1a9ea85dbe96..6ba58779114f5 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h @@ -59,6 +59,7 @@ protected: // values are specified by the TargetInfo constructor. bool BigEndian; bool TLSSupported; + bool VLASupported; bool NoAsmVariants; // True if {|} are normal characters. bool HasFloat128; unsigned char PointerWidth, PointerAlign; @@ -85,7 +86,7 @@ protected: *LongDoubleFormat, *Float128Format; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI TheCXXABI; - const LangAS::Map *AddrSpaceMap; + const LangASMap *AddrSpaceMap; mutable StringRef PlatformName; mutable VersionTuple PlatformMinVersion; @@ -247,6 +248,9 @@ public: IntType getPtrDiffType(unsigned AddrSpace) const { return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace); } + IntType getUnsignedPtrDiffType(unsigned AddrSpace) const { + return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace)); + } IntType getIntPtrType() const { return IntPtrType; } IntType getUIntPtrType() const { return getCorrespondingUnsignedType(IntPtrType); @@ -318,9 +322,7 @@ public: /// \brief Get integer value for null pointer. /// \param AddrSpace address space of pointee in source language. - virtual uint64_t getNullPointerValue(unsigned AddrSpace) const { - return 0; - } + virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; } /// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } @@ -447,6 +449,9 @@ public: /// \brief Return the maximum width lock-free atomic operation which can be /// inlined given the supported features of the given target. unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } + /// \brief Set the maximum inline or promote width lock-free atomic operation + /// for the given target. + virtual void setMaxAtomicWidth() {} /// \brief Returns true if the given target supports lock-free atomic /// operations at the specified width and alignment. virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, @@ -464,21 +469,6 @@ public: /// types for the given target. unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; } - /// Return the alignment (in bits) of the thrown exception object. This is - /// only meaningful for targets that allocate C++ exceptions in a system - /// runtime, such as those using the Itanium C++ ABI. - virtual unsigned getExnObjectAlignment() const { - // Itanium says that an _Unwind_Exception has to be "double-word" - // aligned (and thus the end of it is also so-aligned), meaning 16 - // bytes. Of course, that was written for the actual Itanium, - // which is a 64-bit platform. Classically, the ABI doesn't really - // specify the alignment on other platforms, but in practice - // libUnwind declares the struct with __attribute__((aligned)), so - // we assume that alignment here. (It's generally 16 bytes, but - // some targets overwrite it.) - return getDefaultAlignForAttributeAligned(); - } - /// \brief Return the size of intmax_t and uintmax_t for this target, in bits. unsigned getIntMaxTWidth() const { return getTypeWidth(IntMaxType); @@ -569,6 +559,14 @@ public: return ComplexLongDoubleUsesFP2Ret; } + /// Check whether llvm intrinsics such as llvm.convert.to.fp16 should be used + /// to convert to and from __fp16. + /// FIXME: This function should be removed once all targets stop using the + /// conversion intrinsics. + virtual bool useFP16ConversionIntrinsics() const { + return true; + } + /// \brief Specify if mangling based on address space map should be used or /// not for language specific address spaces bool useAddressSpaceMapMangling() const { @@ -869,6 +867,11 @@ public: return false; } + /// brief Determine whether this TargetInfo supports the given CPU name. + virtual bool isValidCPUName(StringRef Name) const { + return true; + } + /// \brief Use the specified ABI. /// /// \return False on error (invalid ABI name). @@ -891,6 +894,11 @@ public: Features[Name] = Enabled; } + /// \brief Determine whether this TargetInfo supports the given feature. + virtual bool isValidFeatureName(StringRef Feature) const { + return true; + } + /// \brief Perform initialization based on the user configured /// set of features (e.g., +sse4). /// @@ -916,6 +924,10 @@ public: // argument. virtual bool validateCpuSupports(StringRef Name) const { return false; } + // \brief Validate the contents of the __builtin_cpu_is(const char*) + // argument. + virtual bool validateCpuIs(StringRef Name) const { return false; } + // \brief Returns maximal number of args passed in registers. unsigned getRegParmMax() const { assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); @@ -935,6 +947,9 @@ public: return MaxTLSAlign; } + /// \brief Whether target supports variable-length arrays. + bool isVLASupported() const { return VLASupported; } + /// \brief Whether the target supports SEH __try. bool isSEHTrySupported() const { return getTriple().isOSWindows() && @@ -965,15 +980,13 @@ public: return nullptr; } - const LangAS::Map &getAddressSpaceMap() const { - return *AddrSpaceMap; - } + const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; } /// \brief Return an AST address space which can be used opportunistically /// for constant global memory. It must be possible to convert pointers into /// this address space to LangAS::Default. If no such address space exists, /// this may return None, and such optimizations will be disabled. - virtual llvm::Optional<unsigned> getConstantAddressSpace() const { + virtual llvm::Optional<LangAS> getConstantAddressSpace() const { return LangAS::Default; } @@ -1051,10 +1064,19 @@ public: return getTargetOpts().SupportedOpenCLOptions; } - /// \brief Get OpenCL image type address space. - virtual LangAS::ID getOpenCLImageAddrSpace() const { - return LangAS::opencl_global; - } + enum OpenCLTypeKind { + OCLTK_Default, + OCLTK_ClkEvent, + OCLTK_Event, + OCLTK_Image, + OCLTK_Pipe, + OCLTK_Queue, + OCLTK_ReserveID, + OCLTK_Sampler, + }; + + /// \brief Get address space for OpenCL type. + virtual LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const; /// \returns Target specific vtbl ptr address space. virtual unsigned getVtblPtrAddressSpace() const { diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h index 9bb19c7b79df0..60becfb8ee76e 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h @@ -54,8 +54,6 @@ public: /// be a list of strings starting with by '+' or '-'. std::vector<std::string> Features; - std::vector<std::string> Reciprocals; - /// Supported OpenCL extensions and optional core features. OpenCLOptions SupportedOpenCLOptions; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def index be67663a1015c..6ae8821a834d0 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def @@ -27,8 +27,11 @@ #ifndef CXX11_KEYWORD #define CXX11_KEYWORD(X,Y) KEYWORD(X,KEYCXX11|(Y)) #endif +#ifndef CXX2A_KEYWORD +#define CXX2A_KEYWORD(X,Y) KEYWORD(X,KEYCXX2A|(Y)) +#endif #ifndef CONCEPTS_KEYWORD -#define CONCEPTS_KEYWORD(X) KEYWORD(X,KEYCONCEPTS) +#define CONCEPTS_KEYWORD(X) CXX2A_KEYWORD(X,KEYCONCEPTS) #endif #ifndef MODULES_KEYWORD #define MODULES_KEYWORD(X) KEYWORD(X,KEYMODULES) @@ -142,7 +145,7 @@ TOK(numeric_constant) // 0x123 TOK(char_constant) // 'a' TOK(wide_char_constant) // L'b' -// C++1z Character Constants +// C++17 Character Constants TOK(utf8_char_constant) // u8'a' // C++11 Character Constants @@ -191,6 +194,7 @@ PUNCTUATOR(less, "<") PUNCTUATOR(lessless, "<<") PUNCTUATOR(lessequal, "<=") PUNCTUATOR(lesslessequal, "<<=") +PUNCTUATOR(spaceship, "<=>") PUNCTUATOR(greater, ">") PUNCTUATOR(greatergreater, ">>") PUNCTUATOR(greaterequal, ">=") @@ -236,6 +240,7 @@ PUNCTUATOR(caretcaret, "^^") // implementation namespace // KEYNOCXX - This is a keyword in every non-C++ dialect. // KEYCXX11 - This is a C++ keyword introduced to C++ in C++11 +// KEYCXX2A - This is a C++ keyword introduced to C++ in C++2a // KEYCONCEPTS - This is a keyword if the C++ extensions for concepts // are enabled. // KEYMODULES - This is a keyword if the C++ extensions for modules @@ -362,7 +367,7 @@ CXX11_KEYWORD(nullptr , 0) CXX11_KEYWORD(static_assert , 0) CXX11_KEYWORD(thread_local , 0) -// C++ concepts TS keywords +// C++2a / concepts TS keywords CONCEPTS_KEYWORD(concept) CONCEPTS_KEYWORD(requires) @@ -375,6 +380,9 @@ KEYWORD(co_yield , KEYCOROUTINES) MODULES_KEYWORD(module) MODULES_KEYWORD(import) +// C11 Extension +KEYWORD(_Float16 , KEYALL) + // GNU Extensions (in impl-reserved namespace) KEYWORD(_Decimal32 , KEYALL) KEYWORD(_Decimal64 , KEYALL) @@ -390,6 +398,7 @@ TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX) KEYWORD(__builtin_va_arg , KEYALL) KEYWORD(__extension__ , KEYALL) KEYWORD(__float128 , KEYALL) +ALIAS("_Float128", __float128 , KEYNOCXX) KEYWORD(__imag , KEYALL) KEYWORD(__int128 , KEYALL) KEYWORD(__label__ , KEYALL) @@ -448,6 +457,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX) TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX) TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX) TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) +TYPE_TRAIT_1(__has_unique_object_representations, + HasUniqueObjectRepresentations, KEYCXX) // Clang-only C++ Type Traits TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) @@ -810,6 +821,7 @@ ANNOTATION(module_end) #undef TYPE_TRAIT_1 #undef TYPE_TRAIT #undef CONCEPTS_KEYWORD +#undef CXX2A_KEYWORD #undef CXX11_KEYWORD #undef KEYWORD #undef PUNCTUATOR diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h index 6aadf795d82e5..8ecd63f9c3cbb 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h @@ -70,7 +70,8 @@ namespace clang { UTT_IsUnsigned, UTT_IsVoid, UTT_IsVolatile, - UTT_Last = UTT_IsVolatile, + UTT_HasUniqueObjectRepresentations, + UTT_Last = UTT_HasUniqueObjectRepresentations, BTT_IsBaseOf, BTT_IsConvertible, BTT_IsConvertibleTo, diff --git a/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h index e52b345e286c6..245452dd12b57 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h @@ -319,16 +319,30 @@ public: explicit InMemoryFileSystem(bool UseNormalizedPaths = true); ~InMemoryFileSystem() override; - /// Add a buffer to the VFS with a path. The VFS owns the buffer. - /// \return true if the file was successfully added, false if the file already - /// exists in the file system with different contents. + /// Add a file containing a buffer or a directory to the VFS with a + /// path. The VFS owns the buffer. If present, User, Group, Type + /// and Perms apply to the newly-created file or directory. + /// \return true if the file or directory was successfully added, + /// false if the file or directory already exists in the file system with + /// different contents. bool addFile(const Twine &Path, time_t ModificationTime, - std::unique_ptr<llvm::MemoryBuffer> Buffer); + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User = None, Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); /// Add a buffer to the VFS with a path. The VFS does not own the buffer. - /// \return true if the file was successfully added, false if the file already - /// exists in the file system with different contents. + /// If present, User, Group, Type and Perms apply to the newly-created file + /// or directory. + /// \return true if the file or directory was successfully added, + /// false if the file or directory already exists in the file system with + /// different contents. bool addFileNoOwn(const Twine &Path, time_t ModificationTime, - llvm::MemoryBuffer *Buffer); + llvm::MemoryBuffer *Buffer, + Optional<uint32_t> User = None, + Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); + std::string toString() const; /// Return true if this file system normalizes . and .. in paths. bool useNormalizedPaths() const { return UseNormalizedPaths; } diff --git a/contrib/llvm/tools/clang/include/clang/Basic/X86Target.def b/contrib/llvm/tools/clang/include/clang/Basic/X86Target.def new file mode 100644 index 0000000000000..21550fe2dd55f --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Basic/X86Target.def @@ -0,0 +1,232 @@ +//===--- X86Target.def - X86 Feature/Processor Database ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the X86-specific Features and Processors, as used by +// the X86 Targets. +// +//===----------------------------------------------------------------------===// + + +#ifndef PROC +#define PROC(ENUM, STRING, IS64BIT) +#endif + +#ifndef PROC_ALIAS +#define PROC_ALIAS(ENUM, ALIAS) +#endif + +#define PROC_64_BIT true +#define PROC_32_BIT false + +/// \name i386 +/// i386-generation processors. +//@{ +PROC(i386, "i386", PROC_32_BIT) +//@} + +/// \name i486 +/// i486-generation processors. +//@{ +PROC(i486, "i486", PROC_32_BIT) +PROC(WinChipC6, "winchip-c6", PROC_32_BIT) +PROC(WinChip2, "winchip2", PROC_32_BIT) +PROC(C3, "c3", PROC_32_BIT) +//@} + +/// \name i586 +/// i586-generation processors, P5 microarchitecture based. +//@{ +PROC(i586, "i586", PROC_32_BIT) +PROC(Pentium, "pentium", PROC_32_BIT) +PROC(PentiumMMX, "pentium-mmx", PROC_32_BIT) +//@} + +/// \name i686 +/// i686-generation processors, P6 / Pentium M microarchitecture based. +//@{ +PROC(PentiumPro, "pentiumpro", PROC_32_BIT) +PROC_ALIAS(PentiumPro, "i686") +PROC(Pentium2, "pentium2", PROC_32_BIT) +PROC(Pentium3, "pentium3", PROC_32_BIT) +PROC_ALIAS(Pentium3, "pentium3m") +PROC(PentiumM, "pentium-m", PROC_32_BIT) +PROC(C3_2, "c3-2", PROC_32_BIT) + +/// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. +/// Clang however has some logic to support this. +// FIXME: Warn, deprecate, and potentially remove this. +PROC(Yonah, "yonah", PROC_32_BIT) +//@} + +/// \name Netburst +/// Netburst microarchitecture based processors. +//@{ +PROC(Pentium4, "pentium4", PROC_32_BIT) +PROC_ALIAS(Pentium4, "pentium4m") + +PROC(Prescott, "prescott", PROC_32_BIT) +PROC(Nocona, "nocona", PROC_64_BIT) +//@} + +/// \name Core +/// Core microarchitecture based processors. +//@{ +PROC(Core2, "core2", PROC_64_BIT) + +/// This enumerator, like Yonah, is a bit odd. It is another +/// codename which GCC no longer accepts as an option to -march, but Clang +/// has some logic for recognizing it. +// FIXME: Warn, deprecate, and potentially remove this. +PROC(Penryn, "penryn", PROC_64_BIT) +//@} + +/// \name Atom +/// Atom processors +//@{ +PROC(Bonnell, "bonnell", PROC_64_BIT) +PROC_ALIAS(Bonnell, "atom") + +PROC(Silvermont, "silvermont", PROC_64_BIT) +PROC_ALIAS(Silvermont, "slm") + +PROC(Goldmont, "goldmont", PROC_64_BIT) +//@} + +/// \name Nehalem +/// Nehalem microarchitecture based processors. +PROC(Nehalem, "nehalem", PROC_64_BIT) +PROC_ALIAS(Nehalem, "corei7") + +/// \name Westmere +/// Westmere microarchitecture based processors. +PROC(Westmere, "westmere", PROC_64_BIT) + +/// \name Sandy Bridge +/// Sandy Bridge microarchitecture based processors. +PROC(SandyBridge, "sandybridge", PROC_64_BIT) +PROC_ALIAS(SandyBridge, "corei7-avx") + +/// \name Ivy Bridge +/// Ivy Bridge microarchitecture based processors. +PROC(IvyBridge, "ivybridge", PROC_64_BIT) +PROC_ALIAS(IvyBridge, "core-avx-i") + +/// \name Haswell +/// Haswell microarchitecture based processors. +PROC(Haswell, "haswell", PROC_64_BIT) +PROC_ALIAS(Haswell, "core-avx2") + +/// \name Broadwell +/// Broadwell microarchitecture based processors. +PROC(Broadwell, "broadwell", PROC_64_BIT) + +/// \name Skylake Client +/// Skylake client microarchitecture based processors. +PROC(SkylakeClient, "skylake", PROC_64_BIT) + +/// \name Skylake Server +/// Skylake server microarchitecture based processors. +PROC(SkylakeServer, "skylake-avx512", PROC_64_BIT) +PROC_ALIAS(SkylakeServer, "skx") + +/// \name Cannonlake Client +/// Cannonlake client microarchitecture based processors. +PROC(Cannonlake, "cannonlake", PROC_64_BIT) + +/// \name Icelake Client +/// Icelake client microarchitecture based processors. +PROC(Icelake, "icelake", PROC_64_BIT) + +/// \name Knights Landing +/// Knights Landing processor. +PROC(KNL, "knl", PROC_64_BIT) + +/// \name Knights Mill +/// Knights Mill processor. +PROC(KNM, "knm", PROC_64_BIT) + +/// \name Lakemont +/// Lakemont microarchitecture based processors. +PROC(Lakemont, "lakemont", PROC_32_BIT) + +/// \name K6 +/// K6 architecture processors. +//@{ +PROC(K6, "k6", PROC_32_BIT) +PROC(K6_2, "k6-2", PROC_32_BIT) +PROC(K6_3, "k6-3", PROC_32_BIT) +//@} + +/// \name K7 +/// K7 architecture processors. +//@{ +PROC(Athlon, "athlon", PROC_32_BIT) +PROC_ALIAS(Athlon, "athlon-tbird") + +PROC(AthlonXP, "athlon-xp", PROC_32_BIT) +PROC_ALIAS(AthlonXP, "athlon-mp") +PROC_ALIAS(AthlonXP, "athlon-4") +//@} + +/// \name K8 +/// K8 architecture processors. +//@{ +PROC(K8, "k8", PROC_64_BIT) +PROC_ALIAS(K8, "athlon64") +PROC_ALIAS(K8, "athlon-fx") +PROC_ALIAS(K8, "opteron") + +PROC(K8SSE3, "k8-sse3", PROC_64_BIT) +PROC_ALIAS(K8SSE3, "athlon64-sse3") +PROC_ALIAS(K8SSE3, "opteron-sse3") + +PROC(AMDFAM10, "amdfam10", PROC_64_BIT) +PROC_ALIAS(AMDFAM10, "barcelona") +//@} + +/// \name Bobcat +/// Bobcat architecture processors. +//@{ +PROC(BTVER1, "btver1", PROC_64_BIT) +PROC(BTVER2, "btver2", PROC_64_BIT) +//@} + +/// \name Bulldozer +/// Bulldozer architecture processors. +//@{ +PROC(BDVER1, "bdver1", PROC_64_BIT) +PROC(BDVER2, "bdver2", PROC_64_BIT) +PROC(BDVER3, "bdver3", PROC_64_BIT) +PROC(BDVER4, "bdver4", PROC_64_BIT) +//@} + +/// \name zen +/// Zen architecture processors. +//@{ +PROC(ZNVER1, "znver1", PROC_64_BIT) +//@} + +/// This specification is deprecated and will be removed in the future. +/// Users should prefer K8. +// FIXME: Warn on this when the CPU is set to it. +//@{ +PROC(x86_64, "x86-64", PROC_64_BIT) +//@} + +/// \name Geode +/// Geode processors. +//@{ +PROC(Geode, "geode", PROC_32_BIT) +//@} + + +#undef PROC_64_BIT +#undef PROC_32_BIT +#undef PROC +#undef PROC_ALIAS diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h index 615e55c8b69f8..53619fa8ef65b 100644 --- a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -72,12 +72,19 @@ const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM, FunctionType::ExtInfo info, RequiredArgs args); -// Returns null if the function type is incomplete and can't be lowered. +/// Returns null if the function type is incomplete and can't be lowered. llvm::FunctionType *convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD); llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); +/// Given a non-bitfield struct field, return its index within the elements of +/// the struct's converted type. The returned index refers to a field number in +/// the complete object type which is returned by convertTypeForMemory. FD must +/// be a field in RD directly (i.e. not an inherited field). +unsigned getLLVMFieldNumber(CodeGenModule &CGM, + const RecordDecl *RD, const FieldDecl *FD); + } // end namespace CodeGen } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h index ef1a5d2f49af7..f1a7e2264fc6b 100644 --- a/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h @@ -31,8 +31,7 @@ class ConstantInitBuilderBase; } namespace llvm { template <> -class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> { -public: +struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> { using T = ::clang::CodeGen::ConstantInitBuilderBase*; static inline void *getAsVoidPointer(T p) { return p; } @@ -93,8 +92,7 @@ public: namespace llvm { template <> -class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> { -public: +struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> { using T = ::clang::CodeGen::ConstantInitFuture; static inline void *getAsVoidPointer(T future) { diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h index 6f81ea9d6370b..e110f6fd30c1e 100644 --- a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h @@ -84,6 +84,10 @@ public: /// code generator will schedule the entity for emission if a /// definition has been registered with this code generator. llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition); + + /// Create a new \c llvm::Module after calling HandleTranslationUnit. This + /// enable codegen in interactive processing environments. + llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C); }; /// CreateLLVMCodeGen - Create a CodeGenerator instance. diff --git a/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTUDiagnostic.h b/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTUDiagnostic.h new file mode 100644 index 0000000000000..dad38309fd1ad --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTUDiagnostic.h @@ -0,0 +1,29 @@ +//===--- CrossTUDiagnostic.h - Diagnostics for Cross TU ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CROSSTU_CROSSTUDIAGNOSTIC_H +#define LLVM_CLANG_CROSSTU_CROSSTUDIAGNOSTIC_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 CROSSTUSTART +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#undef DIAG + NUM_BUILTIN_CROSSTU_DIAGNOSTICS +}; +} // end namespace diag +} // end namespace clang + +#endif // LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H diff --git a/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTranslationUnit.h b/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTranslationUnit.h new file mode 100644 index 0000000000000..f2a1690250090 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/CrossTU/CrossTranslationUnit.h @@ -0,0 +1,159 @@ +//===--- CrossTranslationUnit.h - -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an interface to load binary AST dumps on demand. This +// feature can be utilized for tools that require cross translation unit +// support. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H +#define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Error.h" + +namespace clang { +class CompilerInstance; +class ASTContext; +class ASTImporter; +class ASTUnit; +class DeclContext; +class FunctionDecl; +class NamedDecl; +class TranslationUnitDecl; + +namespace cross_tu { + +enum class index_error_code { + unspecified = 1, + missing_index_file, + invalid_index_format, + multiple_definitions, + missing_definition, + failed_import, + failed_to_get_external_ast, + failed_to_generate_usr +}; + +class IndexError : public llvm::ErrorInfo<IndexError> { +public: + static char ID; + IndexError(index_error_code C) : Code(C), LineNo(0) {} + IndexError(index_error_code C, std::string FileName, int LineNo = 0) + : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {} + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + index_error_code getCode() const { return Code; } + int getLineNum() const { return LineNo; } + std::string getFileName() const { return FileName; } + +private: + index_error_code Code; + std::string FileName; + int LineNo; +}; + +/// \brief This function parses an index file that determines which +/// translation unit contains which definition. +/// +/// The index file format is the following: +/// each line consists of an USR and a filepath separated by a space. +/// +/// \return Returns a map where the USR is the key and the filepath is the value +/// or an error. +llvm::Expected<llvm::StringMap<std::string>> +parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir); + +std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index); + +/// \brief This class is used for tools that requires cross translation +/// unit capability. +/// +/// This class can load function definitions from external AST files. +/// The loaded definition will be merged back to the original AST using the +/// AST Importer. +/// In order to use this class, an index file is required that describes +/// the locations of the AST files for each function definition. +/// +/// Note that this class also implements caching. +class CrossTranslationUnitContext { +public: + CrossTranslationUnitContext(CompilerInstance &CI); + ~CrossTranslationUnitContext(); + + /// \brief This function loads a function definition from an external AST + /// file and merge it into the original AST. + /// + /// This method should only be used on functions that have no definitions in + /// the current translation unit. A function definition with the same + /// declaration will be looked up in the index file which should be in the + /// \p CrossTUDir directory, called \p IndexName. In case the declaration is + /// found in the index the corresponding AST file will be loaded and the + /// definition of the function will be merged into the original AST using + /// the AST Importer. + /// + /// \return The declaration with the definition will be returned. + /// If no suitable definition is found in the index file or multiple + /// definitions found error will be returned. + /// + /// Note that the AST files should also be in the \p CrossTUDir. + llvm::Expected<const FunctionDecl *> + getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, + StringRef IndexName); + + /// \brief This function loads a function definition from an external AST + /// file. + /// + /// A function definition with the same declaration will be looked up in the + /// index file which should be in the \p CrossTUDir directory, called + /// \p IndexName. In case the declaration is found in the index the + /// corresponding AST file will be loaded. + /// + /// \return Returns an ASTUnit that contains the definition of the looked up + /// function. + /// + /// Note that the AST files should also be in the \p CrossTUDir. + llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName, + StringRef CrossTUDir, + StringRef IndexName); + + /// \brief This function merges a definition from a separate AST Unit into + /// the current one which was created by the compiler instance that + /// was passed to the constructor. + /// + /// \return Returns the resulting definition or an error. + llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD); + + /// \brief Get a name to identify a function. + static std::string getLookupName(const NamedDecl *ND); + + /// \brief Emit diagnostics for the user for potential configuration errors. + void emitCrossTUDiagnostics(const IndexError &IE); + +private: + ASTImporter &getOrCreateASTImporter(ASTContext &From); + const FunctionDecl *findFunctionInDeclContext(const DeclContext *DC, + StringRef LookupFnName); + + llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap; + llvm::StringMap<clang::ASTUnit *> FunctionASTUnitMap; + llvm::StringMap<std::string> FunctionFileMap; + llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>> + ASTUnitImporterMap; + CompilerInstance &CI; + ASTContext &Context; +}; + +} // namespace cross_tu +} // namespace clang + +#endif // LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td index 205f36b723c87..7dea88b62cc19 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td @@ -70,7 +70,7 @@ def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-neste def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">; def analyze_function : Separate<["-"], "analyze-function">, - HelpText<"Run analysis on specific function">; + HelpText<"Run analysis on specific function (for C++ include parameters in name)">; def analyze_function_EQ : Joined<["-"], "analyze-function=">, Alias<analyze_function>; def analyzer_eagerly_assume : Flag<["-"], "analyzer-eagerly-assume">, HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; @@ -99,7 +99,19 @@ def analyzer_stats : Flag<["-"], "analyzer-stats">, HelpText<"Print internal analyzer statistics.">; def analyzer_checker : Separate<["-"], "analyzer-checker">, - HelpText<"Choose analyzer checkers to enable">; + HelpText<"Choose analyzer checkers to enable">, + ValuesCode<[{ + const char *Values = + #define GET_CHECKERS + #define CHECKER(FULLNAME, CLASS, DESCFILE, HT, G, H) FULLNAME "," + #include "clang/StaticAnalyzer/Checkers/Checkers.inc" + #undef GET_CHECKERS + #define GET_PACKAGES + #define PACKAGE(FULLNAME, G, D) FULLNAME "," + #include "clang/StaticAnalyzer/Checkers/Checkers.inc" + #undef GET_PACKAGES + ; + }]>; def analyzer_checker_EQ : Joined<["-"], "analyzer-checker=">, Alias<analyzer_checker>; @@ -188,6 +200,12 @@ def arange_sections : Flag<["-"], "arange_sections">, def dwarf_ext_refs : Flag<["-"], "dwarf-ext-refs">, HelpText<"Generate debug info with external references to clang modules" " or precompiled headers">; +def dwarf_explicit_import : Flag<["-"], "dwarf-explicit-import">, + HelpText<"Generate explicit import from anonymous namespace to containing" + " scope">; +def debug_forward_template_params : Flag<["-"], "debug-forward-template-params">, + HelpText<"Emit complete descriptions of template parameters in forward" + " declarations">; def fforbid_guard_variables : Flag<["-"], "fforbid-guard-variables">, HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; def no_implicit_float : Flag<["-"], "no-implicit-float">, @@ -226,6 +244,8 @@ def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">, HelpText<"Turn off Type Based Alias Analysis">; def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">, HelpText<"Turn off struct-path aware Type Based Alias Analysis">; +def new_struct_path_tbaa : Flag<["-"], "new-struct-path-tbaa">, + HelpText<"Enable enhanced struct-path aware Type Based Alias Analysis">; def masm_verbose : Flag<["-"], "masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<["-"], "mcode-model">, @@ -243,8 +263,12 @@ def menable_no_nans : Flag<["-"], "menable-no-nans">, def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, HelpText<"Allow unsafe floating-point math optimizations which may decrease " "precision">; +def mreassociate : Flag<["-"], "mreassociate">, + HelpText<"Allow reassociation transformations for floating-point instructions">; def mfloat_abi : Separate<["-"], "mfloat-abi">, HelpText<"The float ABI to use">; +def mtp : Separate<["-"], "mtp">, + HelpText<"Mode for reading thread pointer">; def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">, HelpText<"Limit float precision to the given value">; def split_stacks : Flag<["-"], "split-stacks">, @@ -295,6 +319,9 @@ def fsanitize_coverage_8bit_counters def fsanitize_coverage_inline_8bit_counters : Flag<["-"], "fsanitize-coverage-inline-8bit-counters">, HelpText<"Enable inline 8-bit counters in sanitizer coverage">; +def fsanitize_coverage_pc_table + : Flag<["-"], "fsanitize-coverage-pc-table">, + HelpText<"Create a table of coverage-instrumented PCs">; def fsanitize_coverage_trace_pc : Flag<["-"], "fsanitize-coverage-trace-pc">, HelpText<"Enable PC tracing in sanitizer coverage">; @@ -304,6 +331,9 @@ def fsanitize_coverage_trace_pc_guard def fsanitize_coverage_no_prune : Flag<["-"], "fsanitize-coverage-no-prune">, HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">; +def fsanitize_coverage_stack_depth + : Flag<["-"], "fsanitize-coverage-stack-depth">, + HelpText<"Enable max stack depth tracing">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " "or none">, Values<"none,clang,llvm">; @@ -372,8 +402,12 @@ def fcaret_diagnostics_max_lines : HelpText<"Set the maximum number of source lines to show in a caret diagnostic">; def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; +def verify_EQ : CommaJoined<["-"], "verify=">, + MetaVarName<"<prefixes>">, + HelpText<"Verify diagnostic output using comment directives that start with" + " prefixes in the comma-separated sequence <prefixes>">; def verify : Flag<["-"], "verify">, - HelpText<"Verify diagnostic output using comment directives">; + HelpText<"Equivalent to -verify=expected">; def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">, HelpText<"Ignore unexpected diagnostic messages">; def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">, @@ -409,6 +443,8 @@ def code_completion_patterns : Flag<["-"], "code-completion-patterns">, HelpText<"Include code patterns in code-completion results">; def no_code_completion_globals : Flag<["-"], "no-code-completion-globals">, HelpText<"Do not include global declarations in code-completion results.">; +def no_code_completion_ns_level_decls : Flag<["-"], "no-code-completion-ns-level-decls">, + HelpText<"Do not include declarations inside namespaces (incl. global namespace) in the code-completion results.">; def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments">, HelpText<"Include brief documentation comments in code-completion results.">; def disable_free : Flag<["-"], "disable-free">, @@ -678,11 +714,17 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">, HelpText<"Allow function arguments and returns of type half">; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, - HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">; + HelpText<"Set default calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall,regcall">; def finclude_default_header : Flag<["-"], "finclude-default-header">, HelpText<"Include the default header file for OpenCL">; def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">, HelpText<"Preserve 3-component vector type">; +def fwchar_type_EQ : Joined<["-"], "fwchar-type=">, + HelpText<"Select underlying type for wchar_t">, Values<"char,short,int">; +def fsigned_wchar : Flag<["-"], "fsigned-wchar">, + HelpText<"Use a signed type for wchar_t">; +def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">, + HelpText<"Use an unsigned type for wchar_t">; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td index aebb36ed0e2b6..c1f0a89b5dc8f 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td @@ -145,7 +145,8 @@ def _SLASH_W1 : CLFlag<"W1">, HelpText<"Enable -Wall">, Alias<Wall>; def _SLASH_W2 : CLFlag<"W2">, HelpText<"Enable -Wall">, Alias<Wall>; def _SLASH_W3 : CLFlag<"W3">, HelpText<"Enable -Wall">, Alias<Wall>; def _SLASH_W4 : CLFlag<"W4">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>; -def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Wall and -Wextra">, Alias<WCL4>; +def _SLASH_Wall : CLFlag<"Wall">, HelpText<"Enable -Weverything">, + Alias<W_Joined>, AliasArgs<["everything"]>; def _SLASH_WX : CLFlag<"WX">, HelpText<"Treat warnings as errors">, Alias<W_Joined>, AliasArgs<["error"]>; def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">, @@ -153,6 +154,8 @@ def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">, def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias<w>; def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>, AliasArgs<["no-macro-redefined"]>; +def _SLASH_wd4018 : CLFlag<"wd4018">, Alias<W_Joined>, + AliasArgs<["no-sign-compare"]>; def _SLASH_wd4100 : CLFlag<"wd4100">, Alias<W_Joined>, AliasArgs<["no-unused-parameter"]>; def _SLASH_wd4910 : CLFlag<"wd4910">, Alias<W_Joined>, @@ -302,6 +305,8 @@ def _SLASH_Gz : CLFlag<"Gz">, HelpText<"Set __stdcall as a default calling convention">; def _SLASH_Gv : CLFlag<"Gv">, HelpText<"Set __vectorcall as a default calling convention">; +def _SLASH_Gregcall : CLFlag<"Gregcall">, + HelpText<"Set __regcall as a default calling convention">; // Ignored: diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h index 036b04605ac70..89c0def6c57a0 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h @@ -99,8 +99,8 @@ class Compilation { /// only be removed if we crash. ArgStringMap FailureResultFiles; - /// Redirection for stdout, stderr, etc. - const StringRef **Redirects; + /// Optional redirection for stdin, stdout, stderr. + std::vector<Optional<StringRef>> Redirects; /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics; @@ -283,12 +283,10 @@ public: /// Redirect - Redirect output of this compilation. Can only be done once. /// - /// \param Redirects - array of pointers to paths. The array - /// should have a size of three. The inferior process's - /// stdin(0), stdout(1), and stderr(2) will be redirected to the - /// corresponding paths. This compilation instance becomes - /// the owner of Redirects and will delete the array and StringRef's. - void Redirect(const StringRef** Redirects); + /// \param Redirects - array of optional paths. The array should have a size + /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will + /// be redirected to the corresponding paths, if provided (not llvm::None). + void Redirect(ArrayRef<Optional<StringRef>> Redirects); }; } // end namespace driver diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Distro.h b/contrib/llvm/tools/clang/include/clang/Driver/Distro.h index fab49862a442b..4ab4e2ae99370 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Distro.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/Distro.h @@ -26,12 +26,14 @@ public: // NB: Releases of a particular Linux distro should be kept together // in this enum, because some tests are done by integer comparison against // the first and last known member in the family, e.g. IsRedHat(). + AlpineLinux, ArchLinux, DebianLenny, DebianSqueeze, DebianWheezy, DebianJessie, DebianStretch, + DebianBuster, Exherbo, RHEL5, RHEL6, @@ -58,6 +60,7 @@ public: UbuntuYakkety, UbuntuZesty, UbuntuArtful, + UbuntuBionic, UnknownDistro }; @@ -107,11 +110,15 @@ public: } bool IsDebian() const { - return DistroVal >= DebianLenny && DistroVal <= DebianStretch; + return DistroVal >= DebianLenny && DistroVal <= DebianBuster; } bool IsUbuntu() const { - return DistroVal >= UbuntuHardy && DistroVal <= UbuntuArtful; + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuBionic; + } + + bool IsAlpineLinux() const { + return DistroVal == AlpineLinux; } /// @} diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h index 5a087eea1b4ec..a3662872a9531 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h @@ -129,6 +129,9 @@ public: /// The original path to the clang executable. std::string ClangExecutable; + /// Target and driver mode components extracted from clang executable name. + ParsedClangName ClangNameParts; + /// The path to the installed clang directory, if any. std::string InstalledDir; @@ -148,9 +151,6 @@ public: /// Dynamic loader prefix, if present std::string DyldPrefix; - /// If the standard library is used - bool UseStdLib; - /// Driver title to use with help. std::string DriverTitle; @@ -287,6 +287,8 @@ public: void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; } + const std::string &getTitle() { return DriverTitle; } void setTitle(std::string Value) { DriverTitle = std::move(Value); } @@ -423,6 +425,10 @@ public: // FIXME: This should be in CompilationInfo. std::string GetProgramPath(StringRef Name, const ToolChain &TC) const; + /// handleAutocompletions - Handle --autocomplete by searching and printing + /// possible flags, descriptions, and its arguments. + void handleAutocompletions(StringRef PassedFlags) const; + /// HandleImmediateArgs - Handle any arguments which should be /// treated before building actions or binding tools. /// diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Job.h b/contrib/llvm/tools/clang/include/clang/Driver/Job.h index ff88256b8c0d6..b74b3b4b35e1b 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Job.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/Job.h @@ -97,8 +97,8 @@ public: virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const; - virtual int Execute(const StringRef **Redirects, std::string *ErrMsg, - bool *ExecutionFailed) const; + virtual int Execute(ArrayRef<Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const; /// getSource - Return the Action which caused the creation of this job. const Action &getSource() const { return Source; } @@ -141,7 +141,7 @@ public: void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; - int Execute(const StringRef **Redirects, std::string *ErrMsg, + int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override; private: @@ -158,7 +158,7 @@ public: void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; - int Execute(const StringRef **Redirects, std::string *ErrMsg, + int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const override; }; diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td index 05dc9d7eb3ad9..d36e1a63220e9 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Options.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.td @@ -139,6 +139,10 @@ def m_arm_Features_Group : OptionGroup<"<arm features group>">, Group<m_Group>, DocName<"ARM">; def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">, Group<m_Group>, DocName<"Hexagon">; +// The features added by this group will not be added to target features. +// These are explicitly handled. +def m_hexagon_Features_HVX_Group : OptionGroup<"<hexagon features group>">, + Group<m_Group>, DocName<"Hexagon">; def m_ppc_Features_Group : OptionGroup<"<ppc features group>">, Group<m_Group>, DocName<"PowerPC">; def m_wasm_Features_Group : OptionGroup<"<wasm features group>">, @@ -459,6 +463,10 @@ def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">, HelpText<"Pass <arg> to fatbinary invocation">, MetaVarName<"<arg>">; def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">, HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">; +def Xopenmp_target : Separate<["-"], "Xopenmp-target">, + HelpText<"Pass <arg> to the target offloading toolchain.">, MetaVarName<"<arg>">; +def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">, + HelpText<"Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.">, MetaVarName<"<arg>">; def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>, HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">, Group<Link_Group>; @@ -511,7 +519,7 @@ def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-round def client__name : JoinedOrSeparate<["-"], "client_name">; def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>; def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">; -def coverage : Flag<["-", "--"], "coverage">; +def coverage : Flag<["-", "--"], "coverage">, Flags<[CoreOption]>; def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>; def current__version : JoinedOrSeparate<["-"], "current_version">; def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>, @@ -588,7 +596,9 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]> HelpText<"Use Apple's kernel extensions ABI">; def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable Apple gcc-compatible #pragma pack handling">; -def shared_libasan : Flag<["-"], "shared-libasan">; +def shared_libsan : Flag<["-"], "shared-libsan">; +def static_libsan : Flag<["-"], "static-libsan">; +def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>; def fasm : Flag<["-"], "fasm">, Group<f_Group>; def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>, Flags<[CC1Option]>; @@ -600,6 +610,13 @@ def fastf : Flag<["-"], "fastf">, Group<f_Group>; def fast : Flag<["-"], "fast">, Group<f_Group>; def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>; +def fdouble_square_bracket_attributes : Flag<[ "-" ], "fdouble-square-bracket-attributes">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Enable '[[]]' attributes in all C and C++ language modes">; +def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-double-square-bracket-attributes">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Disable '[[]]' attributes in all C and C++ language modes">; + def fautolink : Flag <["-"], "fautolink">, Group<f_Group>; def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, @@ -633,12 +650,25 @@ def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Grou def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, HelpText<"Enable sample-based profile guided optimizations">; +def fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, + HelpText<"Specifies that the sample profile is accurate">, + DocBrief<[{Specifies that the sample profile is accurate. If the sample + profile is accurate, callsites without profile samples are marked + as cold. Otherwise, treat callsites without profile samples as if + we have no profile}]>; +def fno_profile_sample_accurate : Flag<["-"], "fno-profile-sample-accurate">, + Group<f_Group>, Flags<[DriverOption]>; def fauto_profile : Flag<["-"], "fauto-profile">, Group<f_Group>, Alias<fprofile_sample_use>; def fno_auto_profile : Flag<["-"], "fno-auto-profile">, Group<f_Group>, Alias<fno_profile_sample_use>; def fauto_profile_EQ : Joined<["-"], "fauto-profile=">, Alias<fprofile_sample_use_EQ>; +def fauto_profile_accurate : Flag<["-"], "fauto-profile-accurate">, + Group<f_Group>, Alias<fprofile_sample_accurate>; +def fno_auto_profile_accurate : Flag<["-"], "fno-auto-profile-accurate">, + Group<f_Group>, Alias<fno_profile_sample_accurate>; def fdebug_info_for_profiling : Flag<["-"], "fdebug-info-for-profiling">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Emit extra debug info to make sample profile more accurate.">; @@ -770,8 +800,12 @@ def fencoding_EQ : Joined<["-"], "fencoding=">, Group<f_Group>; def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>, Flags<[CoreOption]>; def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable support for exception handling">; +def fdwarf_exceptions : Flag<["-"], "fdwarf-exceptions">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Use DWARF style exceptions">; def fsjlj_exceptions : Flag<["-"], "fsjlj-exceptions">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use SjLj style exceptions">; +def fseh_exceptions : Flag<["-"], "fseh-exceptions">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Use SEH style exceptions">; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group<clang_ignored_gcc_optimization_f_Group>; def : Flag<["-"], "fexpensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>; @@ -834,6 +868,9 @@ def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-o def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">, Group<f_clang_Group>, HelpText<"Enable use-after-destroy detection in MemorySanitizer">; +def fno_sanitize_memory_use_after_dtor : Flag<["-"], "fno-sanitize-memory-use-after-dtor">, + Group<f_clang_Group>, + HelpText<"Disable use-after-destroy detection in MemorySanitizer">; def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">, Group<f_clang_Group>, HelpText<"Level of field padding for AddressSanitizer">; @@ -868,6 +905,10 @@ def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on Group<f_clang_Group>; def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group<f_clang_Group>; +def fsanitize_minimal_runtime : Flag<["-"], "fsanitize-minimal-runtime">, + Group<f_clang_Group>; +def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">, + Group<f_clang_Group>; def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">, Group<f_clang_Group>; def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">, @@ -877,6 +918,9 @@ def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">, Flags<[CoreOption, DriverOption]>, Group<f_clang_Group>, HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">; +def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-generalize-pointers">, + Group<f_clang_Group>, + HelpText<"Generalize pointers in CFI indirect call type signature checks">; def fsanitize_stats : Flag<["-"], "fsanitize-stats">, Group<f_clang_Group>, HelpText<"Enable sanitizer statistics gathering.">; @@ -988,6 +1032,10 @@ def finput_charset_EQ : Joined<["-"], "finput-charset=">, Group<f_Group>; def fexec_charset_EQ : Joined<["-"], "fexec-charset=">, Group<f_Group>; def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Generate calls to instrument function entry and exit">; +def finstrument_functions_after_inlining : Flag<["-"], "finstrument-functions-after-inlining">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Like -finstrument-functions, but insert the calls after inlining">; +def finstrument_function_entry_bare : Flag<["-"], "finstrument-function-entry-bare">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Instrument function entry only, after inlining, without arguments to the instrumentation call">; def fxray_instrument : Flag<["-"], "fxray-instrument">, Group<f_Group>, Flags<[CC1Option]>, @@ -1012,6 +1060,19 @@ def fxray_never_instrument : Group<f_Group>, Flags<[CC1Option]>, HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">; +def fxray_always_emit_customevents : Flag<["-"], "fxray-always-emit-customevents">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Determine whether to always emit __xray_customevent(...) calls even if the function it appears in is not always instrumented.">; +def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group<f_Group>, + Flags<[CC1Option]>; + +def ffine_grained_bitfield_accesses : Flag<["-"], + "ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Use separate accesses for bitfields with legal widths and alignments.">; +def fno_fine_grained_bitfield_accesses : Flag<["-"], + "fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Use large-integer access for consecutive bitfield runs.">; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; @@ -1104,8 +1165,8 @@ def fmodule_map_file : Joined<["-"], "fmodule-map-file=">, Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">, HelpText<"Load this module map file">; def fmodule_file : Joined<["-"], "fmodule-file=">, - Group<f_Group>, Flags<[DriverOption,CC1Option]>, - HelpText<"Load this precompiled module file">, MetaVarName<"<file>">; + Group<i_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"[<name>=]<file>">, + HelpText<"Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.">; def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Ignore the definition of the given macro when building and loading modules">; def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>, @@ -1310,6 +1371,10 @@ def fopenmp_targets_EQ : CommaJoined<["-"], "fopenmp-targets=">, Flags<[DriverOp HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">; def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, + HelpText<"OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.">; +def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, + HelpText<"Do not compile OpenMP target code as relocatable.">; def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>; def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>; def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">; @@ -1333,6 +1398,10 @@ def fpic : Flag<["-"], "fpic">, Group<f_Group>; def fno_pic : Flag<["-"], "fno-pic">, Group<f_Group>; def fpie : Flag<["-"], "fpie">, Group<f_Group>; def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>; +def fplt : Flag<["-"], "fplt">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use the PLT to make function calls">; +def fno_plt : Flag<["-"], "fno-plt">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Do not use the PLT to make function calls">; def fropi : Flag<["-"], "fropi">, Group<f_Group>; def fno_ropi : Flag<["-"], "fno-ropi">, Group<f_Group>; def frwpi : Flag<["-"], "frwpi">, Group<f_Group>; @@ -1352,9 +1421,9 @@ def frtti : Flag<["-"], "frtti">, Group<f_Group>; def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>; def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; -def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>, +def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, HelpText<"Force wchar_t to be a short unsigned int">; -def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1Option]>, +def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, HelpText<"Force wchar_t to be an unsigned int">; def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Which overload candidates to show when overload resolution fails: " @@ -1477,9 +1546,10 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group> HelpText<"Give global types 'default' visibility and global functions and " "variables 'hidden' visibility by default">; def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Group>, - Flags<[CC1Option]>, + Flags<[CoreOption, CC1Option]>, HelpText<"Enables whole-program vtable optimization. Requires -flto">; -def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>; +def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>, + Flags<[CoreOption]>; def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Treat signed integer overflow as two's complement">; def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>, @@ -1571,7 +1641,7 @@ def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>; def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[CoreOption]>; def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>, Flags<[CoreOption]>; def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>; -def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>; +def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>; def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>; def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>, HelpText<"Generate debug info with external references to clang modules" @@ -1644,8 +1714,6 @@ def m16 : Flag<["-"], "m16">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>, HelpText<"Enable hexagon-qdsp6 backward compatibility">; -def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; -def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>; def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>; @@ -1664,6 +1732,8 @@ def mexecute_only : Flag<["-"], "mexecute-only">, Group<m_arm_Features_Group>, HelpText<"Disallow generation of data access to code sections (ARM only)">; def mno_execute_only : Flag<["-"], "mno-execute-only">, Group<m_arm_Features_Group>, HelpText<"Allow generation of data access to code sections (ARM only)">; +def mtp_mode_EQ : Joined<["-"], "mtp=">, Group<m_arm_Features_Group>, Values<"soft, cp15">, + HelpText<"Read thread pointer from coprocessor register (ARM only)">; def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for GCC compatibility def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>; def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>; @@ -1730,13 +1800,9 @@ def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1 def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">; -def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>; -def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>; -def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>; def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>; def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Disable merging of globals">; -def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>; def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">, Alias<fno_pascal_strings>; def mno_red_zone : Flag<["-"], "mno-red-zone">, Group<m_Group>; @@ -1744,65 +1810,6 @@ def mno_relax_all : Flag<["-"], "mno-relax-all">, Group<m_Group>; def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>; def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>; def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>; -def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>; -def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>; -def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>; -def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>; -def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>; -def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>; -def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>; -// -mno-sse4 turns off sse4.1 which has the effect of turning off everything -// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on -// everything earlier than 4.2. -def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>; -def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>; -def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>; -def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>; -def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>; -def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>; -def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>; -def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>; -def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>; -def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>; -def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>; -def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>; -def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>; -def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>; -def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>; -def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>; -def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; -def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; -def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; -def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; -def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; -def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; -def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; -def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>; -def mno_lwp : Flag<["-"], "mno-lwp">, Group<m_x86_Features_Group>; -def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>; -def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>; -def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; -def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>; -def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; -def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; -def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; -def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>; -def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>; -def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>; -def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; -def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>; -def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>; -def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>; -def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; -def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>; -def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>; -def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; -def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>; -def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>; -def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>; -def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>; -def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>; -def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>; def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>, HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">; @@ -1829,7 +1836,6 @@ def mno_neg_immediates: Flag<["-"], "mno-neg-immediates">, Group<m_arm_Features_ def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>, HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">; - def mfix_cortex_a53_835769 : Flag<["-"], "mfix-cortex-a53-835769">, Group<m_aarch64_Features_Group>, HelpText<"Workaround Cortex-A53 erratum 835769 (AArch64 only)">; @@ -1841,12 +1847,18 @@ def ffixed_x18 : Flag<["-"], "ffixed-x18">, Group<m_aarch64_Features_Group>, def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>; def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>; +def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Features_Group>; +def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>; def mamdgpu_debugger_abi : Joined<["-"], "mamdgpu-debugger-abi=">, Flags<[HelpHidden]>, Group<m_Group>, HelpText<"Generate additional code for specified <version> of debugger ABI (AMDGPU only)">, MetaVarName<"<version>">; +def mxnack : Flag<["-"], "mxnack">, Group<m_amdgpu_Features_Group>, + HelpText<"Enable XNACK (AMDGPU only)">; +def mno_xnack : Flag<["-"], "mno-xnack">, Group<m_amdgpu_Features_Group>, + HelpText<"Disable XNACK (AMDGPU only)">; def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[DriverOption]>; def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[DriverOption]>; @@ -1942,68 +1954,14 @@ def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>, def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>; def mrecip : Flag<["-"], "mrecip">, Group<m_Group>; def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>, Flags<[CC1Option]>; +def mprefer_vector_width_EQ : Joined<["-"], "mprefer-vector-width=">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Specifies preferred vector width for auto-vectorization. Defaults to 'none' which allows target specific decisions.">; def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Use copy relocations support for PIE builds">; def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>; def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">, Flags<[CC1Option]>, Group<m_Group>; -def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>; -def m80387 : Flag<["-"], "m80387">, Alias<mx87>; -def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>; -def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>; -def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>; -def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>; -def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>; -def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>; -def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>; -def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>; -def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>; -def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>; -def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>; -def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>; -def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>; -def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>; -def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>; -def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>; -def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>; -def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>; -def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>; -def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>; -def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>; -def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; -def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; -def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; -def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; -def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; -def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; -def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; -def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>; -def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>; -def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>; -def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>; -def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; -def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>; -def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; -def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; -def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; -def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; -def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>; -def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; -def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; -def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; -def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; -def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>; -def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>; -def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; -def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>; -def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>; -def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>; -def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>; -def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>; -def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>; -def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>; -def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>; def mips16 : Flag<["-"], "mips16">, Group<m_Group>; def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>; def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>; @@ -2016,6 +1974,10 @@ def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_Group>; def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, Group<m_Group>; def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_Group>; +def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>, + IgnoredGCCCompat; +def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group<m_Group>, + IgnoredGCCCompat; def mdsp : Flag<["-"], "mdsp">, Group<m_Group>; def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>; def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>; @@ -2038,7 +2000,30 @@ def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>, HelpText<"Use 64-bit floating point registers (MIPS only)">; def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>, HelpText<"Use 32-bit floating point registers (MIPS only)">; +def mgpopt : Flag<["-"], "mgpopt">, Group<m_Group>, + HelpText<"Use GP relative accesses for symbols known to be in a small" + " data section (MIPS)">; +def mno_gpopt : Flag<["-"], "mno-gpopt">, Group<m_Group>, + HelpText<"Do not use GP relative accesses for symbols known to be in a small" + " data section (MIPS)">; +def mlocal_sdata : Flag<["-"], "mlocal-sdata">, Group<m_Group>, + HelpText<"Extend the -G behaviour to object local data (MIPS)">; +def mno_local_sdata : Flag<["-"], "mno-local-sdata">, Group<m_Group>, + HelpText<"Do not extend the -G behaviour to object local data (MIPS)">; +def mextern_sdata : Flag<["-"], "mextern-sdata">, Group<m_Group>, + HelpText<"Assume that externally defined data is in the small data if it" + " meets the -G <size> threshold (MIPS)">; +def mno_extern_sdata : Flag<["-"], "mno-extern-sdata">, Group<m_Group>, + HelpText<"Do not assume that externally defined data is in the small data if" + " it meets the -G <size> threshold (MIPS)">; +def membedded_data : Flag<["-"], "membedded-data">, Group<m_Group>, + HelpText<"Place constants in the .rodata section instead of the .sdata " + "section even if they meet the -G <size> threshold (MIPS)">; +def mno_embedded_data : Flag<["-"], "mno-embedded-data">, Group<m_Group>, + HelpText<"Do not place constants in the .rodata section instead of the " + ".sdata if they meet the -G <size> threshold (MIPS)">; def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>; +def mabs_EQ : Joined<["-"], "mabs=">, Group<m_Group>; def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>, HelpText<"Enable SVR4-style position-independent code (Mips only)">; def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>, @@ -2131,6 +2116,7 @@ def nostdlibinc : Flag<["-"], "nostdlibinc">; def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>, HelpText<"Disable standard #include directories for the C++ standard library">; def nostdlib : Flag<["-"], "nostdlib">; +def nostdlibxx : Flag<["-"], "nostdlib++">; def object : Flag<["-"], "object">; def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>, HelpText<"Write output to <file>">, MetaVarName<"<file>">; @@ -2225,7 +2211,14 @@ def static_libstdcxx : Flag<["-"], "static-libstdc++">; def static : Flag<["-", "--"], "static">, Flags<[NoArgumentUnused]>; def std_default_EQ : Joined<["-"], "std-default=">; def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>, - Group<CompileOnly_Group>, HelpText<"Language standard to compile for">; + Group<CompileOnly_Group>, HelpText<"Language standard to compile for">, + ValuesCode<[{ + const char *Values = + #define LANGSTANDARD(id, name, lang, desc, features) name "," + #define LANGSTANDARD_ALIAS(id, alias) alias "," + #include "clang/Frontend/LangStandards.def" + ; + }]>; def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>, HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">; def sub__library : JoinedOrSeparate<["-"], "sub_library">; @@ -2383,7 +2376,8 @@ def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>; def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>, HelpText<"Serialize compiler diagnostics to a file">; // We give --version different semantics from -version. -def _version : Flag<["--"], "version">, Flags<[CC1Option]>; +def _version : Flag<["--"], "version">, Flags<[CoreOption, CC1Option]>, + HelpText<"Print version information">; def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>; def _std : Separate<["--"], "std">, Alias<std_EQ>; def _stdlib : Separate<["--"], "stdlib">, Alias<stdlib_EQ>; @@ -2413,14 +2407,156 @@ def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>; def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>; -def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">; -def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Disable Hexagon Vector eXtensions">; -def mhexagon_hvx_double : Flag<["-"], "mhvx-double">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Enable Hexagon Double Vector eXtensions">; -def mno_hexagon_hvx_double : Flag<["-"], "mno-hvx-double">, Group<m_hexagon_Features_Group>, - Flags<[CC1Option]>, HelpText<"Disable Hexagon Double Vector eXtensions">; +def mv65 : Flag<["-"], "mv65">, Group<m_hexagon_Features_Group>, + Alias<mcpu_EQ>, AliasArgs<["hexagonv65"]>; +def mhexagon_hvx : Flag<[ "-" ], "mhvx">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mhexagon_hvx_EQ : Joined<[ "-" ], "mhvx=">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mno_hexagon_hvx : Flag<[ "-" ], "mno-hvx">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Disable Hexagon Vector eXtensions">; +def mhexagon_hvx_length_EQ : Joined<[ "-" ], "mhvx-length=">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Set Hexagon Vector Length">, Values<"64B,128B">; +// hvx-double deprecrated flag. +def mhexagon_hvx_double : Flag<[ "-" ], "mhvx-double">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Double Vector eXtensions">; +def mno_hexagon_hvx_double + : Flag<[ "-" ], "mno-hvx-double">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Disable Hexagon Double Vector eXtensions">; + + +// X86 feature flags +def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>; +def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>; +def m80387 : Flag<["-"], "m80387">, Alias<mx87>; +def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>; +def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>; +def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>; +def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>; +def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>; +def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>; +def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>; +def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>; +def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>; +def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>; +def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>; +def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>; +def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>; +def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>; +def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>; +def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>; +def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>; +def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>; +def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>; +def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>; +// -mno-sse4 turns off sse4.1 which has the effect of turning off everything +// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on +// everything earlier than 4.2. +def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>; +def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>; +def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>; +def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>; +def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>; +def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>; +def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>; +def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>; +def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>; +def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>; +def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>; +def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>; +def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>; +def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>; +def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>; +def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>; +def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>; +def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>; +def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>; +def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>; +def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>; +def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>; +def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>; +def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>; +def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>; +def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>; +def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>; +def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>; +def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>; +def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>; +def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>; +def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; +def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; +def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; +def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; +def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>; +def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>; +def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>; +def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>; +def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>; +def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>; +def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; +def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>; +def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>; +def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>; +def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>; +def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>; +def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>; +def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>; +def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; +def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; +def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; +def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; +def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>; +def mno_lwp : Flag<["-"], "mno-lwp">, Group<m_x86_Features_Group>; +def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; +def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; +def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>; +def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>; +def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>; +def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>; +def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>; +def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>; +def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; +def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; +def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; +def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; +def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; +def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; +def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>; +def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>; +def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; +def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; +def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; +def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; +def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; +def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; +def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; +def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; +def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>; +def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>; +def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; +def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>; +def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>; +def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>; +def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; +def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; +def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; +def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>; +def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>; +def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>; +def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>; +def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>; +def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; +def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; +def mshstk : Flag<["-"], "mshstk">, Group<m_x86_Features_Group>; +def mno_shstk : Flag<["-"], "mno-shstk">, Group<m_x86_Features_Group>; +def mibt : Flag<["-"], "mibt">, Group<m_x86_Features_Group>; +def mno_ibt : Flag<["-"], "mno-ibt">, Group<m_x86_Features_Group>; // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag diff --git a/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h index a9645d463fa16..a31ac05afc1bb 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h @@ -32,41 +32,49 @@ class SanitizerArgs { int MsanTrackOrigins = 0; bool MsanUseAfterDtor = false; bool CfiCrossDso = false; + bool CfiICallGeneralizePointers = false; int AsanFieldPadding = 0; - bool AsanSharedRuntime = false; + bool SharedRuntime = false; bool AsanUseAfterScope = true; bool AsanGlobalsDeadStripping = false; bool LinkCXXRuntimes = false; bool NeedPIE = false; + bool SafeStackRuntime = false; bool Stats = false; bool TsanMemoryAccess = true; bool TsanFuncEntryExit = true; bool TsanAtomics = true; + bool MinimalRuntime = false; + // True if cross-dso CFI support if provided by the system (i.e. Android). + bool ImplicitCfiRuntime = false; public: /// Parses the sanitizer arguments from an argument list. SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); + bool needsSharedRt() const { return SharedRuntime; } + bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); } - bool needsSharedAsanRt() const { return AsanSharedRuntime; } + bool needsHwasanRt() const { return Sanitizers.has(SanitizerKind::HWAddress); } bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); } bool needsLsanRt() const { return Sanitizers.has(SanitizerKind::Leak) && - !Sanitizers.has(SanitizerKind::Address); + !Sanitizers.has(SanitizerKind::Address) && + !Sanitizers.has(SanitizerKind::HWAddress); } bool needsUbsanRt() const; + bool requiresMinimalRuntime() const { return MinimalRuntime; } bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); } - bool needsSafeStackRt() const { - return Sanitizers.has(SanitizerKind::SafeStack); - } + bool needsSafeStackRt() const { return SafeStackRuntime; } bool needsCfiRt() const; bool needsCfiDiagRt() const; bool needsStatsRt() const { return Stats; } bool needsEsanRt() const { return Sanitizers.hasOneOf(SanitizerKind::Efficiency); } + bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); } bool requiresPIE() const; bool needsUnwindTables() const; diff --git a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h index 6651491e5b27c..13f54d3718b4c 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h @@ -40,12 +40,35 @@ namespace driver { class Compilation; class CudaInstallationDetector; class Driver; + class InputInfo; class JobAction; class RegisterEffectiveTriple; class SanitizerArgs; class Tool; class XRayArgs; +/// Helper structure used to pass information extracted from clang executable +/// name such as `i686-linux-android-g++`. +/// +struct ParsedClangName { + /// Target part of the executable name, as `i686-linux-android`. + std::string TargetPrefix; + /// Driver mode part of the executable name, as `g++`. + std::string ModeSuffix; + /// Corresponding driver mode argument, as '--driver-mode=g++' + const char *DriverMode; + /// True if TargetPrefix is recognized as a registered target name. + bool TargetIsValid; + + ParsedClangName() : DriverMode(nullptr), TargetIsValid(false) {} + ParsedClangName(std::string Suffix, const char *Mode) + : ModeSuffix(Suffix), DriverMode(Mode), TargetIsValid(false) {} + ParsedClangName(std::string Target, std::string Suffix, const char *Mode, + bool IsRegistered) + : TargetPrefix(Target), ModeSuffix(Suffix), DriverMode(Mode), + TargetIsValid(IsRegistered) {} +}; + /// ToolChain - Access to tools for a single platform. class ToolChain { public: @@ -70,7 +93,7 @@ public: private: const Driver &D; - const llvm::Triple Triple; + llvm::Triple Triple; const llvm::opt::ArgList &Args; // We need to initialize CachedRTTIArg before CachedRTTIMode const llvm::opt::Arg *const CachedRTTIArg; @@ -113,6 +136,8 @@ protected: ToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args); + void setTripleEnvironment(llvm::Triple::EnvironmentType Env); + virtual Tool *buildAssembler() const; virtual Tool *buildLinker() const; virtual Tool *getTool(Action::ActionClass AC) const; @@ -150,6 +175,11 @@ public: /// while the aux triple is the host (CPU) toolchain, e.g. x86-linux-gnu. virtual const llvm::Triple *getAuxTriple() const { return nullptr; } + /// Some toolchains need to modify the file name, for example to replace the + /// extension for object files with .cubin for OpenMP offloading to Nvidia + /// GPUs. + virtual std::string getInputFilename(const InputInfo &Input) const; + llvm::Triple::ArchType getArch() const { return Triple.getArch(); } StringRef getArchName() const { return Triple.getArchName(); } StringRef getPlatform() const { return Triple.getVendorName(); } @@ -193,13 +223,16 @@ public: /// For example, when called with i686-linux-android-g++, the first element /// of the return value will be set to `"i686-linux-android"` and the second /// will be set to "--driver-mode=g++"`. + /// It is OK if the target name is not registered. In this case the return + /// value contains false in the field TargetIsValid. /// /// \pre `llvm::InitializeAllTargets()` has been called. /// \param ProgName The name the Clang driver was invoked with (from, - /// e.g., argv[0]) - /// \return A pair of (`target`, `mode-flag`), where one or both may be empty. - static std::pair<std::string, std::string> - getTargetAndModeFromProgramName(StringRef ProgName); + /// e.g., argv[0]). + /// \return A structure of type ParsedClangName that contains the executable + /// name parts. + /// + static ParsedClangName getTargetAndModeFromProgramName(StringRef ProgName); // Tool access. @@ -217,6 +250,13 @@ public: return nullptr; } + /// TranslateOpenMPTargetArgs - Create a new derived argument list for + /// that contains the OpenMP target specific flags passed via + /// -Xopenmp-target -opt=val OR -Xopenmp-target=<triple> -opt=val + virtual llvm::opt::DerivedArgList *TranslateOpenMPTargetArgs( + const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, + SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const; + /// Choose a tool to use to handle the action \p JA. /// /// This can be overridden when a particular ToolChain needs to use @@ -278,6 +318,9 @@ public: /// mixed dispatch method be used? virtual bool UseObjCMixedDispatch() const { return false; } + /// \brief Check whether to enable x86 relax relocations by default. + virtual bool useRelaxRelocations() const; + /// GetDefaultStackProtectorLevel - Get the default stack protector level for /// this tool chain (0=off, 1=on, 2=strong, 3=all). virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { @@ -298,6 +341,8 @@ public: return ToolChain::CST_Libstdcxx; } + virtual std::string getCompilerRTPath() const; + virtual std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, bool Shared = false) const; @@ -332,9 +377,6 @@ public: /// SupportsProfiling - Does this tool chain support -pg. virtual bool SupportsProfiling() const { return true; } - /// Does this tool chain support Objective-C garbage collection. - virtual bool SupportsObjCGC() const { return true; } - /// Complain if this tool chain doesn't support Objective-C ARC. virtual void CheckObjCARC() const {} @@ -357,10 +399,9 @@ public: return llvm::DebuggerKind::GDB; } - /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. - virtual bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const { - return false; - } + /// GetExceptionModel - Return the tool chain exception model. + virtual llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const; /// SupportsEmbeddedBitcode - Does this tool chain support embedded bitcode. virtual bool SupportsEmbeddedBitcode() const { @@ -432,6 +473,10 @@ public: AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + /// Returns if the C++ standard library should be linked in. + /// Note that e.g. -lm should still be linked even if this returns false. + bool ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const; + /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use /// for the given C++ standard library type. virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, diff --git a/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h b/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h index 83210d100a12c..e5b76162de8e2 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h @@ -24,6 +24,7 @@ class XRayArgs { std::vector<std::string> ExtraDeps; bool XRayInstrument = false; int InstructionThreshold = 200; + bool XRayAlwaysEmitCustomEvents = false; public: /// Parses the XRay arguments from an argument list. diff --git a/contrib/llvm/tools/clang/include/clang/Format/Format.h b/contrib/llvm/tools/clang/include/clang/Format/Format.h index 99d54e55e8285..d27d934f76798 100644 --- a/contrib/llvm/tools/clang/include/clang/Format/Format.h +++ b/contrib/llvm/tools/clang/include/clang/Format/Format.h @@ -151,13 +151,20 @@ struct FormatStyle { /// \endcode bool AlignTrailingComments; - /// \brief Allow putting all parameters of a function declaration onto + /// \brief If the function declaration doesn't fit on a line, + /// allow putting all parameters of a function declaration onto /// the next line even if ``BinPackParameters`` is ``false``. /// \code - /// true: false: - /// myFunction(foo, vs. myFunction(foo, bar, plop); - /// bar, - /// plop); + /// true: + /// void myFunction( + /// int a, int b, int c, int d, int e); + /// + /// false: + /// void myFunction(int a, + /// int b, + /// int c, + /// int d, + /// int e); /// \endcode bool AllowAllParametersOfDeclarationOnNextLine; @@ -674,6 +681,20 @@ struct FormatStyle { /// } /// \endcode bool AfterUnion; + /// \brief Wrap extern blocks. + /// \code + /// true: + /// extern "C" + /// { + /// int foo(); + /// } + /// + /// false: + /// extern "C" { + /// int foo(); + /// } + /// \endcode + bool AfterExternBlock; /// \brief Wrap before ``catch``. /// \code /// true: @@ -746,6 +767,14 @@ struct FormatStyle { /// /// If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how /// each individual brace case should be handled. Otherwise, this is ignored. + /// \code{.yaml} + /// # Example of usage: + /// BreakBeforeBraces: Custom + /// BraceWrapping: + /// AfterEnum: true + /// AfterStruct: false + /// SplitEmptyFunction: false + /// \endcode BraceWrappingFlags BraceWrapping; /// \brief If ``true``, ternary operators will be placed after line breaks. @@ -956,6 +985,40 @@ struct FormatStyle { /// For example: BOOST_FOREACH. std::vector<std::string> ForEachMacros; + /// \brief Styles for sorting multiple ``#include`` blocks. + enum IncludeBlocksStyle { + /// \brief Sort each ``#include`` block separately. + /// \code + /// #include "b.h" into #include "b.h" + /// + /// #include <lib/main.h> #include "a.h" + /// #include "a.h" #include <lib/main.h> + /// \endcode + IBS_Preserve, + /// \brief Merge multiple ``#include`` blocks together and sort as one. + /// \code + /// #include "b.h" into #include "a.h" + /// #include "b.h" + /// #include <lib/main.h> #include <lib/main.h> + /// #include "a.h" + /// \endcode + IBS_Merge, + /// \brief Merge multiple ``#include`` blocks together and sort as one. + /// Then split into groups based on category priority. See + /// ``IncludeCategories``. + /// \code + /// #include "b.h" into #include "a.h" + /// #include "b.h" + /// #include <lib/main.h> + /// #include "a.h" #include <lib/main.h> + /// \endcode + IBS_Regroup, + }; + + /// \brief Dependent on the value, multiple ``#include`` blocks can be sorted + /// as one and divided based on category. + IncludeBlocksStyle IncludeBlocks; + /// \brief See documentation of ``IncludeCategories``. struct IncludeCategory { /// \brief The regular expression that this category matches. @@ -1024,6 +1087,31 @@ struct FormatStyle { /// \endcode bool IndentCaseLabels; + /// \brief Options for indenting preprocessor directives. + enum PPDirectiveIndentStyle { + /// Does not indent any directives. + /// \code + /// #if FOO + /// #if BAR + /// #include <foo> + /// #endif + /// #endif + /// \endcode + PPDIS_None, + /// Indents directives after the hash. + /// \code + /// #if FOO + /// # if BAR + /// # include <foo> + /// # endif + /// #endif + /// \endcode + PPDIS_AfterHash + }; + + /// \brief The preprocessor directive indenting style to use. + PPDirectiveIndentStyle IndentPPDirectives; + /// \brief The number of columns to use for indentation. /// \code /// IndentWidth: 3 @@ -1273,6 +1361,41 @@ struct FormatStyle { /// \brief Pointer and reference alignment style. PointerAlignmentStyle PointerAlignment; + /// See documentation of ``RawStringFormats``. + struct RawStringFormat { + /// \brief The delimiter that this raw string format matches. + std::string Delimiter; + /// \brief The language of this raw string. + LanguageKind Language; + /// \brief The style name on which this raw string format is based on. + /// If not specified, the raw string format is based on the style that this + /// format is based on. + std::string BasedOnStyle; + bool operator==(const RawStringFormat &Other) const { + return Delimiter == Other.Delimiter && Language == Other.Language && + BasedOnStyle == Other.BasedOnStyle; + } + }; + + /// \brief Raw string delimiters denoting that the raw string contents are + /// code in a particular language and can be reformatted. + /// + /// A raw string with a matching delimiter will be reformatted assuming the + /// specified language based on a predefined style given by 'BasedOnStyle'. + /// If 'BasedOnStyle' is not found, the formatting is based on llvm style. + /// + /// To configure this in the .clang-format file, use: + /// \code{.yaml} + /// RawStringFormats: + /// - Delimiter: 'pb' + /// Language: TextProto + /// BasedOnStyle: llvm + /// - Delimiter: 'proto' + /// Language: TextProto + /// BasedOnStyle: google + /// \endcode + std::vector<RawStringFormat> RawStringFormats; + /// \brief If ``true``, clang-format will attempt to re-flow comments. /// \code /// false: @@ -1296,6 +1419,14 @@ struct FormatStyle { bool SortIncludes; /// \brief If ``true``, clang-format will sort using declarations. + /// + /// The order of using declarations is defined as follows: + /// Split the strings by "::" and discard any initial empty strings. The last + /// element of each list is a non-namespace name; all others are namespace + /// names. Sort the lists of names lexicographically, where the sort order of + /// individual names is that all non-namespace names come before all namespace + /// names, and within those groups, names are in case-insensitive + /// lexicographic order. /// \code /// false: true: /// using std::cout; vs. using std::cin; @@ -1512,8 +1643,10 @@ struct FormatStyle { R.ExperimentalAutoDetectBinPacking && FixNamespaceComments == R.FixNamespaceComments && ForEachMacros == R.ForEachMacros && + IncludeBlocks == R.IncludeBlocks && IncludeCategories == R.IncludeCategories && IndentCaseLabels == R.IndentCaseLabels && + IndentPPDirectives == R.IndentPPDirectives && IndentWidth == R.IndentWidth && Language == R.Language && IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && JavaScriptQuotes == R.JavaScriptQuotes && @@ -1537,6 +1670,7 @@ struct FormatStyle { PenaltyExcessCharacter == R.PenaltyExcessCharacter && PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine && PointerAlignment == R.PointerAlignment && + RawStringFormats == R.RawStringFormats && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword && SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h index 1ac4f07a3549a..5d04dcd19119a 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h @@ -448,7 +448,7 @@ public: IntrusiveRefCntPtr<ASTReader> getASTReader() const; - StringRef getOriginalSourceFileName() { + StringRef getOriginalSourceFileName() const { return OriginalSourceFile; } @@ -524,26 +524,26 @@ public: /// \brief If \p Loc is a loaded location from the preamble, returns /// the corresponding local location of the main file, otherwise it returns /// \p Loc. - SourceLocation mapLocationFromPreamble(SourceLocation Loc); + SourceLocation mapLocationFromPreamble(SourceLocation Loc) const; /// \brief If \p Loc is a local location of the main file but inside the /// preamble chunk, returns the corresponding loaded location from the /// preamble, otherwise it returns \p Loc. - SourceLocation mapLocationToPreamble(SourceLocation Loc); + SourceLocation mapLocationToPreamble(SourceLocation Loc) const; - bool isInPreambleFileID(SourceLocation Loc); - bool isInMainFileID(SourceLocation Loc); - SourceLocation getStartOfMainFileID(); - SourceLocation getEndOfPreambleFileID(); + bool isInPreambleFileID(SourceLocation Loc) const; + bool isInMainFileID(SourceLocation Loc) const; + SourceLocation getStartOfMainFileID() const; + SourceLocation getEndOfPreambleFileID() const; /// \see mapLocationFromPreamble. - SourceRange mapRangeFromPreamble(SourceRange R) { + SourceRange mapRangeFromPreamble(SourceRange R) const { return SourceRange(mapLocationFromPreamble(R.getBegin()), mapLocationFromPreamble(R.getEnd())); } /// \see mapLocationToPreamble. - SourceRange mapRangeToPreamble(SourceRange R) { + SourceRange mapRangeToPreamble(SourceRange R) const { return SourceRange(mapLocationToPreamble(R.getBegin()), mapLocationToPreamble(R.getEnd())); } @@ -607,7 +607,7 @@ public: /// \brief Returns true if the ASTUnit was constructed from a serialized /// module file. - bool isModuleFile(); + bool isModuleFile() const; std::unique_ptr<llvm::MemoryBuffer> getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr); diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def index 4002415adc459..bb91cf5f742b7 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def @@ -76,10 +76,17 @@ CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. +CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when + ///< -finstrument-functions-after-inlining is enabled. +CODEGENOPT(InstrumentFunctionEntryBare , 1, 0) ///< Set when + ///< -finstrument-function-entry-bare is enabled. CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. +///< Set when -fxray-always-emit-customevents is enabled. +CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0) + ///< Set the minimum number of instructions in a function to determine selective ///< XRay instrumentation. VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) @@ -110,6 +117,7 @@ CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled. CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf. CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero +CODEGENOPT(Reassociate , 1, 0) ///< Allow reassociation of FP math ops CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated. CODEGENOPT(NoTrappingMath , 1, 0) ///< Set when -fno-trapping-math is enabled. CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. @@ -142,6 +150,7 @@ ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Defa CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions. CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA. +CODEGENOPT(NewStructPathTBAA , 1, 0) ///< Whether or not to use enhanced struct-path TBAA. CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection ///< in AddressSanitizer @@ -152,6 +161,10 @@ CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection ///< in MemorySanitizer CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. +CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime for + ///< diagnostics. +CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in + ///< CFI icall function signatures CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage ///< instrumentation. CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage @@ -171,10 +184,13 @@ CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard ///< in sanitizer coverage. CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters. +CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table. CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning. +CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers. CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. +CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. @@ -185,6 +201,7 @@ CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns. CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. +CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate. /// Attempt to use register sized accesses to bit-fields in structures, when /// possible. @@ -214,6 +231,10 @@ CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the ///< skeleton CU to allow for symbolication ///< of inline stack frames without .dwo files. +CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete + ///< template parameter descriptions in + ///< forward declarations (versus just + ///< including them in the name). CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists. @@ -282,6 +303,11 @@ CODEGENOPT(DebugInfoForProfiling, 1, 0) /// Whether 3-component vector type is preserved. CODEGENOPT(PreserveVec3Type, 1, 0) +/// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames. +CODEGENOPT(GnuPubnames, 1, 0) + +CODEGENOPT(NoPLT, 1, 0) + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h index 71730a21dbe24..6b8d2b935fdd2 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -251,6 +251,13 @@ public: /// \brief A list of all -fno-builtin-* function names (e.g., memset). std::vector<std::string> NoBuiltinFuncs; + std::vector<std::string> Reciprocals; + + /// The preferred width for auto-vectorization transforms. This is intended to + /// override default transforms based on the width of the architected vector + /// registers. + std::string PreferVectorWidth; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h b/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h index a78c96d23afa3..f5c1e1a8a67d0 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CommandLineSourceLoc.h @@ -51,6 +51,52 @@ public: } }; +/// A source range that has been parsed on the command line. +struct ParsedSourceRange { + std::string FileName; + /// The starting location of the range. The first element is the line and + /// the second element is the column. + std::pair<unsigned, unsigned> Begin; + /// The ending location of the range. The first element is the line and the + /// second element is the column. + std::pair<unsigned, unsigned> End; + + /// Returns a parsed source range from a string or None if the string is + /// invalid. + /// + /// These source string has the following format: + /// + /// file:start_line:start_column[-end_line:end_column] + /// + /// If the end line and column are omitted, the starting line and columns + /// are used as the end values. + static Optional<ParsedSourceRange> fromString(StringRef Str) { + std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-'); + unsigned EndLine, EndColumn; + bool HasEndLoc = false; + if (!RangeSplit.second.empty()) { + std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':'); + if (Split.first.getAsInteger(10, EndLine) || + Split.second.getAsInteger(10, EndColumn)) { + // The string does not end in end_line:end_column, so the '-' + // probably belongs to the filename which menas the whole + // string should be parsed. + RangeSplit.first = Str; + } else + HasEndLoc = true; + } + auto Begin = ParsedSourceLocation::FromString(RangeSplit.first); + if (Begin.FileName.empty()) + return None; + if (!HasEndLoc) { + EndLine = Begin.Line; + EndColumn = Begin.Column; + } + return ParsedSourceRange{std::move(Begin.FileName), + {Begin.Line, Begin.Column}, + {EndLine, EndColumn}}; + } +}; } namespace llvm { diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h index 5b5c75298a313..90a9501475b52 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h @@ -640,7 +640,9 @@ public: const CodeGenOptions *CodeGenOpts = nullptr); /// Create the file manager and replace any existing one with it. - void createFileManager(); + /// + /// \return The new file manager on success, or null on failure. + FileManager *createFileManager(); /// Create the source manager and replace any existing one with it. void createSourceManager(FileManager &FileMgr); diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h index c45aeaa208c8c..fa1529a3d65dc 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h @@ -86,10 +86,15 @@ public: /// \brief Compute the AST consumer arguments that will be used to /// create the PCHGenerator instance returned by CreateASTConsumer. /// - /// \returns true if an error occurred, false otherwise. - static std::unique_ptr<raw_pwrite_stream> - ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile, - std::string &Sysroot, std::string &OutputFile); + /// \returns false if an error occurred, true otherwise. + static bool ComputeASTConsumerArguments(CompilerInstance &CI, + std::string &Sysroot); + + /// \brief Creates file to write the PCH into and returns a stream to write it + /// into. On error, returns null. + static std::unique_ptr<llvm::raw_pwrite_stream> + CreateOutputFile(CompilerInstance &CI, StringRef InFile, + std::string &OutputFile); bool BeginSourceFileAction(CompilerInstance &CI) override; }; diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h index e757a7e397e35..5192a3774cc1d 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h @@ -128,21 +128,24 @@ class FrontendInputFile { /// \brief The file name, or "-" to read from standard input. std::string File; - llvm::MemoryBuffer *Buffer; + /// The input, if it comes from a buffer rather than a file. This object + /// does not own the buffer, and the caller is responsible for ensuring + /// that it outlives any users. + llvm::MemoryBuffer *Buffer = nullptr; /// \brief The kind of input, e.g., C source, AST file, LLVM IR. InputKind Kind; /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input). - bool IsSystem; + bool IsSystem = false; public: - FrontendInputFile() : Buffer(nullptr), Kind(), IsSystem(false) { } + FrontendInputFile() { } FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) - : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } - FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, + : File(File.str()), Kind(Kind), IsSystem(IsSystem) { } + FrontendInputFile(llvm::MemoryBuffer *Buffer, InputKind Kind, bool IsSystem = false) - : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { } + : Buffer(Buffer), Kind(Kind), IsSystem(IsSystem) { } InputKind getKind() const { return Kind; } bool isSystem() const { return IsSystem; } diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h index 6731e08bcae8f..83e452d884b62 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h @@ -22,16 +22,17 @@ enum LangFeatures { LineComment = (1 << 0), C99 = (1 << 1), C11 = (1 << 2), - CPlusPlus = (1 << 3), - CPlusPlus11 = (1 << 4), - CPlusPlus14 = (1 << 5), - CPlusPlus1z = (1 << 6), - CPlusPlus2a = (1 << 7), - Digraphs = (1 << 8), - GNUMode = (1 << 9), - HexFloat = (1 << 10), - ImplicitInt = (1 << 11), - OpenCL = (1 << 12) + C17 = (1 << 3), + CPlusPlus = (1 << 4), + CPlusPlus11 = (1 << 5), + CPlusPlus14 = (1 << 6), + CPlusPlus17 = (1 << 7), + CPlusPlus2a = (1 << 8), + Digraphs = (1 << 9), + GNUMode = (1 << 10), + HexFloat = (1 << 11), + ImplicitInt = (1 << 12), + OpenCL = (1 << 13) }; } @@ -70,6 +71,9 @@ public: /// isC11 - Language is a superset of C11. bool isC11() const { return Flags & frontend::C11; } + /// isC17 - Language is a superset of C17. + bool isC17() const { return Flags & frontend::C17; } + /// isCPlusPlus - Language is a C++ variant. bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } @@ -79,8 +83,8 @@ public: /// isCPlusPlus14 - Language is a C++14 variant (or later). bool isCPlusPlus14() const { return Flags & frontend::CPlusPlus14; } - /// isCPlusPlus1z - Language is a C++17 variant (or later). - bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; } + /// isCPlusPlus17 - Language is a C++17 variant (or later). + bool isCPlusPlus17() const { return Flags & frontend::CPlusPlus17; } /// isCPlusPlus2a - Language is a post-C++17 variant (or later). bool isCPlusPlus2a() const { return Flags & frontend::CPlusPlus2a; } diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def index a019d63922140..e7a081dc2aa76 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def @@ -77,6 +77,15 @@ LANGSTANDARD(gnu11, "gnu11", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") +// C17 modes +LANGSTANDARD(c17, "c17", + C, "ISO C 2017", + LineComment | C99 | C11 | C17 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c17, "iso9899:2017") +LANGSTANDARD(gnu17, "gnu17", + C, "ISO C 2017 with GNU extensions", + LineComment | C99 | C11 | C17 | Digraphs | GNUMode | HexFloat) + // C++ modes LANGSTANDARD(cxx98, "c++98", CXX, "ISO C++ 1998 with amendments", @@ -111,24 +120,24 @@ LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y") LANGSTANDARD(cxx17, "c++17", CXX, "ISO C++ 2017 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | Digraphs | HexFloat) LANGSTANDARD_ALIAS_DEPR(cxx17, "c++1z") LANGSTANDARD(gnucxx17, "gnu++17", CXX, "ISO C++ 2017 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | Digraphs | HexFloat | GNUMode) LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z") LANGSTANDARD(cxx2a, "c++2a", CXX, "Working draft for ISO C++ 2020", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | CPlusPlus2a | Digraphs | HexFloat) LANGSTANDARD(gnucxx2a, "gnu++2a", CXX, "Working draft for ISO C++ 2020 with GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | CPlusPlus2a | Digraphs | HexFloat | GNUMode) // OpenCL diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h index 8307392e7febd..64342b1dffa81 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h @@ -17,6 +17,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/AlignOf.h" #include "llvm/Support/MD5.h" #include <memory> #include <system_error> @@ -36,21 +37,6 @@ class CompilerInvocation; class DeclGroupRef; class PCHContainerOperations; -/// A size of the preamble and a flag required by -/// PreprocessorOptions::PrecompiledPreambleBytes. -struct PreambleBounds { - PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine) - : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} - - /// \brief Size of the preamble in bytes. - unsigned Size; - /// \brief Whether the preamble ends at the start of a new line. - /// - /// Used to inform the lexer as to whether it's starting at the beginning of - /// a line after skipping the preamble. - bool PreambleEndsAtStartOfLine; -}; - /// \brief Runs lexer to compute suggested preamble bounds. PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, llvm::MemoryBuffer *Buffer, @@ -62,7 +48,7 @@ class PreambleCallbacks; /// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and /// CanReusePreamble + AddImplicitPreamble to make use of it. class PrecompiledPreamble { - class TempPCHFile; + class PCHStorage; struct PreambleFileHash; public: @@ -85,6 +71,9 @@ public: /// /// \param PCHContainerOps An instance of PCHContainerOperations. /// + /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in + /// a temporary file. + /// /// \param Callbacks A set of callbacks to be executed when building /// the preamble. static llvm::ErrorOr<PrecompiledPreamble> @@ -92,12 +81,12 @@ public: const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, std::shared_ptr<PCHContainerOperations> PCHContainerOps, - PreambleCallbacks &Callbacks); + bool StoreInMemory, PreambleCallbacks &Callbacks); PrecompiledPreamble(PrecompiledPreamble &&) = default; PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; - /// PreambleBounds used to build the preamble + /// PreambleBounds used to build the preamble. PreambleBounds getBounds() const; /// Check whether PrecompiledPreamble can be reused for the new contents(\p @@ -107,12 +96,18 @@ public: vfs::FileSystem *VFS) const; /// Changes options inside \p CI to use PCH from this preamble. Also remaps - /// main file to \p MainFileBuffer. + /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble + /// is accessible. + /// For in-memory preambles, PrecompiledPreamble instance continues to own + /// the MemoryBuffer with the Preamble after this method returns. The caller + /// is reponsible for making sure the PrecompiledPreamble instance outlives + /// the compiler run and the AST that will be using the PCH. void AddImplicitPreamble(CompilerInvocation &CI, + IntrusiveRefCntPtr<vfs::FileSystem> &VFS, llvm::MemoryBuffer *MainFileBuffer) const; private: - PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes, + PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes, bool PreambleEndsAtStartOfLine, llvm::StringMap<PreambleFileHash> FilesInPreamble); @@ -154,6 +149,44 @@ private: llvm::Optional<std::string> FilePath; }; + class InMemoryPreamble { + public: + std::string Data; + }; + + class PCHStorage { + public: + enum class Kind { Empty, InMemory, TempFile }; + + PCHStorage() = default; + PCHStorage(TempPCHFile File); + PCHStorage(InMemoryPreamble Memory); + + PCHStorage(const PCHStorage &) = delete; + PCHStorage &operator=(const PCHStorage &) = delete; + + PCHStorage(PCHStorage &&Other); + PCHStorage &operator=(PCHStorage &&Other); + + ~PCHStorage(); + + Kind getKind() const; + + TempPCHFile &asFile(); + const TempPCHFile &asFile() const; + + InMemoryPreamble &asMemory(); + const InMemoryPreamble &asMemory() const; + + private: + void destroy(); + void setEmpty(); + + private: + Kind StorageKind = Kind::Empty; + llvm::AlignedCharArrayUnion<TempPCHFile, InMemoryPreamble> Storage = {}; + }; + /// Data used to determine if a file used in the preamble has been changed. struct PreambleFileHash { /// All files have size set. @@ -183,8 +216,15 @@ private: } }; - /// Manages the lifetime of temporary file that stores a PCH. - TempPCHFile PCHFile; + /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p + /// Storage is accessible to clang. This method is an implementation detail of + /// AddImplicitPreamble. + static void setupPreambleStorage(const PCHStorage &Storage, + PreprocessorOptions &PreprocessorOpts, + IntrusiveRefCntPtr<vfs::FileSystem> &VFS); + + /// Manages the memory buffer or temporary file that stores the PCH. + PCHStorage Storage; /// Keeps track of the files that were used when computing the /// preamble, with both their buffer size and their modification time. /// @@ -215,11 +255,9 @@ public: /// NOTE: To allow more flexibility a custom ASTConsumer could probably be /// used instead, but having only this method allows a simpler API. virtual void HandleTopLevelDecl(DeclGroupRef DG); - /// Called for each macro defined in the Preamble. - /// NOTE: To allow more flexibility a custom PPCallbacks could probably be - /// used instead, but having only this method allows a simpler API. - virtual void HandleMacroDefined(const Token &MacroNameTok, - const MacroDirective *MD); + /// Creates wrapper class for PPCallbacks so we can also process information + /// about includes that are inside of a preamble + virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); }; enum class BuildPreambleError { diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h index 3bcf824455e2d..23f168e2232df 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticBuffer.h @@ -29,6 +29,11 @@ public: typedef DiagList::const_iterator const_iterator; private: DiagList Errors, Warnings, Remarks, Notes; + /// All - All diagnostics in the order in which they were generated. That + /// order likely doesn't correspond to user input order, but it at least + /// keeps notes in the right places. Each pair in the vector is a diagnostic + /// level and an index into the corresponding DiagList above. + std::vector<std::pair<DiagnosticsEngine::Level, size_t>> All; public: const_iterator err_begin() const { return Errors.begin(); } const_iterator err_end() const { return Errors.end(); } diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h index 475f07f9dc06a..8d71fb98b0bb1 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -176,7 +176,8 @@ public: : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); - assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); + assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) && + "DiagnosticLoc is invalid!"); } private: diff --git a/contrib/llvm/tools/clang/include/clang/Index/IndexDataConsumer.h b/contrib/llvm/tools/clang/include/clang/Index/IndexDataConsumer.h index 315437048345b..080f4cb4d0978 100644 --- a/contrib/llvm/tools/clang/include/clang/Index/IndexDataConsumer.h +++ b/contrib/llvm/tools/clang/include/clang/Index/IndexDataConsumer.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_INDEX_INDEXDATACONSUMER_H #include "clang/Index/IndexSymbol.h" +#include "clang/Lex/Preprocessor.h" namespace clang { class ASTContext; @@ -36,6 +37,8 @@ public: virtual void initialize(ASTContext &Ctx) {} + virtual void setPreprocessor(std::shared_ptr<Preprocessor> PP) {} + /// \returns true to continue indexing, or false to abort. virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, diff --git a/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h b/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h index abb132f9e4ce8..ae591364f229e 100644 --- a/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h +++ b/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h @@ -53,6 +53,7 @@ enum class SymbolKind : uint8_t { ConversionFunction, Parameter, + Using, }; enum class SymbolLanguage { @@ -69,6 +70,8 @@ enum class SymbolSubKind { CXXMoveConstructor, AccessorGetter, AccessorSetter, + UsingTypename, + UsingValue, }; /// Set of properties that provide additional info about a symbol. diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h index 1b7f80c87ff1d..6b9dbfcd1e934 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h @@ -1,4 +1,4 @@ -//===--- HeaderSearch.h - Resolve Header File Locations ---------*- C++ -*-===// +//===- HeaderSearch.h - Resolve Header File Locations -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,25 +14,37 @@ #ifndef LLVM_CLANG_LEX_HEADERSEARCH_H #define LLVM_CLANG_LEX_HEADERSEARCH_H +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Lex/DirectoryLookup.h" #include "clang/Lex/ModuleMap.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstddef> #include <memory> +#include <string> +#include <utility> #include <vector> namespace clang { - -class DiagnosticsEngine; + +class DiagnosticsEngine; +class DirectoryEntry; class ExternalPreprocessorSource; class FileEntry; class FileManager; +class HeaderMap; class HeaderSearchOptions; class IdentifierInfo; +class LangOptions; +class Module; class Preprocessor; +class TargetInfo; /// \brief The preprocessor keeps track of this information for each /// file that is \#included. @@ -76,14 +88,14 @@ struct HeaderFileInfo { unsigned IsValid : 1; /// \brief The number of times the file has been included already. - unsigned short NumIncludes; + unsigned short NumIncludes = 0; /// \brief The ID number of the controlling macro. /// /// This ID number will be non-zero when there is a controlling /// macro whose IdentifierInfo may not yet have been loaded from /// external storage. - unsigned ControllingMacroID; + unsigned ControllingMacroID = 0; /// If this file has a \#ifndef XXX (or equivalent) guard that /// protects the entire contents of the file, this is the identifier @@ -93,17 +105,16 @@ struct HeaderFileInfo { /// the controlling macro of this header, since /// getControllingMacro() is able to load a controlling macro from /// external storage. - const IdentifierInfo *ControllingMacro; + const IdentifierInfo *ControllingMacro = nullptr; /// \brief If this header came from a framework include, this is the name /// of the framework. StringRef Framework; HeaderFileInfo() - : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), - External(false), isModuleHeader(false), isCompilingModuleHeader(false), - Resolved(false), IndexHeaderMapHeader(false), IsValid(0), - NumIncludes(0), ControllingMacroID(0), ControllingMacro(nullptr) {} + : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), + External(false), isModuleHeader(false), isCompilingModuleHeader(false), + Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} /// \brief Retrieve the controlling macro for this header file, if /// any. @@ -135,6 +146,8 @@ public: /// \brief Encapsulates the information needed to find the file referenced /// by a \#include or \#include_next, (sub-)framework lookup, etc. class HeaderSearch { + friend class DirectoryLookup; + /// This structure is used to record entries in our framework cache. struct FrameworkCacheEntry { /// The directory entry which should be used for the cached framework. @@ -151,6 +164,7 @@ class HeaderSearch { DiagnosticsEngine &Diags; FileManager &FileMgr; + /// \#include search path information. Requests for \#include "x" search the /// directory of the \#including file first, then each directory in SearchDirs /// consecutively. Requests for <x> search the current dir first, then each @@ -158,9 +172,9 @@ class HeaderSearch { /// NoCurDirSearch is true, then the check for the file in the current /// directory is suppressed. std::vector<DirectoryLookup> SearchDirs; - unsigned AngledDirIdx; - unsigned SystemDirIdx; - bool NoCurDirSearch; + unsigned AngledDirIdx = 0; + unsigned SystemDirIdx = 0; + bool NoCurDirSearch = false; /// \brief \#include prefixes for which the 'system header' property is /// overridden. @@ -168,7 +182,7 @@ class HeaderSearch { /// For a \#include "x" or \#include \<x> directive, the last string in this /// list which is a prefix of 'x' determines whether the file is treated as /// a system header. - std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes; + std::vector<std::pair<std::string, bool>> SystemHeaderPrefixes; /// \brief The path to the module cache. std::string ModuleCachePath; @@ -182,15 +196,17 @@ class HeaderSearch { /// Starting index in SearchDirs that the cached search was performed from. /// If there is a hit and this value doesn't match the current query, the /// cache has to be ignored. - unsigned StartIdx; + unsigned StartIdx = 0; + /// The entry in SearchDirs that satisfied the query. - unsigned HitIdx; + unsigned HitIdx = 0; + /// This is non-null if the original filename was mapped to a framework /// include via a headermap. - const char *MappedName; + const char *MappedName = nullptr; /// Default constructor -- Initialize all members with zero. - LookupFileCacheInfo(): StartIdx(0), HitIdx(0), MappedName(nullptr) {} + LookupFileCacheInfo() = default; void reset(unsigned StartIdx) { this->StartIdx = StartIdx; @@ -206,13 +222,13 @@ class HeaderSearch { /// IncludeAliases - maps include file names (including the quotes or /// angle brackets) to other include file names. This is used to support the /// include_alias pragma for Microsoft compatibility. - typedef llvm::StringMap<std::string, llvm::BumpPtrAllocator> - IncludeAliasMap; + using IncludeAliasMap = + llvm::StringMap<std::string, llvm::BumpPtrAllocator>; std::unique_ptr<IncludeAliasMap> IncludeAliases; /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing /// headermaps. This vector owns the headermap. - std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; + std::vector<std::pair<const FileEntry *, const HeaderMap *>> HeaderMaps; /// \brief The mapping between modules and headers. mutable ModuleMap ModMap; @@ -231,26 +247,23 @@ class HeaderSearch { /// \brief Entity used to resolve the identifier IDs of controlling /// macros into IdentifierInfo pointers, and keep the identifire up to date, /// as needed. - ExternalPreprocessorSource *ExternalLookup; + ExternalPreprocessorSource *ExternalLookup = nullptr; /// \brief Entity used to look up stored header file information. - ExternalHeaderFileInfoSource *ExternalSource; + ExternalHeaderFileInfoSource *ExternalSource = nullptr; // Various statistics we track for performance analysis. - unsigned NumIncluded; - unsigned NumMultiIncludeFileOptzn; - unsigned NumFrameworkLookups, NumSubFrameworkLookups; + unsigned NumIncluded = 0; + unsigned NumMultiIncludeFileOptzn = 0; + unsigned NumFrameworkLookups = 0; + unsigned NumSubFrameworkLookups = 0; - // HeaderSearch doesn't support default or copy construction. - HeaderSearch(const HeaderSearch&) = delete; - void operator=(const HeaderSearch&) = delete; - - friend class DirectoryLookup; - public: HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts, SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target); + HeaderSearch(const HeaderSearch &) = delete; + HeaderSearch &operator=(const HeaderSearch &) = delete; ~HeaderSearch(); /// \brief Retrieve the header-search options with which this header search @@ -282,7 +295,7 @@ public: } /// \brief Set the list of system header prefixes. - void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool> > P) { + void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool>> P) { SystemHeaderPrefixes.assign(P.begin(), P.end()); } @@ -310,7 +323,7 @@ public: IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source); if (Iter != IncludeAliases->end()) return Iter->second; - return StringRef(); + return {}; } /// \brief Set the path to the module cache. @@ -471,29 +484,40 @@ public: /// \brief Get filenames for all registered header maps. void getHeaderMapFileNames(SmallVectorImpl<std::string> &Names) const; - /// \brief Retrieve the name of the module file that should be used to - /// load the given module. + /// \brief Retrieve the name of the cached module file that should be used + /// to load the given module. /// /// \param Module The module whose module file name will be returned. /// /// \returns The name of the module file that corresponds to this module, /// or an empty string if this module does not correspond to any module file. - std::string getModuleFileName(Module *Module); + std::string getCachedModuleFileName(Module *Module); + + /// \brief Retrieve the name of the prebuilt module file that should be used + /// to load a module with the given name. + /// + /// \param ModuleName The module whose module file name will be returned. + /// + /// \param FileMapOnly If true, then only look in the explicit module name + // to file name map and skip the directory search. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getPrebuiltModuleFileName(StringRef ModuleName, + bool FileMapOnly = false); - /// \brief Retrieve the name of the module file that should be used to - /// load a module with the given name. + /// \brief Retrieve the name of the (to-be-)cached module file that should + /// be used to load a module with the given name. /// /// \param ModuleName The module whose module file name will be returned. /// /// \param ModuleMapPath A path that when combined with \c ModuleName /// uniquely identifies this module. See Module::ModuleMap. /// - /// \param UsePrebuiltPath Whether we should use the prebuilt module path. - /// /// \returns The name of the module file that corresponds to this module, /// or an empty string if this module does not correspond to any module file. - std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath, - bool UsePrebuiltPath); + std::string getCachedModuleFileName(StringRef ModuleName, + StringRef ModuleMapPath); /// \brief Lookup a module Search for a module with the given name. /// @@ -560,7 +584,6 @@ public: void loadTopLevelSystemModules(); private: - /// \brief Lookup a module with the given module name and search-name. /// /// \param ModuleName The name of the module we're looking for. @@ -640,7 +663,8 @@ public: bool WantExternal = true) const; // Used by external tools - typedef std::vector<DirectoryLookup>::const_iterator search_dir_iterator; + using search_dir_iterator = std::vector<DirectoryLookup>::const_iterator; + search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); } search_dir_iterator search_dir_end() const { return SearchDirs.end(); } unsigned search_dir_size() const { return SearchDirs.size(); } @@ -648,6 +672,7 @@ public: search_dir_iterator quoted_dir_begin() const { return SearchDirs.begin(); } + search_dir_iterator quoted_dir_end() const { return SearchDirs.begin() + AngledDirIdx; } @@ -655,6 +680,7 @@ public: search_dir_iterator angled_dir_begin() const { return SearchDirs.begin() + AngledDirIdx; } + search_dir_iterator angled_dir_end() const { return SearchDirs.begin() + SystemDirIdx; } @@ -662,6 +688,7 @@ public: search_dir_iterator system_dir_begin() const { return SearchDirs.begin() + SystemDirIdx; } + search_dir_iterator system_dir_end() const { return SearchDirs.end(); } /// \brief Retrieve a uniqued framework name. @@ -684,10 +711,13 @@ private: enum LoadModuleMapResult { /// \brief The module map file had already been loaded. LMM_AlreadyLoaded, + /// \brief The module map file was loaded by this invocation. LMM_NewlyLoaded, + /// \brief There is was directory with the given name. LMM_NoDirectory, + /// \brief There was either no module map file or the module map file was /// invalid. LMM_InvalidModuleMap @@ -723,6 +753,6 @@ private: bool IsSystem, bool IsFramework); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_HEADERSEARCH_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h index ca3a84e75e181..937ad9863db37 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h @@ -1,4 +1,4 @@ -//===--- HeaderSearchOptions.h ----------------------------------*- C++ -*-===// +//===- HeaderSearchOptions.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,35 +12,55 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/CachedHashString.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" +#include <cstdint> #include <string> #include <vector> +#include <map> namespace clang { namespace frontend { - /// IncludeDirGroup - Identifies the group an include Entry belongs to, - /// representing its relative positive in the search list. - /// \#include directives whose paths are enclosed by string quotes ("") - /// start searching at the Quoted group (specified by '-iquote'), - /// then search the Angled group, then the System group, etc. - enum IncludeDirGroup { - Quoted = 0, ///< '\#include ""' paths, added by 'gcc -iquote'. - Angled, ///< Paths for '\#include <>' added by '-I'. - IndexHeaderMap, ///< Like Angled, but marks header maps used when - /// building frameworks. - System, ///< Like Angled, but marks system directories. - ExternCSystem, ///< Like System, but headers are implicitly wrapped in - /// extern "C". - CSystem, ///< Like System, but only used for C. - CXXSystem, ///< Like System, but only used for C++. - ObjCSystem, ///< Like System, but only used for ObjC. - ObjCXXSystem, ///< Like System, but only used for ObjC++. - After ///< Like System, but searched after the system directories. - }; -} + +/// IncludeDirGroup - Identifies the group an include Entry belongs to, +/// representing its relative positive in the search list. +/// \#include directives whose paths are enclosed by string quotes ("") +/// start searching at the Quoted group (specified by '-iquote'), +/// then search the Angled group, then the System group, etc. +enum IncludeDirGroup { + /// '\#include ""' paths, added by 'gcc -iquote'. + Quoted = 0, + + /// Paths for '\#include <>' added by '-I'. + Angled, + + /// Like Angled, but marks header maps used when building frameworks. + IndexHeaderMap, + + /// Like Angled, but marks system directories. + System, + + /// Like System, but headers are implicitly wrapped in extern "C". + ExternCSystem, + + /// Like System, but only used for C. + CSystem, + + /// Like System, but only used for C++. + CXXSystem, + + /// Like System, but only used for ObjC. + ObjCSystem, + + /// Like System, but only used for ObjC++. + ObjCXXSystem, + + /// Like System, but searched after the system directories. + After +}; + +} // namespace frontend /// HeaderSearchOptions - Helper class for storing options related to the /// initialization of the HeaderSearch object. @@ -58,8 +78,8 @@ public: Entry(StringRef path, frontend::IncludeDirGroup group, bool isFramework, bool ignoreSysRoot) - : Path(path), Group(group), IsFramework(isFramework), - IgnoreSysRoot(ignoreSysRoot) {} + : Path(path), Group(group), IsFramework(isFramework), + IgnoreSysRoot(ignoreSysRoot) {} }; struct SystemHeaderPrefix { @@ -71,7 +91,7 @@ public: bool IsSystemHeader; SystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) - : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {} + : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {} }; /// If non-empty, the directory to use as a "virtual system root" for include @@ -94,6 +114,9 @@ public: /// \brief The directory used for a user build. std::string ModuleUserBuildPath; + /// \brief The mapping of module names to prebuilt module files. + std::map<std::string, std::string> PrebuiltModuleFiles; + /// \brief The directories used to load prebuilt module files. std::vector<std::string> PrebuiltModulePaths; @@ -126,7 +149,7 @@ public: /// files. /// /// The default value is large, e.g., the operation runs once a week. - unsigned ModuleCachePruneInterval; + unsigned ModuleCachePruneInterval = 7 * 24 * 60 * 60; /// \brief The time (in seconds) after which an unused module file will be /// considered unused and will, therefore, be pruned. @@ -135,13 +158,13 @@ public: /// accessed in this many seconds will be removed. The default value is /// large, e.g., a month, to avoid forcing infrequently-used modules to be /// regenerated often. - unsigned ModuleCachePruneAfter; + unsigned ModuleCachePruneAfter = 31 * 24 * 60 * 60; /// \brief The time in seconds when the build session started. /// /// This time is used by other optimizations in header search and module /// loading. - uint64_t BuildSessionTimestamp; + uint64_t BuildSessionTimestamp = 0; /// \brief The set of macro names that should be ignored for the purposes /// of computing the module hash. @@ -181,10 +204,8 @@ public: unsigned ModulesHashContent : 1; HeaderSearchOptions(StringRef _Sysroot = "/") - : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(0), - ImplicitModuleMaps(0), ModuleMapFileHomeIsCwd(0), - ModuleCachePruneInterval(7 * 24 * 60 * 60), - ModuleCachePruneAfter(31 * 24 * 60 * 60), BuildSessionTimestamp(0), + : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false), + ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false), UseBuiltinIncludes(true), UseStandardSystemIncludes(true), UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), ModulesValidateOncePerBuildSession(false), @@ -213,6 +234,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h index 3be733167e5cf..d58849654cb83 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h @@ -1,4 +1,4 @@ -//===--- Lexer.h - C Language Family Lexer ----------------------*- C++ -*-===// +//===- Lexer.h - C Language Family Lexer ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,45 +15,88 @@ #define LLVM_CLANG_LEX_LEXER_H #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include <cassert> +#include <cstdint> #include <string> +namespace llvm { + +class MemoryBuffer; + +} // namespace llvm + namespace clang { -class DiagnosticsEngine; -class SourceManager; -class Preprocessor; + class DiagnosticBuilder; +class Preprocessor; +class SourceManager; /// ConflictMarkerKind - Kinds of conflict marker which the lexer might be /// recovering from. enum ConflictMarkerKind { /// Not within a conflict marker. CMK_None, + /// A normal or diff3 conflict marker, initiated by at least 7 "<"s, /// separated by at least 7 "="s or "|"s, and terminated by at least 7 ">"s. CMK_Normal, + /// A Perforce-style conflict marker, initiated by 4 ">"s, /// separated by 4 "="s, and terminated by 4 "<"s. CMK_Perforce }; +/// Describes the bounds (start, size) of the preamble and a flag required by +/// PreprocessorOptions::PrecompiledPreambleBytes. +/// The preamble includes the BOM, if any. +struct PreambleBounds { + /// \brief Size of the preamble in bytes. + unsigned Size; + + /// \brief Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; + + PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine) + : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} +}; + /// Lexer - This provides a simple interface that turns a text buffer into a /// stream of tokens. This provides no support for file reading or buffering, /// or buffering/seeking of tokens, only forward lexing is supported. It relies /// on the specified Preprocessor object to handle preprocessor directives, etc. class Lexer : public PreprocessorLexer { + friend class Preprocessor; + void anchor() override; //===--------------------------------------------------------------------===// // Constant configuration values for this lexer. - const char *BufferStart; // Start of the buffer. - const char *BufferEnd; // End of the buffer. - SourceLocation FileLoc; // Location for start of file. - LangOptions LangOpts; // LangOpts enabled by this language (cache). - bool Is_PragmaLexer; // True if lexer for _Pragma handling. - + + // Start of the buffer. + const char *BufferStart; + + // End of the buffer. + const char *BufferEnd; + + // Location for start of file. + SourceLocation FileLoc; + + // LangOpts enabled by this language (cache). + LangOptions LangOpts; + + // True if lexer for _Pragma handling. + bool Is_PragmaLexer; + //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. // @@ -89,13 +132,9 @@ class Lexer : public PreprocessorLexer { // CurrentConflictMarkerState - The kind of conflict marker we are handling. ConflictMarkerKind CurrentConflictMarkerState; - Lexer(const Lexer &) = delete; - void operator=(const Lexer &) = delete; - friend class Preprocessor; - void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); -public: +public: /// Lexer constructor - Create a new lexer object for the specified buffer /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will @@ -114,6 +153,9 @@ public: Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, const SourceManager &SM, const LangOptions &LangOpts); + Lexer(const Lexer &) = delete; + Lexer &operator=(const Lexer &) = delete; + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method /// sets up. It returns a new'd Lexer that must be delete'd when done. @@ -122,7 +164,6 @@ public: SourceLocation ExpansionLocEnd, unsigned TokLen, Preprocessor &PP); - /// getLangOpts - Return the language features currently enabled. /// NOTE: this lexer modifies features as a file is parsed! const LangOptions &getLangOpts() const { return LangOpts; } @@ -224,17 +265,16 @@ public: /// \brief Return the current location in the buffer. const char *getBufferLocation() const { return BufferPtr; } - - /// Stringify - Convert the specified string into a C string by escaping '\' - /// and " characters. This does not add surrounding ""'s to the string. + + /// Stringify - Convert the specified string into a C string by i) escaping + /// '\\' and " characters and ii) replacing newline character(s) with "\\n". /// If Charify is true, this escapes the ' character instead of ". static std::string Stringify(StringRef Str, bool Charify = false); - /// Stringify - Convert the specified string into a C string by escaping '\' - /// and " characters. This does not add surrounding ""'s to the string. + /// Stringify - Convert the specified string into a C string by i) escaping + /// '\\' and " characters and ii) replacing newline character(s) with "\\n". static void Stringify(SmallVectorImpl<char> &Str); - /// getSpelling - This method is used to get the spelling of a token into a /// preallocated buffer, instead of as an std::string. The caller is required /// to allocate enough space for the token, which is guaranteed to be at least @@ -245,11 +285,11 @@ public: /// to point to a constant buffer with the data already in it (avoiding a /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. - static unsigned getSpelling(const Token &Tok, const char *&Buffer, + static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid = nullptr); - + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a /// token is the characters used to represent the token in the source file /// after trigraph expansion and escaped-newline folding. In particular, this @@ -257,7 +297,7 @@ public: /// UCNs, etc. static std::string getSpelling(const Token &Tok, const SourceManager &SourceMgr, - const LangOptions &LangOpts, + const LangOptions &LangOpts, bool *Invalid = nullptr); /// getSpelling - This method is used to get the spelling of the @@ -273,7 +313,7 @@ public: const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *invalid = nullptr); - + /// MeasureTokenLength - Relex the token at the specified location and return /// its length in bytes in the input file. If the token needs cleaning (e.g. /// includes a trigraph or an escaped newline) then this count includes bytes @@ -295,7 +335,7 @@ public: static SourceLocation GetBeginningOfToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts); - + /// AdvanceToTokenCharacter - If the current SourceLocation specifies a /// location at the start of a token, return a new location that specifies a /// character within the token. This handles trigraphs and escaped newlines. @@ -303,7 +343,7 @@ public: unsigned Character, const SourceManager &SM, const LangOptions &LangOpts); - + /// \brief Computes the source location just past the end of the /// token at this source location. /// @@ -443,11 +483,18 @@ public: /// to fewer than this number of lines. /// /// \returns The offset into the file where the preamble ends and the rest - /// of the file begins along with a boolean value indicating whether + /// of the file begins along with a boolean value indicating whether /// the preamble ends at the beginning of a new line. - static std::pair<unsigned, bool> ComputePreamble(StringRef Buffer, - const LangOptions &LangOpts, - unsigned MaxLines = 0); + static PreambleBounds ComputePreamble(StringRef Buffer, + const LangOptions &LangOpts, + unsigned MaxLines = 0); + + /// Finds the token that comes right after the given location. + /// + /// Returns the next token, or none if the location is inside a macro. + static Optional<Token> findNextToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); /// \brief Checks that the given token is the first token that occurs after /// the given location (this excludes comments and whitespace). Returns the @@ -463,6 +510,10 @@ public: /// \brief Returns true if the given character could appear in an identifier. static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts); + /// \brief Checks whether new line pointed by Str is preceded by escape + /// sequence. + static bool isNewLineEscaped(const char *BufferStart, const char *Str); + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever /// emit a warning. static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, @@ -483,9 +534,9 @@ public: static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM); +private: //===--------------------------------------------------------------------===// // Internal implementation interfaces. -private: /// LexTokenInternal - Internal interface to lex a preprocessing token. Called /// by Lex. @@ -614,7 +665,7 @@ private: //===--------------------------------------------------------------------===// // Other lexer functions. - void SkipBytes(unsigned Bytes, bool StartOfLine); + void SetByteOffset(unsigned Offset, bool StartOfLine); void PropagateLineStartLeadingSpaceInfo(Token &Result); @@ -639,7 +690,7 @@ private: bool SkipBlockComment (Token &Result, const char *CurPtr, bool &TokAtPhysicalStartOfLine); bool SaveLineComment (Token &Result, const char *CurPtr); - + bool IsStartOfConflictMarker(const char *CurPtr); bool HandleEndOfConflictMarker(const char *CurPtr); @@ -658,7 +709,7 @@ private: /// valid), this parameter will be updated to point to the /// character after the UCN. /// \param SlashLoc The position in the source buffer of the '\'. - /// \param Tok The token being formed. Pass \c NULL to suppress diagnostics + /// \param Tok The token being formed. Pass \c nullptr to suppress diagnostics /// and handle token formation in the caller. /// /// \return The Unicode codepoint specified by the UCN, or 0 if the UCN is @@ -687,6 +738,6 @@ private: bool tryConsumeIdentifierUTF8Char(const char *&CurPtr); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_LEXER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h b/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h index b66581b428b1f..cc9223eb7dbb3 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h @@ -65,6 +65,7 @@ public: bool isHalf : 1; // 1.0h bool isFloat : 1; // 1.0f bool isImaginary : 1; // 1.0i + bool isFloat16 : 1; // 1.0f16 bool isFloat128 : 1; // 1.0q uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h index cfe46ceb09797..a202550da3b3c 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h @@ -17,6 +17,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/TrailingObjects.h" #include <vector> namespace clang { @@ -26,7 +27,10 @@ namespace clang { /// MacroArgs - An instance of this class captures information about /// the formal arguments specified to a function-like macro invocation. -class MacroArgs { +class MacroArgs final + : private llvm::TrailingObjects<MacroArgs, Token> { + + friend TrailingObjects; /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the /// arguments. All of the actual argument tokens are allocated immediately /// after the MacroArgs object in memory. This is all of the arguments @@ -89,7 +93,7 @@ public: /// getPreExpArgument - Return the pre-expanded form of the specified /// argument. const std::vector<Token> & - getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP); + getPreExpArgument(unsigned Arg, Preprocessor &PP); /// getStringifiedArgument - Compute, cache, and return the specified argument /// that has been 'stringified' as required by the # operator. @@ -108,6 +112,20 @@ public: /// argument, this returns false. bool isVarargsElidedUse() const { return VarargsElided; } + /// Returns true if the macro was defined with a variadic (ellipsis) parameter + /// AND was invoked with at least one token supplied as a variadic argument. + /// + /// \code + /// #define F(a) a + /// #define V(a, ...) __VA_OPT__(a) + /// F() <-- returns false on this invocation. + /// V(,a) <-- returns true on this invocation. + /// V(,) <-- returns false on this invocation. + /// \endcode + /// + + bool invokedWithVariadicArgument(const MacroInfo *const MI) const; + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of /// tokens into the literal string token that should be produced by the C # /// preprocessor operator. If Charify is true, then it should be turned into diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h index d25431b55fdc3..3029294209ec5 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h @@ -1,4 +1,4 @@ -//===--- MacroInfo.h - Information about #defined identifiers ---*- C++ -*-===// +//===- MacroInfo.h - Information about #defined identifiers -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,27 +6,33 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::MacroInfo and clang::MacroDirective classes. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LEX_MACROINFO_H #define LLVM_CLANG_LEX_MACROINFO_H #include "clang/Lex/Token.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" +#include <algorithm> #include <cassert> namespace clang { + +class DefMacroDirective; +class IdentifierInfo; class Module; -class ModuleMacro; class Preprocessor; +class SourceManager; /// \brief Encapsulates the data about a macro definition (e.g. its tokens). /// @@ -37,6 +43,7 @@ class MacroInfo { /// \brief The location the macro is defined. SourceLocation Location; + /// \brief The location of the last token in the macro. SourceLocation EndLocation; @@ -46,10 +53,10 @@ class MacroInfo { /// /// This can be empty, for, e.g. "#define X()". In a C99-style variadic /// macro, this includes the \c __VA_ARGS__ identifier on the list. - IdentifierInfo **ParameterList; + IdentifierInfo **ParameterList = nullptr; /// \see ParameterList - unsigned NumParameters; + unsigned NumParameters = 0; /// \brief This is the list of tokens that the macro is defined to. SmallVector<Token, 8> ReplacementTokens; @@ -169,7 +176,7 @@ public: /// Parameters - The list of parameters for a function-like macro. This can /// be empty, for, e.g. "#define X()". - typedef IdentifierInfo *const *param_iterator; + using param_iterator = IdentifierInfo *const *; bool param_empty() const { return NumParameters == 0; } param_iterator param_begin() const { return ParameterList; } param_iterator param_end() const { return ParameterList + NumParameters; } @@ -224,7 +231,6 @@ public: bool isWarnIfUnused() const { return IsWarnIfUnused; } /// \brief Return the number of tokens that this macro expands to. - /// unsigned getNumTokens() const { return ReplacementTokens.size(); } const Token &getReplacementToken(unsigned Tok) const { @@ -232,7 +238,8 @@ public: return ReplacementTokens[Tok]; } - typedef SmallVectorImpl<Token>::const_iterator tokens_iterator; + using tokens_iterator = SmallVectorImpl<Token>::const_iterator; + tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); } tokens_iterator tokens_end() const { return ReplacementTokens.end(); } bool tokens_empty() const { return ReplacementTokens.empty(); } @@ -269,12 +276,10 @@ public: void dump() const; private: - unsigned getDefinitionLengthSlow(const SourceManager &SM) const; - friend class Preprocessor; -}; -class DefMacroDirective; + unsigned getDefinitionLengthSlow(const SourceManager &SM) const; +}; /// \brief Encapsulates changes to the "macros namespace" (the location where /// the macro name became active, the location where it was undefined, etc.). @@ -285,11 +290,15 @@ class DefMacroDirective; /// create additional DefMacroDirectives for the same MacroInfo. class MacroDirective { public: - enum Kind { MD_Define, MD_Undefine, MD_Visibility }; + enum Kind { + MD_Define, + MD_Undefine, + MD_Visibility + }; protected: - /// \brief Previous macro directive for the same identifier, or NULL. - MacroDirective *Previous; + /// \brief Previous macro directive for the same identifier, or nullptr. + MacroDirective *Previous = nullptr; SourceLocation Loc; @@ -306,8 +315,7 @@ protected: unsigned IsPublic : 1; MacroDirective(Kind K, SourceLocation Loc) - : Previous(nullptr), Loc(Loc), MDKind(K), IsFromPCH(false), - IsPublic(true) {} + : Loc(Loc), MDKind(K), IsFromPCH(false), IsPublic(true) {} public: Kind getKind() const { return Kind(MDKind); } @@ -329,13 +337,12 @@ public: void setIsFromPCH() { IsFromPCH = true; } class DefInfo { - DefMacroDirective *DefDirective; + DefMacroDirective *DefDirective = nullptr; SourceLocation UndefLoc; - bool IsPublic; + bool IsPublic = true; public: - DefInfo() : DefDirective(nullptr), IsPublic(true) {} - + DefInfo() = default; DefInfo(DefMacroDirective *DefDirective, SourceLocation UndefLoc, bool isPublic) : DefDirective(DefDirective), UndefLoc(UndefLoc), IsPublic(isPublic) {} @@ -345,6 +352,7 @@ public: inline SourceLocation getLocation() const; inline MacroInfo *getMacroInfo(); + const MacroInfo *getMacroInfo() const { return const_cast<DefInfo *>(this)->getMacroInfo(); } @@ -360,6 +368,7 @@ public: explicit operator bool() const { return isValid(); } inline DefInfo getPreviousDefinition(); + const DefInfo getPreviousDefinition() const { return const_cast<DefInfo *>(this)->getPreviousDefinition(); } @@ -412,6 +421,7 @@ public: static bool classof(const MacroDirective *MD) { return MD->getKind() == MD_Define; } + static bool classof(const DefMacroDirective *) { return true; } }; @@ -426,6 +436,7 @@ public: static bool classof(const MacroDirective *MD) { return MD->getKind() == MD_Undefine; } + static bool classof(const UndefMacroDirective *) { return true; } }; @@ -444,12 +455,13 @@ public: static bool classof(const MacroDirective *MD) { return MD->getKind() == MD_Visibility; } + static bool classof(const VisibilityMacroDirective *) { return true; } }; inline SourceLocation MacroDirective::DefInfo::getLocation() const { if (isInvalid()) - return SourceLocation(); + return {}; return DefDirective->getLocation(); } @@ -462,7 +474,7 @@ inline MacroInfo *MacroDirective::DefInfo::getMacroInfo() { inline MacroDirective::DefInfo MacroDirective::DefInfo::getPreviousDefinition() { if (isInvalid() || DefDirective->getPrevious() == nullptr) - return DefInfo(); + return {}; return DefDirective->getPrevious()->getDefinition(); } @@ -474,23 +486,26 @@ MacroDirective::DefInfo::getPreviousDefinition() { /// /// These are stored in a FoldingSet in the preprocessor. class ModuleMacro : public llvm::FoldingSetNode { + friend class Preprocessor; + /// The name defined by the macro. IdentifierInfo *II; + /// The body of the #define, or nullptr if this is a #undef. MacroInfo *Macro; + /// The module that exports this macro. Module *OwningModule; + /// The number of module macros that override this one. - unsigned NumOverriddenBy; + unsigned NumOverriddenBy = 0; + /// The number of modules whose macros are directly overridden by this one. unsigned NumOverrides; - // ModuleMacro *OverriddenMacros[NumOverrides]; - - friend class Preprocessor; ModuleMacro(Module *OwningModule, IdentifierInfo *II, MacroInfo *Macro, ArrayRef<ModuleMacro *> Overrides) - : II(II), Macro(Macro), OwningModule(OwningModule), NumOverriddenBy(0), + : II(II), Macro(Macro), OwningModule(OwningModule), NumOverrides(Overrides.size()) { std::copy(Overrides.begin(), Overrides.end(), reinterpret_cast<ModuleMacro **>(this + 1)); @@ -504,12 +519,16 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const { return Profile(ID, OwningModule, II); } + static void Profile(llvm::FoldingSetNodeID &ID, Module *OwningModule, IdentifierInfo *II) { ID.AddPointer(OwningModule); ID.AddPointer(II); } + /// Get the name of the macro. + IdentifierInfo *getName() const { return II; } + /// Get the ID of the module that exports this macro. Module *getOwningModule() const { return OwningModule; } @@ -519,13 +538,16 @@ public: /// Iterators over the overridden module IDs. /// \{ - typedef ModuleMacro *const *overrides_iterator; + using overrides_iterator = ModuleMacro *const *; + overrides_iterator overrides_begin() const { return reinterpret_cast<overrides_iterator>(this + 1); } + overrides_iterator overrides_end() const { return overrides_begin() + NumOverrides; } + ArrayRef<ModuleMacro *> overrides() const { return llvm::makeArrayRef(overrides_begin(), overrides_end()); } @@ -544,7 +566,7 @@ class MacroDefinition { ArrayRef<ModuleMacro *> ModuleMacros; public: - MacroDefinition() : LatestLocalAndAmbiguous(), ModuleMacros() {} + MacroDefinition() = default; MacroDefinition(DefMacroDirective *MD, ArrayRef<ModuleMacro *> MMs, bool IsAmbiguous) : LatestLocalAndAmbiguous(MD, IsAmbiguous), ModuleMacros(MMs) {} @@ -583,6 +605,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_MACROINFO_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h index ee0638b57f872..30ea583b71e0b 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h @@ -1,4 +1,4 @@ -//===--- ModuleLoader.h - Module Loader Interface ---------------*- C++ -*-===// +//===- ModuleLoader.h - Module Loader Interface -----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,23 +11,26 @@ // loading named modules. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_LEX_MODULELOADER_H #define LLVM_CLANG_LEX_MODULELOADER_H +#include "clang/Basic/LLVM.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/StringRef.h" +#include <utility> namespace clang { class GlobalModuleIndex; class IdentifierInfo; -class Module; /// \brief A sequence of identifier/location pairs used to describe a particular /// module or submodule, e.g., std.vector. -typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation> > ModuleIdPath; +using ModuleIdPath = ArrayRef<std::pair<IdentifierInfo *, SourceLocation>>; /// \brief Describes the result of attempting to load a module. class ModuleLoadResult { @@ -35,16 +38,18 @@ public: enum LoadResultKind { // We either succeeded or failed to load the named module. Normal, + // The module exists, but does not actually contain the named submodule. // This should only happen if the named submodule was inferred from an // umbrella directory, but not actually part of the umbrella header. MissingExpected, + // The module exists but cannot be imported due to a configuration mismatch. ConfigMismatch }; llvm::PointerIntPair<Module *, 2, LoadResultKind> Storage; - ModuleLoadResult() : Storage() { } + ModuleLoadResult() = default; ModuleLoadResult(Module *M) : Storage(M, Normal) {} ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {} @@ -69,10 +74,10 @@ public: class ModuleLoader { // Building a module if true. bool BuildingModule; + public: - explicit ModuleLoader(bool BuildingModule = false) : - BuildingModule(BuildingModule), - HadFatalFailure(false) {} + explicit ModuleLoader(bool BuildingModule = false) + : BuildingModule(BuildingModule) {} virtual ~ModuleLoader(); @@ -80,6 +85,7 @@ public: bool buildingModule() const { return BuildingModule; } + /// \brief Flag indicating whether this instance is building a module. void setBuildingModule(bool BuildingModuleFlag) { BuildingModule = BuildingModuleFlag; @@ -144,7 +150,7 @@ public: virtual bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) = 0; - bool HadFatalFailure; + bool HadFatalFailure = false; }; /// A module loader that doesn't know how to load modules. @@ -153,7 +159,7 @@ public: ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override { - return ModuleLoadResult(); + return {}; } void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, @@ -165,12 +171,13 @@ public: GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } + bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override { - return 0; + return false; } }; -} +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_MODULELOADER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h index 11506939f9b18..41ed8e49b6c1d 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h @@ -1,4 +1,4 @@ -//===--- ModuleMap.h - Describe the layout of modules -----------*- C++ -*-===// +//===- ModuleMap.h - Describe the layout of modules -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,7 +18,6 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" @@ -28,20 +27,19 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/Twine.h" -#include <algorithm> +#include <ctime> #include <memory> #include <string> #include <utility> namespace clang { +class DiagnosticsEngine; class DirectoryEntry; class FileEntry; class FileManager; -class DiagnosticConsumer; -class DiagnosticsEngine; class HeaderSearch; -class ModuleMapParser; +class SourceManager; /// \brief A mechanism to observe the actions of the module map parser as it /// reads module map files. @@ -82,33 +80,40 @@ class ModuleMap { /// \brief The directory used for Clang-supplied, builtin include headers, /// such as "stdint.h". - const DirectoryEntry *BuiltinIncludeDir; + const DirectoryEntry *BuiltinIncludeDir = nullptr; /// \brief Language options used to parse the module map itself. /// /// These are always simple C language options. LangOptions MMapLangOpts; - // The module that the main source file is associated with (the module - // named LangOpts::CurrentModule, if we've loaded it). - Module *SourceModule; + /// The module that the main source file is associated with (the module + /// named LangOpts::CurrentModule, if we've loaded it). + Module *SourceModule = nullptr; + + /// The global module for the current TU, if we still own it. (Ownership is + /// transferred if/when we create an enclosing module. + std::unique_ptr<Module> PendingGlobalModule; /// \brief The top-level modules that are known. llvm::StringMap<Module *> Modules; /// \brief The number of modules we have created in total. - unsigned NumCreatedModules; + unsigned NumCreatedModules = 0; public: /// \brief Flags describing the role of a module header. enum ModuleHeaderRole { /// \brief This header is normally included in the module. NormalHeader = 0x0, + /// \brief This header is included but private. PrivateHeader = 0x1, + /// \brief This header is part of the module (for layering purposes) but /// should be textually included. TextualHeader = 0x2, + // Caution: Adding an enumerator needs other changes. // Adjust the number of bits for KnownHeader::Storage. // Adjust the bitfield HeaderFileInfo::HeaderRole size. @@ -119,6 +124,7 @@ public: /// Convert a header kind to a role. Requires Kind to not be HK_Excluded. static ModuleHeaderRole headerKindToRole(Module::HeaderKind Kind); + /// Convert a header role to a kind. static Module::HeaderKind headerRoleToKind(ModuleHeaderRole Role); @@ -128,8 +134,8 @@ public: llvm::PointerIntPair<Module *, 2, ModuleHeaderRole> Storage; public: - KnownHeader() : Storage(nullptr, NormalHeader) { } - KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) { } + KnownHeader() : Storage(nullptr, NormalHeader) {} + KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) {} friend bool operator==(const KnownHeader &A, const KnownHeader &B) { return A.Storage == B.Storage; @@ -162,11 +168,13 @@ public: } }; - typedef llvm::SmallPtrSet<const FileEntry *, 1> AdditionalModMapsSet; + using AdditionalModMapsSet = llvm::SmallPtrSet<const FileEntry *, 1>; private: - typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1>> - HeadersMap; + friend class ModuleMapParser; + + using HeadersMap = + llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1>>; /// \brief Mapping from each header to the module that owns the contents of /// that header. @@ -174,6 +182,7 @@ private: /// Map from file sizes to modules with lazy header directives of that size. mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>> LazyHeadersBySize; + /// Map from mtimes to modules with lazy header directives with those mtimes. mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>> LazyHeadersByModTime; @@ -188,9 +197,6 @@ private: /// \brief The set of attributes that can be attached to a module. struct Attributes { - Attributes() - : IsSystem(), IsExternC(), IsExhaustive(), NoUndeclaredIncludes() {} - /// \brief Whether this is a system module. unsigned IsSystem : 1; @@ -203,12 +209,14 @@ private: /// \brief Whether files in this module can only include non-modular headers /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; + + Attributes() + : IsSystem(false), IsExternC(false), IsExhaustive(false), + NoUndeclaredIncludes(false) {} }; /// \brief A directory for which framework modules can be inferred. struct InferredDirectory { - InferredDirectory() : InferModules() {} - /// \brief Whether to infer modules from this directory. unsigned InferModules : 1; @@ -222,6 +230,8 @@ private: /// \brief The names of modules that cannot be inferred within this /// directory. SmallVector<std::string, 2> ExcludedModules; + + InferredDirectory() : InferModules(false) {} }; /// \brief A mapping from directories to information about inferring @@ -238,8 +248,6 @@ private: /// map. llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap; - friend class ModuleMapParser; - /// \brief Resolve the given export declaration into an actual export /// declaration. /// @@ -341,7 +349,6 @@ public: HeaderSearch &HeaderInfo); /// \brief Destroy the module map. - /// ~ModuleMap(); /// \brief Set the target information. @@ -460,7 +467,7 @@ public: /// \param Name The name of the module to find or create. /// /// \param Parent The module that will act as the parent of this submodule, - /// or NULL to indicate that this is a top-level module. + /// or nullptr to indicate that this is a top-level module. /// /// \param IsFramework Whether this is a framework module. /// @@ -472,6 +479,14 @@ public: bool IsFramework, bool IsExplicit); + /// \brief Create a 'global module' for a C++ Modules TS module interface + /// unit. + /// + /// We model the global module as a submodule of the module interface unit. + /// Unfortunately, we can't create the module interface unit's Module until + /// later, because we don't know what it will be called. + Module *createGlobalModuleForInterfaceUnit(SourceLocation Loc); + /// \brief Create a new module for a C++ Modules TS module interface unit. /// The module must not already exist, and will be configured for the current /// compilation. @@ -479,7 +494,8 @@ public: /// Note that this also sets the current module to the newly-created module. /// /// \returns The newly-created module. - Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name); + Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name, + Module *GlobalModule); /// \brief Infer the contents of a framework module map from the given /// framework directory. @@ -492,7 +508,7 @@ public: /// \param Module The module whose module map file will be returned, if known. /// /// \returns The file entry for the module map file containing the given - /// module, or NULL if the module definition was inferred. + /// module, or nullptr if the module definition was inferred. const FileEntry *getContainingModuleMapFile(const Module *Module) const; /// \brief Get the module map file that (along with the module name) uniquely @@ -599,11 +615,12 @@ public: /// \brief Dump the contents of the module map, for debugging purposes. void dump(); - typedef llvm::StringMap<Module *>::const_iterator module_iterator; + using module_iterator = llvm::StringMap<Module *>::const_iterator; + module_iterator module_begin() const { return Modules.begin(); } module_iterator module_end() const { return Modules.end(); } }; -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_LEX_MODULEMAP_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h b/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h index 83e6f99078dfd..3967f8688966f 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/MultipleIncludeOpt.h @@ -92,7 +92,7 @@ public: TheMacro = nullptr; } - /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the + /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the /// top of the file when reading preprocessor directives. Otherwise, reading /// the "ifndef x" would count as reading tokens. bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h index 81c3bd7d14ec5..19bce4dd32e88 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h @@ -235,6 +235,14 @@ public: virtual void PragmaWarningPop(SourceLocation Loc) { } + /// \brief Callback invoked when a \#pragma clang assume_nonnull begin directive + /// is read. + virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {} + + /// \brief Callback invoked when a \#pragma clang assume_nonnull end directive + /// is read. + virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {} + /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a /// macro invocation is found. virtual void MacroExpands(const Token &MacroNameTok, @@ -266,7 +274,10 @@ public: /// \brief Hook called when a source range is skipped. /// \param Range The SourceRange that was skipped. The range begins at the /// \#if/\#else directive and ends after the \#endif/\#else directive. - virtual void SourceRangeSkipped(SourceRange Range) { + /// \param EndifLoc The end location of the 'endif' token, which may precede + /// the range skipped by the directive (e.g excluding comments after an + /// 'endif'). + virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { } enum ConditionValueKind { @@ -381,6 +392,12 @@ public: Second->Ident(Loc, str); } + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) override { + First->PragmaDirective(Loc, Introducer); + Second->PragmaDirective(Loc, Introducer); + } + void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, StringRef Str) override { First->PragmaComment(Loc, Kind, Str); @@ -393,6 +410,11 @@ public: Second->PragmaDetectMismatch(Loc, Name, Value); } + void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { + First->PragmaDebug(Loc, DebugType); + Second->PragmaDebug(Loc, DebugType); + } + void PragmaMessage(SourceLocation Loc, StringRef Namespace, PragmaMessageKind Kind, StringRef Str) override { First->PragmaMessage(Loc, Namespace, Kind, Str); @@ -437,6 +459,16 @@ public: Second->PragmaWarningPop(Loc); } + void PragmaAssumeNonNullBegin(SourceLocation Loc) override { + First->PragmaAssumeNonNullBegin(Loc); + Second->PragmaAssumeNonNullBegin(Loc); + } + + void PragmaAssumeNonNullEnd(SourceLocation Loc) override { + First->PragmaAssumeNonNullEnd(Loc); + Second->PragmaAssumeNonNullEnd(Loc); + } + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override { First->MacroExpands(MacroNameTok, MD, Range, Args); @@ -462,9 +494,9 @@ public: Second->Defined(MacroNameTok, MD, Range); } - void SourceRangeSkipped(SourceRange Range) override { - First->SourceRangeSkipped(Range); - Second->SourceRangeSkipped(Range); + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { + First->SourceRangeSkipped(Range, EndifLoc); + Second->SourceRangeSkipped(Range, EndifLoc); } /// \brief Hook called whenever an \#if is seen. diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h index f96af665b1574..f122a008e4aa1 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h @@ -1,4 +1,4 @@ -//===--- PTHLexer.h - Lexer based on Pre-tokenized input --------*- C++ -*-===// +//===- PTHLexer.h - Lexer based on Pre-tokenized input ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,12 +14,15 @@ #ifndef LLVM_CLANG_LEX_PTHLEXER_H #define LLVM_CLANG_LEX_PTHLEXER_H +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/Token.h" namespace clang { +class Preprocessor; class PTHManager; -class PTHSpellingSearch; class PTHLexer : public PreprocessorLexer { SourceLocation FileStartLoc; @@ -33,7 +36,7 @@ class PTHLexer : public PreprocessorLexer { /// LastHashTokPtr - Pointer into TokBuf of the last processed '#' /// token that appears at the start of a line. - const unsigned char* LastHashTokPtr; + const unsigned char* LastHashTokPtr = nullptr; /// PPCond - Pointer to a side table in the PTH file that provides a /// a concise summary of the preprocessor conditional block structure. @@ -44,11 +47,8 @@ class PTHLexer : public PreprocessorLexer { /// to process when doing quick skipping of preprocessor blocks. const unsigned char* CurPPCondPtr; - PTHLexer(const PTHLexer &) = delete; - void operator=(const PTHLexer &) = delete; - /// ReadToken - Used by PTHLexer to read tokens TokBuf. - void ReadToken(Token& T); + void ReadToken(Token &T); bool LexEndOfFile(Token &Result); @@ -61,10 +61,13 @@ protected: friend class PTHManager; /// Create a PTHLexer for the specified token stream. - PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D, + PTHLexer(Preprocessor &pp, FileID FID, const unsigned char *D, const unsigned char* ppcond, PTHManager &PM); + public: - ~PTHLexer() override {} + PTHLexer(const PTHLexer &) = delete; + PTHLexer &operator=(const PTHLexer &) = delete; + ~PTHLexer() override = default; /// Lex - Return the next token. bool Lex(Token &Tok); @@ -99,6 +102,6 @@ public: bool SkipBlock(); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_PTHLEXER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h b/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h index f4e4774429f94..483b69f23a9cc 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PTHManager.h @@ -1,4 +1,4 @@ -//===--- PTHManager.h - Manager object for PTH processing -------*- C++ -*-===// +//===- PTHManager.h - Manager object for PTH processing ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,30 +17,33 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/OnDiskHashTable.h" +#include <memory> namespace llvm { - class MemoryBuffer; -} + +class MemoryBuffer; + +} // namespace llvm namespace clang { -class FileEntry; -class Preprocessor; -class PTHLexer; class DiagnosticsEngine; class FileSystemStatCache; +class Preprocessor; +class PTHLexer; class PTHManager : public IdentifierInfoLookup { friend class PTHLexer; - friend class PTHStatCache; - class PTHStringLookupTrait; class PTHFileLookupTrait; - typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup; - typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup; + class PTHStringLookupTrait; + + using PTHStringIdLookup = llvm::OnDiskChainedHashTable<PTHStringLookupTrait>; + using PTHFileLookup = llvm::OnDiskChainedHashTable<PTHFileLookupTrait>; /// The memory mapped PTH file. std::unique_ptr<const llvm::MemoryBuffer> Buf; @@ -70,7 +73,7 @@ class PTHManager : public IdentifierInfoLookup { /// PP - The Preprocessor object that will use this PTHManager to create /// PTHLexer objects. - Preprocessor* PP; + Preprocessor* PP = nullptr; /// SpellingBase - The base offset within the PTH memory buffer that /// contains the cached spellings for literals. @@ -89,16 +92,13 @@ class PTHManager : public IdentifierInfoLookup { std::unique_ptr<PTHStringIdLookup> stringIdLookup, unsigned numIds, const unsigned char *spellingBase, const char *originalSourceFile); - PTHManager(const PTHManager &) = delete; - void operator=(const PTHManager &) = delete; - /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached /// spelling for a token. unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer); /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the /// PTH file. - inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) { + IdentifierInfo *GetIdentifierInfo(unsigned PersistentID) { // Check if the IdentifierInfo has already been resolved. if (IdentifierInfo* II = PerIDCache[PersistentID]) return II; @@ -110,6 +110,8 @@ public: // The current PTH version. enum { Version = 10 }; + PTHManager(const PTHManager &) = delete; + PTHManager &operator=(const PTHManager &) = delete; ~PTHManager() override; /// getOriginalSourceFile - Return the full path to the original header @@ -120,18 +122,18 @@ public: /// get - Return the identifier token info for the specified named identifier. /// Unlike the version in IdentifierTable, this returns a pointer instead - /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// of a reference. If the pointer is nullptr then the IdentifierInfo cannot /// be found. IdentifierInfo *get(StringRef Name) override; /// Create - This method creates PTHManager objects. The 'file' argument - /// is the name of the PTH file. This method returns NULL upon failure. + /// is the name of the PTH file. This method returns nullptr upon failure. static PTHManager *Create(StringRef file, DiagnosticsEngine &Diags); void setPreprocessor(Preprocessor *pp) { PP = pp; } /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the - /// specified file. This method returns NULL if no cached tokens exist. + /// specified file. This method returns nullptr if no cached tokens exist. /// It is the responsibility of the caller to 'delete' the returned object. PTHLexer *CreateLexer(FileID FID); @@ -142,6 +144,6 @@ public: std::unique_ptr<FileSystemStatCache> createStatCache(); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_PTHMANAGER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h b/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h index 274f0dad3dd00..090ae2a98236e 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/Pragma.h @@ -1,4 +1,4 @@ -//===--- Pragma.h - Pragma registration and handling ------------*- C++ -*-===// +//===- Pragma.h - Pragma registration and handling --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,13 +17,13 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include <cassert> +#include <string> namespace clang { - class Preprocessor; - class Token; - class IdentifierInfo; - class PragmaNamespace; + +class PragmaNamespace; +class Preprocessor; +class Token; /** * \brief Describes how the pragma was introduced, e.g., with \#pragma, @@ -58,9 +58,10 @@ namespace clang { /// pragmas. class PragmaHandler { std::string Name; + public: + PragmaHandler() = default; explicit PragmaHandler(StringRef name) : Name(name) {} - PragmaHandler() {} virtual ~PragmaHandler(); StringRef getName() const { return Name; } @@ -89,8 +90,8 @@ public: class PragmaNamespace : public PragmaHandler { /// Handlers - This is a map of the handlers in this namespace with their name /// as key. - /// - llvm::StringMap<PragmaHandler*> Handlers; + llvm::StringMap<PragmaHandler *> Handlers; + public: explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {} ~PragmaNamespace() override; @@ -103,16 +104,13 @@ public: bool IgnoreNull = true) const; /// AddPragma - Add a pragma to this namespace. - /// void AddPragma(PragmaHandler *Handler); /// RemovePragmaHandler - Remove the given handler from the /// namespace. void RemovePragmaHandler(PragmaHandler *Handler); - bool IsEmpty() { - return Handlers.empty(); - } + bool IsEmpty() const { return Handlers.empty(); } void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken) override; @@ -120,7 +118,6 @@ public: PragmaNamespace *getIfNamespace() override { return this; } }; +} // namespace clang -} // end namespace clang - -#endif +#endif // LLVM_CLANG_LEX_PRAGMA_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h index fc2c507004001..5f7a6efcef107 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h @@ -1,4 +1,4 @@ -//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===// +//===- PreprocessingRecord.h - Record of Preprocessing ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,24 +11,33 @@ // of what occurred during preprocessing. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H #define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H -#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/PPCallbacks.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <utility> #include <vector> namespace clang { - class IdentifierInfo; - class MacroInfo; - class PreprocessingRecord; -} + +class PreprocessingRecord; + +} // namespace clang /// \brief Allocates memory within a Clang preprocessing record. void *operator new(size_t bytes, clang::PreprocessingRecord &PR, @@ -39,8 +48,12 @@ void operator delete(void *ptr, clang::PreprocessingRecord &PR, unsigned) noexcept; namespace clang { - class MacroDefinitionRecord; - class FileEntry; + +class FileEntry; +class IdentifierInfo; +class MacroInfo; +class SourceManager; +class Token; /// \brief Base class that describes a preprocessed entity, which may be a /// preprocessor directive or macro expansion. @@ -78,11 +91,11 @@ namespace clang { SourceRange Range; protected: - PreprocessedEntity(EntityKind Kind, SourceRange Range) - : Kind(Kind), Range(Range) { } - friend class PreprocessingRecord; + PreprocessedEntity(EntityKind Kind, SourceRange Range) + : Kind(Kind), Range(Range) {} + public: /// \brief Retrieve the kind of preprocessed entity stored in this object. EntityKind getKind() const { return Kind; } @@ -122,7 +135,7 @@ namespace clang { class PreprocessingDirective : public PreprocessedEntity { public: PreprocessingDirective(EntityKind Kind, SourceRange Range) - : PreprocessedEntity(Kind, Range) { } + : PreprocessedEntity(Kind, Range) {} // Implement isa/cast/dyncast/etc. static bool classof(const PreprocessedEntity *PD) { @@ -199,10 +212,13 @@ namespace clang { enum InclusionKind { /// \brief An \c \#include directive. Include, + /// \brief An Objective-C \c \#import directive. Import, + /// \brief A GNU \c \#include_next directive. IncludeNext, + /// \brief A Clang \c \#__include_macros directive. IncludeMacros }; @@ -316,11 +332,14 @@ namespace clang { /// value 1 corresponds to element 0 in the local entities vector, /// value 2 corresponds to element 1 in the local entities vector, etc. class PPEntityID { - int ID; - explicit PPEntityID(int ID) : ID(ID) {} friend class PreprocessingRecord; + + int ID = 0; + + explicit PPEntityID(int ID) : ID(ID) {} + public: - PPEntityID() : ID(0) {} + PPEntityID() = default; }; static PPEntityID getPPEntityID(unsigned Index, bool isLoaded) { @@ -331,7 +350,7 @@ namespace clang { llvm::DenseMap<const MacroInfo *, MacroDefinitionRecord *> MacroDefinitions; /// \brief External source of preprocessed entities. - ExternalPreprocessingRecordSource *ExternalSource; + ExternalPreprocessingRecordSource *ExternalSource = nullptr; /// \brief Retrieve the preprocessed entity at the given ID. PreprocessedEntity *getPreprocessedEntity(PPEntityID PPID); @@ -371,7 +390,7 @@ namespace clang { } /// \brief Deallocate memory in the preprocessing record. - void Deallocate(void *Ptr) { } + void Deallocate(void *Ptr) {} size_t getTotalMemory() const; @@ -397,11 +416,12 @@ namespace clang { iterator, int, std::random_access_iterator_tag, PreprocessedEntity *, int, PreprocessedEntity *, PreprocessedEntity *> { + friend class PreprocessingRecord; + PreprocessingRecord *Self; iterator(PreprocessingRecord *Self, int Position) : iterator::iterator_adaptor_base(Position), Self(Self) {} - friend class PreprocessingRecord; public: iterator() : iterator(nullptr, 0) {} @@ -451,7 +471,6 @@ namespace clang { /// encompasses. /// /// \param R the range to look for preprocessed entities. - /// llvm::iterator_range<iterator> getPreprocessedEntitiesInRange(SourceRange R); @@ -485,6 +504,9 @@ namespace clang { } private: + friend class ASTReader; + friend class ASTWriter; + void MacroExpands(const Token &Id, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override; void MacroDefined(const Token &Id, const MacroDirective *MD) override; @@ -500,11 +522,13 @@ namespace clang { const MacroDefinition &MD) override; void Ifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override; + /// \brief Hook called whenever the 'defined' operator is seen. void Defined(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range) override; - void SourceRangeSkipped(SourceRange Range) override; + void SourceRangeSkipped(SourceRange Range, + SourceLocation EndifLoc) override; void addMacroExpansion(const Token &Id, const MacroInfo *MI, SourceRange Range); @@ -517,11 +541,9 @@ namespace clang { } CachedRangeQuery; std::pair<int, int> getPreprocessedEntitiesInRangeSlow(SourceRange R); - - friend class ASTReader; - friend class ASTWriter; }; -} // end namespace clang + +} // namespace clang inline void *operator new(size_t bytes, clang::PreprocessingRecord &PR, unsigned alignment) noexcept { diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h index dba4b80f60719..485600f122329 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h @@ -1,4 +1,4 @@ -//===--- Preprocessor.h - C Language Family Preprocessor --------*- C++ -*-===// +//===- Preprocessor.h - C Language Family Preprocessor ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::Preprocessor interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LEX_PREPROCESSOR_H @@ -18,48 +18,70 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleLoader.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/PTHLexer.h" +#include "clang/Lex/Token.h" #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Registry.h" +#include <cassert> +#include <cstddef> +#include <cstdint> #include <memory> +#include <map> +#include <string> +#include <utility> #include <vector> namespace llvm { - template<unsigned InternalLen> class SmallString; -} + +template<unsigned InternalLen> class SmallString; + +} // namespace llvm namespace clang { -class SourceManager; +class CodeCompletionHandler; +class CommentHandler; +class DirectoryEntry; +class DirectoryLookup; class ExternalPreprocessorSource; -class FileManager; class FileEntry; +class FileManager; class HeaderSearch; +class MacroArgs; class MemoryBufferCache; -class PragmaNamespace; class PragmaHandler; -class CommentHandler; -class ScratchBuffer; -class TargetInfo; -class PPCallbacks; -class CodeCompletionHandler; -class DirectoryLookup; +class PragmaNamespace; class PreprocessingRecord; -class ModuleLoader; -class PTHManager; +class PreprocessorLexer; class PreprocessorOptions; +class PTHManager; +class ScratchBuffer; +class TargetInfo; /// \brief Stores token information for comparing actual tokens with /// predefined values. Only handles simple tokens and identifiers. @@ -75,7 +97,9 @@ public: assert(!tok::isLiteral(Kind) && "Literals are not supported."); assert(!tok::isAnnotation(Kind) && "Annotations are not supported."); } + TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {} + bool operator==(const Token &Tok) const { return Tok.getKind() == Kind && (!II || II == Tok.getIdentifierInfo()); @@ -84,9 +108,14 @@ public: /// \brief Context in which macro name is used. enum MacroUse { - MU_Other = 0, // other than #define or #undef - MU_Define = 1, // macro name specified in #define - MU_Undef = 2 // macro name specified in #undef + // other than #define or #undef + MU_Other = 0, + + // macro name specified in #define + MU_Define = 1, + + // macro name specified in #undef + MU_Undef = 2 }; /// \brief Engages in a tight little dance with the lexer to efficiently @@ -96,11 +125,14 @@ enum MacroUse { /// know anything about preprocessor-level issues like the \#include stack, /// token expansion, etc. class Preprocessor { + friend class VAOptDefinitionContext; + friend class VariadicMacroScopeGuard; + std::shared_ptr<PreprocessorOptions> PPOpts; DiagnosticsEngine *Diags; LangOptions &LangOpts; - const TargetInfo *Target; - const TargetInfo *AuxTarget; + const TargetInfo *Target = nullptr; + const TargetInfo *AuxTarget = nullptr; FileManager &FileMgr; SourceManager &SourceMgr; MemoryBufferCache &PCMCache; @@ -111,7 +143,6 @@ class Preprocessor { /// \brief External source of macros. ExternalPreprocessorSource *ExternalSource; - /// An optional PTHManager object used for getting tokens from /// a token cache rather than lexing the original source file. std::unique_ptr<PTHManager> PTH; @@ -130,6 +161,7 @@ class Preprocessor { IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma IdentifierInfo *Ident__identifier; // __identifier IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_extension; // __has_extension IdentifierInfo *Ident__has_builtin; // __has_builtin @@ -141,10 +173,17 @@ class Preprocessor { IdentifierInfo *Ident__building_module; // __building_module IdentifierInfo *Ident__MODULE__; // __MODULE__ IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute + IdentifierInfo *Ident__has_c_attribute; // __has_c_attribute IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute + IdentifierInfo *Ident__is_target_arch; // __is_target_arch + IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor + IdentifierInfo *Ident__is_target_os; // __is_target_os + IdentifierInfo *Ident__is_target_environment; // __is_target_environment SourceLocation DATELoc, TIMELoc; - unsigned CounterValue; // Next __COUNTER__ value. + + // Next __COUNTER__ value, starts at 0. + unsigned CounterValue = 0; enum { /// \brief Maximum depth of \#includes. @@ -218,19 +257,19 @@ class Preprocessor { /// \brief True if we want to ignore EOF token and continue later on (thus /// avoid tearing the Lexer and etc. down). - bool IncrementalProcessing; + bool IncrementalProcessing = false; /// The kind of translation unit we are processing. TranslationUnitKind TUKind; /// \brief The code-completion handler. - CodeCompletionHandler *CodeComplete; + CodeCompletionHandler *CodeComplete = nullptr; /// \brief The file that we're performing code-completion for, if any. - const FileEntry *CodeCompletionFile; + const FileEntry *CodeCompletionFile = nullptr; /// \brief The offset in file for the code-completion point. - unsigned CodeCompletionOffset; + unsigned CodeCompletionOffset = 0; /// \brief The location for the code-completion point. This gets instantiated /// when the CodeCompletionFile gets \#include'ed for preprocessing. @@ -250,11 +289,11 @@ class Preprocessor { SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> ModuleImportPath; /// \brief Whether the last token we lexed was an '@'. - bool LastTokenWasAt; + bool LastTokenWasAt = false; /// \brief Whether the module import expects an identifier next. Otherwise, /// it expects a '.' or ';'. - bool ModuleImportExpectsIdentifier; + bool ModuleImportExpectsIdentifier = false; /// \brief The source location of the currently-active /// \#pragma clang arc_cf_code_audited begin. @@ -265,16 +304,16 @@ class Preprocessor { SourceLocation PragmaAssumeNonNullLoc; /// \brief True if we hit the code-completion point. - bool CodeCompletionReached; + bool CodeCompletionReached = false; /// \brief The code completion token containing the information /// on the stem that is to be code completed. - IdentifierInfo *CodeCompletionII; + IdentifierInfo *CodeCompletionII = nullptr; /// \brief The directory that the main file should be considered to occupy, /// if it does not correspond to a real file (as happens when building a /// module). - const DirectoryEntry *MainFileDir; + const DirectoryEntry *MainFileDir = nullptr; /// \brief The number of bytes that we will initially skip when entering the /// main file, along with a flag that indicates whether skipping this number @@ -283,6 +322,26 @@ class Preprocessor { /// This is used when loading a precompiled preamble. std::pair<int, bool> SkipMainFilePreamble; +public: + struct PreambleSkipInfo { + SourceLocation HashTokenLoc; + SourceLocation IfTokenLoc; + bool FoundNonSkipPortion; + bool FoundElse; + SourceLocation ElseLoc; + + PreambleSkipInfo(SourceLocation HashTokenLoc, SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc) + : HashTokenLoc(HashTokenLoc), IfTokenLoc(IfTokenLoc), + FoundNonSkipPortion(FoundNonSkipPortion), FoundElse(FoundElse), + ElseLoc(ElseLoc) {} + }; + +private: + friend class ASTReader; + friend class MacroArgs; + class PreambleConditionalStackStore { enum State { Off = 0, @@ -291,7 +350,7 @@ class Preprocessor { }; public: - PreambleConditionalStackStore() : ConditionalStackState(Off) {} + PreambleConditionalStackStore() = default; void startRecording() { ConditionalStackState = Recording; } void startReplaying() { ConditionalStackState = Replaying; } @@ -316,9 +375,15 @@ class Preprocessor { bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } + bool reachedEOFWhileSkipping() const { return SkipInfo.hasValue(); } + + void clearSkipInfo() { SkipInfo.reset(); } + + llvm::Optional<PreambleSkipInfo> SkipInfo; + private: SmallVector<PPConditionalInfo, 4> ConditionalStack; - State ConditionalStackState; + State ConditionalStackState = Off; } PreambleConditionalStack; /// \brief The current top of the stack that we're lexing from if @@ -337,14 +402,14 @@ class Preprocessor { /// if not expanding a macro. /// /// This is an alias for either CurLexer or CurPTHLexer. - PreprocessorLexer *CurPPLexer; + PreprocessorLexer *CurPPLexer = nullptr; /// \brief Used to find the current FileEntry, if CurLexer is non-null /// and if applicable. /// /// This allows us to implement \#include_next and find directory-specific /// properties. - const DirectoryLookup *CurDirLookup; + const DirectoryLookup *CurDirLookup = nullptr; /// \brief The current macro we are expanding, if we are expanding a macro. /// @@ -358,11 +423,11 @@ class Preprocessor { CLK_TokenLexer, CLK_CachingLexer, CLK_LexAfterModuleImport - } CurLexerKind; + } CurLexerKind = CLK_Lexer; /// \brief If the current lexer is for a submodule that is being built, this /// is that submodule. - Module *CurLexerSubmodule; + Module *CurLexerSubmodule = nullptr; /// \brief Keeps track of the stack of files currently /// \#included, and macros currently being expanded from, not counting @@ -401,27 +466,31 @@ class Preprocessor { Token Tok; MacroDefinition MD; SourceRange Range; + MacroExpandsInfo(Token Tok, MacroDefinition MD, SourceRange Range) - : Tok(Tok), MD(MD), Range(Range) { } + : Tok(Tok), MD(MD), Range(Range) {} }; SmallVector<MacroExpandsInfo, 2> DelayedMacroExpandsCallbacks; /// Information about a name that has been used to define a module macro. struct ModuleMacroInfo { - ModuleMacroInfo(MacroDirective *MD) - : MD(MD), ActiveModuleMacrosGeneration(0), IsAmbiguous(false) {} - /// The most recent macro directive for this identifier. MacroDirective *MD; + /// The active module macros for this identifier. - llvm::TinyPtrVector<ModuleMacro*> ActiveModuleMacros; + llvm::TinyPtrVector<ModuleMacro *> ActiveModuleMacros; + /// The generation number at which we last updated ActiveModuleMacros. /// \see Preprocessor::VisibleModules. - unsigned ActiveModuleMacrosGeneration; + unsigned ActiveModuleMacrosGeneration = 0; + /// Whether this macro name is ambiguous. - bool IsAmbiguous; + bool IsAmbiguous = false; + /// The module macros that are overridden by this macro. - llvm::TinyPtrVector<ModuleMacro*> OverriddenMacros; + llvm::TinyPtrVector<ModuleMacro *> OverriddenMacros; + + ModuleMacroInfo(MacroDirective *MD) : MD(MD) {} }; /// The state of a macro for an identifier. @@ -456,15 +525,18 @@ class Preprocessor { public: MacroState() : MacroState(nullptr) {} MacroState(MacroDirective *MD) : State(MD) {} + MacroState(MacroState &&O) noexcept : State(O.State) { O.State = (MacroDirective *)nullptr; } + MacroState &operator=(MacroState &&O) noexcept { auto S = O.State; O.State = (MacroDirective *)nullptr; State = S; return *this; } + ~MacroState() { if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) Info->~ModuleMacroInfo(); @@ -475,6 +547,7 @@ class Preprocessor { return Info->MD; return State.get<MacroDirective*>(); } + void setLatest(MacroDirective *MD) { if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) Info->MD = MD; @@ -486,6 +559,7 @@ class Preprocessor { auto *Info = getModuleInfo(PP, II); return Info ? Info->IsAmbiguous : false; } + ArrayRef<ModuleMacro *> getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { if (auto *Info = getModuleInfo(PP, II)) @@ -498,7 +572,7 @@ class Preprocessor { // FIXME: Incorporate module macros into the result of this. if (auto *Latest = getLatest()) return Latest->findDirectiveAtLoc(Loc, SourceMgr); - return MacroDirective::DefInfo(); + return {}; } void overrideActiveModuleMacros(Preprocessor &PP, IdentifierInfo *II) { @@ -510,11 +584,13 @@ class Preprocessor { Info->IsAmbiguous = false; } } + ArrayRef<ModuleMacro*> getOverriddenMacros() const { if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) return Info->OverriddenMacros; return None; } + void setOverriddenMacros(Preprocessor &PP, ArrayRef<ModuleMacro *> Overrides) { auto *Info = State.dyn_cast<ModuleMacroInfo*>(); @@ -537,31 +613,33 @@ class Preprocessor { /// the reverse order (the latest one is in the head of the list). /// /// This mapping lives within the \p CurSubmoduleState. - typedef llvm::DenseMap<const IdentifierInfo *, MacroState> MacroMap; - - friend class ASTReader; + using MacroMap = llvm::DenseMap<const IdentifierInfo *, MacroState>; struct SubmoduleState; /// \brief Information about a submodule that we're currently building. struct BuildingSubmoduleInfo { - BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma, - SubmoduleState *OuterSubmoduleState, - unsigned OuterPendingModuleMacroNames) - : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma), - OuterSubmoduleState(OuterSubmoduleState), - OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {} - /// The module that we are building. Module *M; + /// The location at which the module was included. SourceLocation ImportLoc; + /// Whether we entered this submodule via a pragma. bool IsPragma; + /// The previous SubmoduleState. SubmoduleState *OuterSubmoduleState; + /// The number of pending module macro names when we started building this. unsigned OuterPendingModuleMacroNames; + + BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma, + SubmoduleState *OuterSubmoduleState, + unsigned OuterPendingModuleMacroNames) + : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma), + OuterSubmoduleState(OuterSubmoduleState), + OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {} }; SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack; @@ -569,12 +647,14 @@ class Preprocessor { struct SubmoduleState { /// The macros for the submodule. MacroMap Macros; + /// The set of modules that are visible within the submodule. VisibleModuleSet VisibleModules; + // FIXME: CounterValue? // FIXME: PragmaPushMacroInfo? }; - std::map<Module*, SubmoduleState> Submodules; + std::map<Module *, SubmoduleState> Submodules; /// The preprocessor state for preprocessing outside of any submodule. SubmoduleState NullSubmoduleState; @@ -587,11 +667,11 @@ class Preprocessor { llvm::FoldingSet<ModuleMacro> ModuleMacros; /// The names of potential module macros that we've not yet processed. - llvm::SmallVector<const IdentifierInfo*, 32> PendingModuleMacroNames; + llvm::SmallVector<const IdentifierInfo *, 32> PendingModuleMacroNames; /// The list of module macros, for each identifier, that are not overridden by /// any other module macro. - llvm::DenseMap<const IdentifierInfo *, llvm::TinyPtrVector<ModuleMacro*>> + llvm::DenseMap<const IdentifierInfo *, llvm::TinyPtrVector<ModuleMacro *>> LeafModuleMacros; /// \brief Macros that we want to warn because they are not used at the end @@ -603,25 +683,35 @@ class Preprocessor { /// just so that we can report that they are unused, we just warn using /// the SourceLocations of this set (that will be filled by the ASTReader). /// We are using SmallPtrSet instead of a vector for faster removal. - typedef llvm::SmallPtrSet<SourceLocation, 32> WarnUnusedMacroLocsTy; + using WarnUnusedMacroLocsTy = llvm::SmallPtrSet<SourceLocation, 32>; WarnUnusedMacroLocsTy WarnUnusedMacroLocs; /// \brief A "freelist" of MacroArg objects that can be /// reused for quick allocation. - MacroArgs *MacroArgCache; - friend class MacroArgs; + MacroArgs *MacroArgCache = nullptr; /// For each IdentifierInfo used in a \#pragma push_macro directive, /// we keep a MacroInfo stack used to restore the previous macro value. - llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo; + llvm::DenseMap<IdentifierInfo *, std::vector<MacroInfo *>> + PragmaPushMacroInfo; // Various statistics we track for performance analysis. - unsigned NumDirectives, NumDefined, NumUndefined, NumPragma; - unsigned NumIf, NumElse, NumEndif; - unsigned NumEnteredSourceFiles, MaxIncludeStackDepth; - unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; - unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; - unsigned NumSkipped; + unsigned NumDirectives = 0; + unsigned NumDefined = 0; + unsigned NumUndefined = 0; + unsigned NumPragma = 0; + unsigned NumIf = 0; + unsigned NumElse = 0; + unsigned NumEndif = 0; + unsigned NumEnteredSourceFiles = 0; + unsigned MaxIncludeStackDepth = 0; + unsigned NumMacroExpanded = 0; + unsigned NumFnMacroExpanded = 0; + unsigned NumBuiltinMacroExpanded = 0; + unsigned NumFastMacroExpanded = 0; + unsigned NumTokenPaste = 0; + unsigned NumFastTokenPaste = 0; + unsigned NumSkipped = 0; /// \brief The predefined macros that preprocessor should use from the /// command line etc. @@ -643,17 +733,17 @@ class Preprocessor { /// going to lex in the cache and when it finishes the tokens are removed /// from the end of the cache. SmallVector<Token, 16> MacroExpandedTokens; - std::vector<std::pair<TokenLexer *, size_t> > MacroExpandingLexersStack; + std::vector<std::pair<TokenLexer *, size_t>> MacroExpandingLexersStack; /// \brief A record of the macro definitions and expansions that /// occurred during preprocessing. /// /// This is an optional side structure that can be enabled with /// \c createPreprocessingRecord() prior to preprocessing. - PreprocessingRecord *Record; + PreprocessingRecord *Record = nullptr; /// Cached tokens state. - typedef SmallVector<Token, 1> CachedTokensTy; + using CachedTokensTy = SmallVector<Token, 1>; /// \brief Cached tokens are stored here when we do backtracking or /// lookahead. They are "lexed" by the CachingLex() method. @@ -664,7 +754,7 @@ class Preprocessor { /// /// If it points beyond the CachedTokens vector, it means that a normal /// Lex() should be invoked. - CachedTokensTy::size_type CachedLexPos; + CachedTokensTy::size_type CachedLexPos = 0; /// \brief Stack of backtrack positions, allowing nested backtracks. /// @@ -680,7 +770,7 @@ class Preprocessor { /// MacroInfos are managed as a chain for easy disposal. This is the head /// of that list. - MacroInfoChain *MIChainHead; + MacroInfoChain *MIChainHead = nullptr; void updateOutOfDateIdentifier(IdentifierInfo &II) const; @@ -853,7 +943,7 @@ public: MacroDefinition getMacroDefinition(const IdentifierInfo *II) { if (!II->hasMacroDefinition()) - return MacroDefinition(); + return {}; MacroState &S = CurSubmoduleState->Macros[II]; auto *MD = S.getLatest(); @@ -867,7 +957,7 @@ public: MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, SourceLocation Loc) { if (!II->hadMacroDefinition()) - return MacroDefinition(); + return {}; MacroState &S = CurSubmoduleState->Macros[II]; MacroDirective::DefInfo DI; @@ -923,6 +1013,7 @@ public: MacroInfo *MI) { return appendDefMacroDirective(II, MI, MI->getDefinitionLoc()); } + /// \brief Set a MacroDirective that was loaded from a PCH file. void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *ED, MacroDirective *MD); @@ -946,10 +1037,12 @@ public: /// Iterators for the macro history table. Currently defined macros have /// IdentifierInfo::hasMacroDefinition() set and an empty /// MacroInfo::getUndefLoc() at the head of the list. - typedef MacroMap::const_iterator macro_iterator; + using macro_iterator = MacroMap::const_iterator; + macro_iterator macro_begin(bool IncludeExternalMacros = true) const; macro_iterator macro_end(bool IncludeExternalMacros = true) const; llvm::iterator_range<macro_iterator> + macros(bool IncludeExternalMacros = true) const { return llvm::make_range(macro_begin(IncludeExternalMacros), macro_end(IncludeExternalMacros)); @@ -963,6 +1056,7 @@ public: ArrayRef<TokenValue> Tokens) const; const std::string &getPredefines() const { return Predefines; } + /// \brief Set the predefines for this Preprocessor. /// /// These predefines are automatically injected when parsing the main file. @@ -1087,6 +1181,7 @@ public: bool DisableMacroExpansion) { EnterTokenStream(Toks.release(), NumToks, DisableMacroExpansion, true); } + void EnterTokenStream(ArrayRef<Token> Toks, bool DisableMacroExpansion) { EnterTokenStream(Toks.data(), Toks.size(), DisableMacroExpansion, false); } @@ -1605,7 +1700,6 @@ private: llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons; public: - /// \brief Specifies the reason for poisoning an identifier. /// /// If that identifier is accessed while poisoned, then this reason will be @@ -1655,7 +1749,6 @@ public: /// lex again. bool HandleIdentifier(Token &Identifier); - /// \brief Callback invoked when the lexer hits the end of the current file. /// /// This either returns the EOF token and returns true, or @@ -1760,6 +1853,8 @@ public: Module *LeaveSubmodule(bool ForPragma); private: + friend void TokenLexer::ExpandFunctionArguments(); + void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, @@ -1818,7 +1913,6 @@ private: /// /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and /// returns a nullptr if an invalid sequence of tokens is encountered. - MacroInfo *ReadOptionalMacroParameterListAndBody( const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard); @@ -1836,7 +1930,8 @@ private: /// \p FoundElse is false, then \#else directives are ok, if not, then we have /// already seen one so a \#else directive is a duplicate. When this returns, /// the caller can lex the first valid token. - void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + void SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, + SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, SourceLocation ElseLoc = SourceLocation()); @@ -1848,6 +1943,7 @@ private: struct DirectiveEvalResult { /// Whether the expression was evaluated as true or not. bool Conditional; + /// True if the expression contained identifiers that were undefined. bool IncludedUndefinedIds; }; @@ -1877,8 +1973,8 @@ private: /// from the end of the cache. Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, ArrayRef<Token> tokens); + void removeCachedMacroExpandedTokensOfLastLexer(); - friend void TokenLexer::ExpandFunctionArguments(); /// Determine whether the next preprocessor token to be /// lexed is a '('. If so, consume the token and return true, if not, this @@ -1934,17 +2030,21 @@ private: //===--------------------------------------------------------------------===// // Caching stuff. void CachingLex(Token &Result); + bool InCachingLexMode() const { // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means // that we are past EOF, not that we are in CachingLex mode. return !CurPPLexer && !CurTokenLexer && !CurPTHLexer && !IncludeMacroStack.empty(); } + void EnterCachingLexMode(); + void ExitCachingLexMode() { if (InCachingLexMode()) RemoveTopOfLexerStack(); } + const Token &PeekAhead(unsigned N); void AnnotatePreviousCachedTokens(const Token &Tok); @@ -2015,9 +2115,15 @@ public: PreambleConditionalStack.setStack(s); } - void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) { + void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s, + llvm::Optional<PreambleSkipInfo> SkipInfo) { PreambleConditionalStack.startReplaying(); PreambleConditionalStack.setStack(s); + PreambleConditionalStack.SkipInfo = SkipInfo; + } + + llvm::Optional<PreambleSkipInfo> getPreambleSkipInfo() const { + return PreambleConditionalStack.SkipInfo; } private: @@ -2030,16 +2136,18 @@ private: void HandleUndefDirective(); // Conditional Inclusion. - void HandleIfdefDirective(Token &Tok, bool isIfndef, - bool ReadAnyTokensBeforeDirective); - void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective); + void HandleIfdefDirective(Token &Tok, const Token &HashToken, + bool isIfndef, bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &Tok, const Token &HashToken, + bool ReadAnyTokensBeforeDirective); void HandleEndifDirective(Token &Tok); - void HandleElseDirective(Token &Tok); - void HandleElifDirective(Token &Tok); + void HandleElseDirective(Token &Tok, const Token &HashToken); + void HandleElifDirective(Token &Tok, const Token &HashToken); // Pragmas. void HandlePragmaDirective(SourceLocation IntroducerLoc, PragmaIntroducerKind Introducer); + public: void HandlePragmaOnce(Token &OnceTok); void HandlePragmaMark(); @@ -2073,8 +2181,8 @@ public: }; /// \brief Registry of pragma handlers added by plugins -typedef llvm::Registry<PragmaHandler> PragmaHandlerRegistry; +using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_PREPROCESSOR_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h index 5c2e4d41454b6..ff71d11b4511b 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h @@ -1,4 +1,4 @@ -//===--- PreprocessorLexer.h - C Language Family Lexer ----------*- C++ -*-===// +//===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the PreprocessorLexer interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H @@ -17,8 +17,10 @@ #include "clang/Lex/MultipleIncludeOpt.h" #include "clang/Lex/Token.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include <cassert> namespace clang { @@ -27,25 +29,29 @@ class Preprocessor; class PreprocessorLexer { virtual void anchor(); + protected: - Preprocessor *PP; // Preprocessor object controlling lexing. + friend class Preprocessor; + + // Preprocessor object controlling lexing. + Preprocessor *PP = nullptr; /// The SourceManager FileID corresponding to the file being lexed. const FileID FID; /// \brief Number of SLocEntries before lexing the file. - unsigned InitialNumSLocEntries; + unsigned InitialNumSLocEntries = 0; //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. //===--------------------------------------------------------------------===// /// \brief True when parsing \#XXX; turns '\\n' into a tok::eod token. - bool ParsingPreprocessorDirective; + bool ParsingPreprocessorDirective = false; /// \brief True after \#include; turns \<xx> into a tok::angle_string_literal /// token. - bool ParsingFilename; + bool ParsingFilename = false; /// \brief True if in raw mode. /// @@ -60,7 +66,7 @@ protected: /// 5. No callbacks are made into the preprocessor. /// /// Note that in raw mode that the PP pointer may be null. - bool LexingRawMode; + bool LexingRawMode = false; /// \brief A state machine that detects the \#ifndef-wrapping a file /// idiom for the multiple-include optimization. @@ -70,19 +76,9 @@ protected: /// we are currently in. SmallVector<PPConditionalInfo, 4> ConditionalStack; - PreprocessorLexer(const PreprocessorLexer &) = delete; - void operator=(const PreprocessorLexer &) = delete; - friend class Preprocessor; - + PreprocessorLexer() : FID() {} PreprocessorLexer(Preprocessor *pp, FileID fid); - - PreprocessorLexer() - : PP(nullptr), InitialNumSLocEntries(0), - ParsingPreprocessorDirective(false), - ParsingFilename(false), - LexingRawMode(false) {} - - virtual ~PreprocessorLexer() {} + virtual ~PreprocessorLexer() = default; virtual void IndirectLex(Token& Result) = 0; @@ -128,6 +124,8 @@ protected: unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } public: + PreprocessorLexer(const PreprocessorLexer &) = delete; + PreprocessorLexer &operator=(const PreprocessorLexer &) = delete; //===--------------------------------------------------------------------===// // Misc. lexing methods. @@ -168,12 +166,13 @@ public: /// \brief Iterator that traverses the current stack of preprocessor /// conditional directives (\#if/\#ifdef/\#ifndef). - typedef SmallVectorImpl<PPConditionalInfo>::const_iterator - conditional_iterator; + using conditional_iterator = + SmallVectorImpl<PPConditionalInfo>::const_iterator; conditional_iterator conditional_begin() const { return ConditionalStack.begin(); } + conditional_iterator conditional_end() const { return ConditionalStack.end(); } @@ -184,6 +183,6 @@ public: } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h index d91c665cf1dd5..55fc305dc2950 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h @@ -1,4 +1,4 @@ -//===--- PreprocessorOptions.h ----------------------------------*- C++ -*-===// +//===- PreprocessorOptions.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,30 +10,30 @@ #ifndef LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ #define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" -#include <cassert> +#include <memory> #include <set> #include <string> #include <utility> #include <vector> namespace llvm { - class MemoryBuffer; -} -namespace clang { +class MemoryBuffer; + +} // namespace llvm -class Preprocessor; -class LangOptions; +namespace clang { /// \brief Enumerate the kinds of standard library that enum ObjCXXARCStandardLibraryKind { ARCXX_nolib, + /// \brief libc++ ARCXX_libcxx, + /// \brief libstdc++ ARCXX_libstdcxx }; @@ -42,17 +42,17 @@ enum ObjCXXARCStandardLibraryKind { /// used in preprocessor initialization to InitializePreprocessor(). class PreprocessorOptions { public: - std::vector<std::pair<std::string, bool/*isUndef*/> > Macros; + std::vector<std::pair<std::string, bool/*isUndef*/>> Macros; std::vector<std::string> Includes; std::vector<std::string> MacroIncludes; /// \brief Initialize the preprocessor with the compiler and target specific /// predefines. - unsigned UsePredefines : 1; + bool UsePredefines = true; /// \brief Whether we should maintain a detailed record of all macro /// definitions and expansions. - unsigned DetailedRecord : 1; + bool DetailedRecord = false; /// The implicit PCH included at the start of the translation unit, or empty. std::string ImplicitPCHInclude; @@ -62,13 +62,13 @@ public: /// \brief When true, disables most of the normal validation performed on /// precompiled headers. - bool DisablePCHValidation; + bool DisablePCHValidation = false; /// \brief When true, a PCH with compiler errors will not be rejected. - bool AllowPCHWithCompilerErrors; + bool AllowPCHWithCompilerErrors = false; /// \brief Dump declarations that are deserialized from PCH, for testing. - bool DumpDeserializedPCHDecls; + bool DumpDeserializedPCHDecls = false; /// \brief This is a set of names for decls that we do not want to be /// deserialized, and we emit an error if they are; for testing purposes. @@ -86,7 +86,7 @@ public: /// When the lexer is done, one of the things that need to be preserved is the /// conditional #if stack, so the ASTWriter/ASTReader can save/restore it when /// processing the rest of the file. - bool GeneratePreamble; + bool GeneratePreamble = false; /// The implicit PTH input included at the start of the translation unit, or /// empty. @@ -107,7 +107,7 @@ public: /// \brief True if the SourceManager should report the original file name for /// contents of files that were remapped to other files. Defaults to true. - bool RemappedFilesKeepOriginalName; + bool RemappedFilesKeepOriginalName = true; /// \brief The set of file remappings, which take existing files on /// the system (the first part of each pair) and gives them the @@ -126,12 +126,12 @@ public: /// This flag defaults to false; it can be set true only through direct /// manipulation of the compiler invocation object, in cases where the /// compiler invocation and its buffers will be reused. - bool RetainRemappedFileBuffers; + bool RetainRemappedFileBuffers = false; /// \brief The Objective-C++ ARC standard library that we should support, /// by providing appropriate definitions to retrofit the standard library /// with support for lifetime-qualified pointers. - ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary; + ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; /// \brief Records the set of modules class FailedModulesSet { @@ -156,18 +156,11 @@ public: std::shared_ptr<FailedModulesSet> FailedModules; public: - PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), - DisablePCHValidation(false), - AllowPCHWithCompilerErrors(false), - DumpDeserializedPCHDecls(false), - PrecompiledPreambleBytes(0, true), - GeneratePreamble(false), - RemappedFilesKeepOriginalName(true), - RetainRemappedFileBuffers(false), - ObjCXXARCStandardLibrary(ARCXX_nolib) { } + PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {} void addMacroDef(StringRef Name) { Macros.emplace_back(Name, false); } void addMacroUndef(StringRef Name) { Macros.emplace_back(Name, true); } + void addRemappedFile(StringRef From, StringRef To) { RemappedFiles.emplace_back(From, To); } @@ -195,10 +188,10 @@ public: LexEditorPlaceholders = true; RetainRemappedFileBuffers = true; PrecompiledPreambleBytes.first = 0; - PrecompiledPreambleBytes.second = 0; + PrecompiledPreambleBytes.second = false; } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_ diff --git a/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h index fdeed44d8f9b3..b8b0beabf2ba2 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/TokenLexer.h @@ -1,4 +1,4 @@ -//===--- TokenLexer.h - Lex from a token buffer -----------------*- C++ -*-===// +//===- TokenLexer.h - Lex from a token buffer -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,29 +15,31 @@ #define LLVM_CLANG_LEX_TOKENLEXER_H #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" namespace clang { - class MacroInfo; - class Preprocessor; - class Token; - class MacroArgs; + +class MacroArgs; +class MacroInfo; +class Preprocessor; +class Token; +class VAOptExpansionContext; /// TokenLexer - This implements a lexer that returns tokens from a macro body /// or token stream instead of lexing from a character buffer. This is used for /// macro expansion and _Pragma handling, for example. -/// class TokenLexer { + friend class Preprocessor; + /// Macro - The macro we are expanding from. This is null if expanding a /// token stream. - /// - MacroInfo *Macro; + MacroInfo *Macro = nullptr; /// ActualArgs - The actual arguments specified for a function-like macro, or /// null. The TokenLexer owns the pointed-to object. - MacroArgs *ActualArgs; + MacroArgs *ActualArgs = nullptr; /// PP - The current preprocessor object we are expanding for. - /// Preprocessor &PP; /// Tokens - This is the pointer to an array of tokens that the macro is @@ -49,15 +51,12 @@ class TokenLexer { /// Note that if it points into Preprocessor's cache buffer, the Preprocessor /// may update the pointer as needed. const Token *Tokens; - friend class Preprocessor; /// NumTokens - This is the length of the Tokens array. - /// unsigned NumTokens; - /// CurToken - This is the next token that Lex will return. - /// - unsigned CurToken; + /// This is the index of the next token that Lex will return. + unsigned CurTokenIdx; /// ExpandLocStart/End - The source location range where this macro was /// expanded. @@ -73,6 +72,7 @@ class TokenLexer { /// \brief Location of the macro definition. SourceLocation MacroDefStart; + /// \brief Length of the macro definition. unsigned MacroDefLength; @@ -99,8 +99,6 @@ class TokenLexer { /// should not be subject to further macro expansion. bool DisableMacroExpansion : 1; - TokenLexer(const TokenLexer &) = delete; - void operator=(const TokenLexer &) = delete; public: /// Create a TokenLexer for the specified macro with the specified actual /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. @@ -108,26 +106,30 @@ public: /// identifier for an object-like macro. TokenLexer(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, MacroArgs *ActualArgs, Preprocessor &pp) - : Macro(nullptr), ActualArgs(nullptr), PP(pp), OwnsTokens(false) { + : PP(pp), OwnsTokens(false) { Init(Tok, ILEnd, MI, ActualArgs); } - /// Init - Initialize this TokenLexer to expand from the specified macro - /// with the specified argument information. Note that this ctor takes - /// ownership of the ActualArgs pointer. ILEnd specifies the location of the - /// ')' for a function-like macro or the identifier for an object-like macro. - void Init(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, - MacroArgs *ActualArgs); - /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is /// specified, this takes ownership of the tokens and delete[]'s them when /// the token lexer is empty. TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion, bool ownsTokens, Preprocessor &pp) - : Macro(nullptr), ActualArgs(nullptr), PP(pp), OwnsTokens(false) { + : PP(pp), OwnsTokens(false) { Init(TokArray, NumToks, DisableExpansion, ownsTokens); } + TokenLexer(const TokenLexer &) = delete; + TokenLexer &operator=(const TokenLexer &) = delete; + ~TokenLexer() { destroy(); } + + /// Init - Initialize this TokenLexer to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. ILEnd specifies the location of the + /// ')' for a function-like macro or the identifier for an object-like macro. + void Init(Token &Tok, SourceLocation ILEnd, MacroInfo *MI, + MacroArgs *ActualArgs); + /// Init - Initialize this TokenLexer with the specified token stream. /// This does not take ownership of the specified token vector. /// @@ -136,8 +138,6 @@ public: void Init(const Token *TokArray, unsigned NumToks, bool DisableMacroExpansion, bool OwnsTokens); - ~TokenLexer() { destroy(); } - /// isNextTokenLParen - If the next token lexed will pop this macro off the /// expansion stack, return 2. If the next unexpanded token is a '(', return /// 1, otherwise return 0. @@ -156,15 +156,54 @@ private: /// isAtEnd - Return true if the next lex call will pop this macro off the /// include stack. bool isAtEnd() const { - return CurToken == NumTokens; + return CurTokenIdx == NumTokens; } - /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## - /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there - /// are is another ## after it, chomp it iteratively. Return the result as - /// Tok. If this returns true, the caller should immediately return the + /// Concatenates the next (sub-)sequence of \p Tokens separated by '##' + /// starting with LHSTok - stopping when we encounter a token that is neither + /// '##' nor preceded by '##'. Places the result back into \p LHSTok and sets + /// \p CurIdx to point to the token following the last one that was pasted. + /// + /// Also performs the MSVC extension wide-literal token pasting involved with: + /// \code L #macro-arg. \endcode + /// + /// \param[in,out] LHSTok - Contains the token to the left of '##' in \p + /// Tokens upon entry and will contain the resulting concatenated Token upon + /// exit. + /// + /// \param[in] TokenStream - The stream of Tokens we are lexing from. + /// + /// \param[in,out] CurIdx - Upon entry, \pTokens[\pCurIdx] must equal '##' + /// (with the exception of the MSVC extension mentioned above). Upon exit, it + /// is set to the index of the token following the last token that was + /// concatenated together. + /// + /// \returns If this returns true, the caller should immediately return the /// token. - bool PasteTokens(Token &Tok); + bool pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream, + unsigned int &CurIdx); + + /// Calls pasteTokens above, passing in the '*this' object's Tokens and + /// CurTokenIdx data members. + bool pasteTokens(Token &Tok); + + + /// Takes the tail sequence of tokens within ReplacementToks that represent + /// the just expanded __VA_OPT__ tokens (possibly zero tokens) and transforms + /// them into a string. \p VCtx is used to determine which token represents + /// the first __VA_OPT__ replacement token. + /// + /// \param[in,out] ReplacementToks - Contains the current Replacement Tokens + /// (prior to rescanning and token pasting), the tail end of which represents + /// the tokens just expanded through __VA_OPT__ processing. These (sub) + /// sequence of tokens are folded into one stringified token. + /// + /// \param[in] VCtx - contains relevent contextual information about the + /// state of the tokens around and including the __VA_OPT__ token, necessary + /// for stringification. + void stringifyVAOPTContents(SmallVectorImpl<Token> &ReplacementToks, + const VAOptExpansionContext &VCtx, + SourceLocation VAOPTClosingParenLoc); /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. @@ -200,6 +239,6 @@ private: void PropagateLineStartLeadingSpaceInfo(Token &Result); }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_LEX_TOKENLEXER_H diff --git a/contrib/llvm/tools/clang/include/clang/Lex/VariadicMacroSupport.h b/contrib/llvm/tools/clang/include/clang/Lex/VariadicMacroSupport.h new file mode 100644 index 0000000000000..cebaf15187de0 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Lex/VariadicMacroSupport.h @@ -0,0 +1,226 @@ +//===- VariadicMacroSupport.h - state machines and scope guards -*- 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 support types to help with preprocessing variadic macro +// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and +// expansions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H +#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H + +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class Preprocessor; + + /// An RAII class that tracks when the Preprocessor starts and stops lexing + /// the definition of a (ISO C/C++) variadic macro. As an example, this is + /// useful for unpoisoning and repoisoning certain identifiers (such as + /// __VA_ARGS__) that are only allowed in this context. Also, being a friend + /// of the Preprocessor class allows it to access PP's cached identifiers + /// directly (as opposed to performing a lookup each time). + class VariadicMacroScopeGuard { + const Preprocessor &PP; + IdentifierInfo *const Ident__VA_ARGS__; + IdentifierInfo *const Ident__VA_OPT__; + + public: + VariadicMacroScopeGuard(const Preprocessor &P) + : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__), + Ident__VA_OPT__(PP.Ident__VA_OPT__) { + assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned " + "outside an ISO C/C++ variadic " + "macro definition!"); + assert( + !Ident__VA_OPT__ || + (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!")); + } + + /// Client code should call this function just before the Preprocessor is + /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro. + void enterScope() { + Ident__VA_ARGS__->setIsPoisoned(false); + if (Ident__VA_OPT__) + Ident__VA_OPT__->setIsPoisoned(false); + } + + /// Client code should call this function as soon as the Preprocessor has + /// either completed lexing the macro's definition tokens, or an error + /// occured and the context is being exited. This function is idempotent + /// (might be explicitly called, and then reinvoked via the destructor). + void exitScope() { + Ident__VA_ARGS__->setIsPoisoned(true); + if (Ident__VA_OPT__) + Ident__VA_OPT__->setIsPoisoned(true); + } + + ~VariadicMacroScopeGuard() { exitScope(); } + }; + + /// \brief A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a variadic macro definition. + class VAOptDefinitionContext { + /// Contains all the locations of so far unmatched lparens. + SmallVector<SourceLocation, 8> UnmatchedOpeningParens; + + const IdentifierInfo *const Ident__VA_OPT__; + + + public: + VAOptDefinitionContext(Preprocessor &PP) + : Ident__VA_OPT__(PP.Ident__VA_OPT__) {} + + bool isVAOptToken(const Token &T) const { + return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__; + } + + /// Returns true if we have seen the __VA_OPT__ and '(' but before having + /// seen the matching ')'. + bool isInVAOpt() const { return UnmatchedOpeningParens.size(); } + + /// Call this function as soon as you see __VA_OPT__ and '('. + void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) { + assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + + } + + SourceLocation getUnmatchedOpeningParenLoc() const { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + return UnmatchedOpeningParens.back(); + } + + /// Call this function each time an rparen is seen. It returns true only if + /// the rparen that was just seen was the eventual (non-nested) closing + /// paren for VAOPT, and ejects us out of the VAOPT context. + bool sawClosingParen() { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.pop_back(); + return !UnmatchedOpeningParens.size(); + } + + /// Call this function each time an lparen is seen. + void sawOpeningParen(SourceLocation LParenLoc) { + assert(isInVAOpt() && "Must be within VAOPT context to call this"); + UnmatchedOpeningParens.push_back(LParenLoc); + } + + }; + + /// \brief A class for tracking whether we're inside a VA_OPT during a + /// traversal of the tokens of a macro during macro expansion. + class VAOptExpansionContext : VAOptDefinitionContext { + + Token SyntheticEOFToken; + + // The (spelling) location of the current __VA_OPT__ in the replacement list + // of the function-like macro being expanded. + SourceLocation VAOptLoc; + + // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first + // token of the current VAOPT contents (so we know where to start eager + // token-pasting and stringification) *within* the substituted tokens of + // the function-like macro's new replacement list. + int NumOfTokensPriorToVAOpt = -1; + + unsigned LeadingSpaceForStringifiedToken : 1; + + unsigned StringifyBefore : 1; + unsigned CharifyBefore : 1; + + + bool hasStringifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return StringifyBefore; + } + + bool isReset() const { + return NumOfTokensPriorToVAOpt == -1 || + VAOptLoc.isInvalid(); + } + + public: + VAOptExpansionContext(Preprocessor &PP) + : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false), + StringifyBefore(false), CharifyBefore(false) { + SyntheticEOFToken.startToken(); + SyntheticEOFToken.setKind(tok::eof); + } + + void reset() { + VAOptLoc = SourceLocation(); + NumOfTokensPriorToVAOpt = -1; + LeadingSpaceForStringifiedToken = false; + StringifyBefore = false; + CharifyBefore = false; + } + + const Token &getEOFTok() const { return SyntheticEOFToken; } + + void sawHashOrHashAtBefore(const bool HasLeadingSpace, + const bool IsHashAt) { + + StringifyBefore = !IsHashAt; + CharifyBefore = IsHashAt; + LeadingSpaceForStringifiedToken = HasLeadingSpace; + } + + + + bool hasCharifyBefore() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return CharifyBefore; + } + bool hasStringifyOrCharifyBefore() const { + return hasStringifyBefore() || hasCharifyBefore(); + } + + unsigned int getNumberOfTokensPriorToVAOpt() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + return NumOfTokensPriorToVAOpt; + } + + bool getLeadingSpaceForStringifiedToken() const { + assert(hasStringifyBefore() && + "Must only be called if this has been marked for stringification"); + return LeadingSpaceForStringifiedToken; + } + + void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, + const unsigned int NumPriorTokens) { + assert(VAOptLoc.isFileID() && "Must not come from a macro expansion"); + assert(isReset() && "Must only be called if the state has been reset"); + VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation()); + this->VAOptLoc = VAOptLoc; + NumOfTokensPriorToVAOpt = NumPriorTokens; + assert(NumOfTokensPriorToVAOpt > -1 && + "Too many prior tokens"); + } + + SourceLocation getVAOptLoc() const { + assert(!isReset() && + "Must only be called if the state has not been reset"); + assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid"); + return VAOptLoc; + } + using VAOptDefinitionContext::isVAOptToken; + using VAOptDefinitionContext::isInVAOpt; + using VAOptDefinitionContext::sawClosingParen; + using VAOptDefinitionContext::sawOpeningParen; + + }; +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h b/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h index 21f9701c3ed8b..34c96816ebdf6 100644 --- a/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h +++ b/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h @@ -29,10 +29,13 @@ namespace clang { /// This operation inserts the parsed decls into the translation /// unit held by Ctx. /// + /// \param PrintStats Whether to print LLVM statistics related to parsing. /// \param TUKind The kind of translation unit being parsed. - /// /// \param CompletionConsumer If given, an object to consume code completion /// results. + /// \param SkipFunctionBodies Whether to skip parsing of function bodies. + /// This option can be used, for example, to speed up searches for + /// declarations/definitions when indexing. void ParseAST(Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, bool PrintStats = false, TranslationUnitKind TUKind = TU_Complete, @@ -43,7 +46,7 @@ namespace clang { /// abstract syntax tree. void ParseAST(Sema &S, bool PrintStats = false, bool SkipFunctionBodies = false); - + } // end namespace clang #endif diff --git a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h index 21d699ec402e5..396b5a9aa394d 100644 --- a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h +++ b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h @@ -253,6 +253,10 @@ class Parser : public CodeCompletionHandler { /// be NULL. bool ParsingInObjCContainer; + /// Whether to skip parsing of function bodies. + /// + /// This option can be used, for example, to speed up searches for + /// declarations/definitions when indexing. bool SkipFunctionBodies; /// The location of the expression statement that is being parsed right now. @@ -334,6 +338,27 @@ public: return true; } + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the + /// current token type. This should only be used in cases where the type of + /// the token really isn't known, e.g. in error recovery. + SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { + if (isTokenParen()) + return ConsumeParen(); + if (isTokenBracket()) + return ConsumeBracket(); + if (isTokenBrace()) + return ConsumeBrace(); + if (isTokenStringLiteral()) + return ConsumeStringToken(); + if (Tok.is(tok::code_completion)) + return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() + : handleUnexpectedCodeCompletionToken(); + if (Tok.isAnnotation()) + return ConsumeAnnotationToken(); + return ConsumeToken(); + } + + SourceLocation getEndOfPreviousToken() { return PP.getLocForEndOfToken(PrevTokLocation); } @@ -384,26 +409,6 @@ private: PP.EnterToken(Next); } - /// ConsumeAnyToken - Dispatch to the right Consume* method based on the - /// current token type. This should only be used in cases where the type of - /// the token really isn't known, e.g. in error recovery. - SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { - if (isTokenParen()) - return ConsumeParen(); - if (isTokenBracket()) - return ConsumeBracket(); - if (isTokenBrace()) - return ConsumeBrace(); - if (isTokenStringLiteral()) - return ConsumeStringToken(); - if (Tok.is(tok::code_completion)) - return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() - : handleUnexpectedCodeCompletionToken(); - if (Tok.isAnnotation()) - return ConsumeAnnotationToken(); - return ConsumeToken(); - } - SourceLocation ConsumeAnnotationToken() { assert(Tok.isAnnotation() && "wrong consume method"); SourceLocation Loc = Tok.getLocation(); @@ -501,6 +506,12 @@ private: Kind == tok::annot_module_end || Kind == tok::annot_module_include; } + /// \brief Checks if the \p Level is valid for use in a fold expression. + bool isFoldOperator(prec::Level Level) const; + + /// \brief Checks if the \p Kind is a valid operator for fold expressions. + bool isFoldOperator(tok::TokenKind Kind) const; + /// \brief Initialize all pragma handlers. void initializePragmaHandlers(); @@ -1470,7 +1481,6 @@ public: ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, unsigned &NumLineToksConsumed, - void *Info, bool IsUnevaluated); private: @@ -1517,9 +1527,10 @@ private: typedef SmallVector<SourceLocation, 20> CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, - SmallVectorImpl<SourceLocation> &CommaLocs, - std::function<void()> Completer = nullptr); + bool ParseExpressionList( + SmallVectorImpl<Expr *> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs, + llvm::function_ref<void()> Completer = llvm::function_ref<void()>()); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. @@ -2159,18 +2170,25 @@ public: private: void ParseBlockId(SourceLocation CaretLoc); - // Check for the start of a C++11 attribute-specifier-seq in a context where - // an attribute is not allowed. + /// Are [[]] attributes enabled? + bool standardAttributesAllowed() const { + const LangOptions &LO = getLangOpts(); + return LO.DoubleSquareBracketAttributes; + } + + // Check for the start of an attribute-specifier-seq in a context where an + // attribute is not allowed. bool CheckProhibitedCXX11Attribute() { assert(Tok.is(tok::l_square)); - if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square)) + if (!standardAttributesAllowed() || NextToken().isNot(tok::l_square)) return false; return DiagnoseProhibitedCXX11Attribute(); } + bool DiagnoseProhibitedCXX11Attribute(); void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, SourceLocation CorrectLocation) { - if (!getLangOpts().CPlusPlus11) + if (!standardAttributesAllowed()) return; if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && Tok.isNot(tok::kw_alignas)) @@ -2190,17 +2208,18 @@ private: } void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); - // Forbid C++11 attributes that appear on certain syntactic - // locations which standard permits but we don't supported yet, - // for example, attributes appertain to decl specifiers. + // Forbid C++11 and C2x attributes that appear on certain syntactic locations + // which standard permits but we don't supported yet, for example, attributes + // appertain to decl specifiers. void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, unsigned DiagID); - /// \brief Skip C++11 attributes and return the end location of the last one. + /// \brief Skip C++11 and C2x attributes and return the end location of the + /// last one. /// \returns SourceLocation() if there are no attributes. SourceLocation SkipCXX11Attributes(); - /// \brief Diagnose and skip C++11 attributes that appear in syntactic + /// \brief Diagnose and skip C++11 and C2x attributes that appear in syntactic /// locations where attributes are not allowed. void DiagnoseAndSkipCXX11Attributes(); @@ -2250,7 +2269,7 @@ private: AttributeList::Syntax Syntax); void MaybeParseCXX11Attributes(Declarator &D) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; ParseCXX11Attributes(attrs, &endLoc); @@ -2259,7 +2278,7 @@ private: } void MaybeParseCXX11Attributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); ParseCXX11Attributes(attrsWithRange, endLoc); attrs.takeAllFrom(attrsWithRange); @@ -2268,8 +2287,8 @@ private: void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = nullptr, bool OuterMightBeMessageSend = false) { - if (getLangOpts().CPlusPlus11 && - isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) + if (standardAttributesAllowed() && + isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) ParseCXX11Attributes(attrs, endLoc); } @@ -2277,8 +2296,8 @@ private: SourceLocation *EndLoc = nullptr); void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *EndLoc = nullptr); - /// \brief Parses a C++-style attribute argument list. Returns true if this - /// results in adding an attribute to the ParsedAttributes list. + /// \brief Parses a C++11 (or C2x)-style attribute argument list. Returns true + /// if this results in adding an attribute to the ParsedAttributes list. bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, @@ -2608,6 +2627,9 @@ private: Decl *TagDecl = nullptr); /// \brief Parse 'omp declare reduction' construct. DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS); + /// Parses initializer for provided omp_priv declaration inside the reduction + /// initializer. + void ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm); /// \brief Parses simple list of variables. /// @@ -2720,11 +2742,11 @@ private: AccessSpecifier AS=AS_none, AttributeList *AccessAttrs = nullptr); bool ParseTemplateParameters(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams, + SmallVectorImpl<NamedDecl *> &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams); + SmallVectorImpl<NamedDecl*> &TemplateParams); bool isStartOfTemplateTypeParameter(); Decl *ParseTemplateParameter(unsigned Depth, unsigned Position); Decl *ParseTypeParameter(unsigned Depth, unsigned Position); @@ -2766,7 +2788,7 @@ private: //===--------------------------------------------------------------------===// // Modules DeclGroupPtrTy ParseModuleDecl(); - DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc); + Decl *ParseModuleImport(SourceLocation AtLoc); bool parseMisplacedModuleImport(); bool tryParseMisplacedModuleImport() { tok::TokenKind Kind = Tok.getKind(); diff --git a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h index 6bdd9d5fcdb6f..4e806116c4d9b 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h @@ -100,16 +100,20 @@ public: AS_GNU, /// [[...]] AS_CXX11, + /// [[...]] + AS_C2x, /// __declspec(...) AS_Declspec, /// [uuid("...")] class Foo AS_Microsoft, /// __ptr16, alignas(...), etc. AS_Keyword, - /// Context-sensitive version of a keyword attribute. - AS_ContextSensitiveKeyword, /// #pragma ... AS_Pragma, + // Note TableGen depends on the order above. Do not add or change the order + // without adding related code to TableGen/ClangAttrEmitter.cpp. + /// Context-sensitive version of a keyword attribute. + AS_ContextSensitiveKeyword, }; private: @@ -376,6 +380,9 @@ public: bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || isAlignasAttribute(); } + bool isC2xAttribute() const { + return SyntaxUsed == AS_C2x; + } bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; } @@ -893,50 +900,17 @@ enum AttributeDeclKind { ExpectedFunction, ExpectedUnion, ExpectedVariableOrFunction, - ExpectedFunctionOrGlobalVar, - ExpectedFunctionVariableOrObjCInterface, ExpectedFunctionOrMethod, - ExpectedParameter, ExpectedFunctionMethodOrBlock, - ExpectedFunctionMethodOrClass, ExpectedFunctionMethodOrParameter, - ExpectedFunctionMethodOrGlobalVar, - ExpectedClass, - ExpectedEnum, ExpectedVariable, - ExpectedMethod, - ExpectedFieldOrGlobalVar, - ExpectedStruct, - ExpectedParameterOrTypedef, - ExpectedVariableOrTypedef, - ExpectedTLSVar, ExpectedVariableOrField, ExpectedVariableFieldOrTag, ExpectedTypeOrNamespace, - ExpectedObjectiveCInterface, - ExpectedMethodOrProperty, - ExpectedFunctionOrMethodOrProperty, - ExpectedStructOrUnion, - ExpectedStructOrUnionOrClass, - ExpectedType, - ExpectedObjCInstanceMethod, - ExpectedObjCInterfaceDeclInitMethod, ExpectedFunctionVariableOrClass, - ExpectedFunctionVariableClassOrObjCInterface, - ExpectedObjectiveCProtocol, - ExpectedStaticOrTLSVar, - ExpectedFunctionGlobalVarMethodOrProperty, - ExpectedStructOrUnionOrTypedef, - ExpectedStructOrTypedef, - ExpectedObjectiveCInterfaceOrProtocol, ExpectedKernelFunction, ExpectedFunctionWithProtoType, - ExpectedVariableEnumFieldOrTypedef, - ExpectedFunctionMethodEnumOrClass, - ExpectedStructClassVariableFunctionOrInlineNamespace, ExpectedForMaybeUnused, - ExpectedEnumOrClass, - ExpectedNamedDecl, }; } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h index dee53dc14a8ca..5d280b5608e71 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -18,6 +18,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/Type.h" #include "clang/Sema/CodeCompleteOptions.h" +#include "clang/Sema/DeclSpec.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -280,6 +281,10 @@ private: /// \brief The identifiers for Objective-C selector parts. ArrayRef<IdentifierInfo *> SelIdents; + /// \brief The scope specifier that comes before the completion token e.g. + /// "a::b::" + llvm::Optional<CXXScopeSpec> ScopeSpecifier; + public: /// \brief Construct a new code-completion context of the given kind. CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(None) { } @@ -315,8 +320,20 @@ public: /// \brief Determines whether we want C++ constructors as results within this /// context. bool wantConstructorResults() const; -}; + /// \brief Sets the scope specifier that comes before the completion token. + /// This is expected to be set in code completions on qualfied specifiers + /// (e.g. "a::b::"). + void setCXXScopeSpecifier(CXXScopeSpec SS) { + this->ScopeSpecifier = std::move(SS); + } + + llvm::Optional<const CXXScopeSpec *> getCXXScopeSpecifier() { + if (ScopeSpecifier) + return ScopeSpecifier.getPointer(); + return llvm::None; + } +}; /// \brief A "string" used to describe how code completion can /// be performed for an entity. @@ -777,6 +794,12 @@ public: CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments); + /// \brief Retrieve the name that should be used to order a result. + /// + /// If the name needs to be constructed as a string, that string will be + /// saved into Saved and the returned StringRef will refer to it. + StringRef getOrderedName(std::string &Saved) const; + private: void computeCursorKindAndAvailability(bool Accessible = true); }; @@ -896,8 +919,13 @@ public: } /// \brief Whether to include global (top-level) declaration results. - bool includeGlobals() const { - return CodeCompleteOpts.IncludeGlobals; + bool includeGlobals() const { return CodeCompleteOpts.IncludeGlobals; } + + /// \brief Whether to include declarations in namespace contexts (including + /// the global namespace). If this is false, `includeGlobals()` will be + /// ignored. + bool includeNamespaceLevelDecls() const { + return CodeCompleteOpts.IncludeNamespaceLevelDecls; } /// \brief Whether to include brief documentation comments within the set of diff --git a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h index fc7713c795712..091d8ca60505e 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteOptions.h @@ -24,15 +24,20 @@ public: /// Show top-level decls in code completion results. unsigned IncludeGlobals : 1; + /// Show decls in namespace (including the global namespace) in code + /// completion results. If this is 0, `IncludeGlobals` will be ignored. + /// + /// Currently, this only works when completing qualified IDs (i.e. + /// `Sema::CodeCompleteQualifiedId`). + /// FIXME: consider supporting more completion cases with this option. + unsigned IncludeNamespaceLevelDecls : 1; + /// Show brief documentation comments in code completion results. unsigned IncludeBriefComments : 1; - CodeCompleteOptions() : - IncludeMacros(0), - IncludeCodePatterns(0), - IncludeGlobals(1), - IncludeBriefComments(0) - { } + CodeCompleteOptions() + : IncludeMacros(0), IncludeCodePatterns(0), IncludeGlobals(1), + IncludeNamespaceLevelDecls(1), IncludeBriefComments(0) {} }; } // namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h index bc817150ab82c..760a04d3c8d2e 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h @@ -280,6 +280,7 @@ public: static const TST TST_half = clang::TST_half; static const TST TST_float = clang::TST_float; static const TST TST_double = clang::TST_double; + static const TST TST_float16 = clang::TST_Float16; static const TST TST_float128 = clang::TST_float128; static const TST TST_bool = clang::TST_bool; static const TST TST_decimal32 = clang::TST_decimal32; @@ -360,9 +361,6 @@ private: // constexpr-specifier unsigned Constexpr_specified : 1; - // concept-specifier - unsigned Concept_specified : 1; - union { UnionParsedType TypeRep; Decl *DeclRep; @@ -392,7 +390,7 @@ private: TQ_unalignedLoc; SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; SourceLocation FS_forceinlineLoc; - SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc; + SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; SourceLocation TQ_pipeLoc; WrittenBuiltinSpecs writtenBS; @@ -438,7 +436,6 @@ public: FS_noreturn_specified(false), Friend_specified(false), Constexpr_specified(false), - Concept_specified(false), Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) { @@ -696,8 +693,6 @@ public: unsigned &DiagID); bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); - bool SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID); bool isFriendSpecified() const { return Friend_specified; } SourceLocation getFriendSpecLoc() const { return FriendLoc; } @@ -708,19 +703,11 @@ public: bool isConstexprSpecified() const { return Constexpr_specified; } SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; } - bool isConceptSpecified() const { return Concept_specified; } - SourceLocation getConceptSpecLoc() const { return ConceptLoc; } - void ClearConstexprSpec() { Constexpr_specified = false; ConstexprLoc = SourceLocation(); } - void ClearConceptSpec() { - Concept_specified = false; - ConceptLoc = SourceLocation(); - } - AttributePool &getAttributePool() const { return Attrs.getPool(); } @@ -2008,9 +1995,9 @@ public: case BlockContext: case ForContext: case InitStmtContext: + case ConditionContext: return true; - case ConditionContext: case MemberContext: case PrototypeContext: case TemplateParamContext: @@ -2300,6 +2287,42 @@ public: } llvm_unreachable("unknown context kind!"); } + + /// Determine whether this declaration appears in a context where an + /// expression could appear. + bool isExpressionContext() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case TypeNameContext: // FIXME: sizeof(...) permits an expression. + case FunctionalCastContext: + case AliasDeclContext: + case AliasTemplateContext: + case PrototypeContext: + case LambdaExprParameterContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXNewContext: + case CXXCatchContext: + case ObjCCatchContext: + case BlockLiteralContext: + case LambdaExprContext: + case ConversionIdContext: + case TrailingReturnContext: + return false; + + case BlockContext: + case ForContext: + case InitStmtContext: + case ConditionContext: + case TemplateTypeArgContext: + return true; + } + + llvm_unreachable("unknown context kind!"); + } /// \brief Return true if a function declarator at this position would be a /// function declaration. diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h index ea32997d40667..546df8842a356 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h @@ -139,6 +139,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -161,6 +162,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -181,6 +183,7 @@ public: LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl), + ExternalRedecl(Other.ExternalRedecl), HideTags(Other.HideTags), Diagnose(false), AllowHidden(Other.AllowHidden), @@ -201,7 +204,9 @@ public: SemaPtr(std::move(Other.SemaPtr)), NameInfo(std::move(Other.NameInfo)), NameContextRange(std::move(Other.NameContextRange)), LookupKind(std::move(Other.LookupKind)), IDNS(std::move(Other.IDNS)), - Redecl(std::move(Other.Redecl)), HideTags(std::move(Other.HideTags)), + Redecl(std::move(Other.Redecl)), + ExternalRedecl(std::move(Other.ExternalRedecl)), + HideTags(std::move(Other.HideTags)), Diagnose(std::move(Other.Diagnose)), AllowHidden(std::move(Other.AllowHidden)), Shadowed(std::move(Other.Shadowed)) { @@ -221,6 +226,7 @@ public: LookupKind = std::move(Other.LookupKind); IDNS = std::move(Other.IDNS); Redecl = std::move(Other.Redecl); + ExternalRedecl = std::move(Other.ExternalRedecl); HideTags = std::move(Other.HideTags); Diagnose = std::move(Other.Diagnose); AllowHidden = std::move(Other.AllowHidden); @@ -265,6 +271,17 @@ public: return Redecl; } + /// True if this lookup is just looking for an existing declaration to link + /// against a declaration with external linkage. + bool isForExternalRedeclaration() const { + return ExternalRedecl; + } + + Sema::RedeclarationKind redeclarationKind() const { + return ExternalRedecl ? Sema::ForExternalRedeclaration : + Redecl ? Sema::ForVisibleRedeclaration : Sema::NotForRedeclaration; + } + /// \brief Specify whether hidden declarations are visible, e.g., /// for recovery reasons. void setAllowHidden(bool AH) { @@ -275,7 +292,7 @@ public: /// declarations, such as those in modules that have not yet been imported. bool isHiddenDeclarationVisible(NamedDecl *ND) const { return AllowHidden || - (isForRedeclaration() && ND->hasExternalFormalLinkage()); + (isForExternalRedeclaration() && ND->isExternallyDeclarable()); } /// Sets whether tag declarations should be hidden by non-tag @@ -556,7 +573,8 @@ public: /// \brief Change this lookup's redeclaration kind. void setRedeclarationKind(Sema::RedeclarationKind RK) { - Redecl = RK; + Redecl = (RK != Sema::NotForRedeclaration); + ExternalRedecl = (RK == Sema::ForExternalRedeclaration); configure(); } @@ -719,6 +737,7 @@ private: unsigned IDNS; // set by configure() bool Redecl; + bool ExternalRedecl; /// \brief True if tag declarations should be hidden if non-tags /// are present diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h index ffdf011d1dcbc..05cfe53666ca9 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h @@ -726,11 +726,20 @@ namespace clang { enum CandidateSetKind { /// Normal lookup. CSK_Normal, - /// Lookup for candidates for a call using operator syntax. Candidates - /// that have no parameters of class type will be skipped unless there - /// is a parameter of (reference to) enum type and the corresponding - /// argument is of the same enum type. - CSK_Operator + /// C++ [over.match.oper]: + /// Lookup of operator function candidates in a call using operator + /// syntax. Candidates that have no parameters of class type will be + /// skipped unless there is a parameter of (reference to) enum type and + /// the corresponding argument is of the same enum type. + CSK_Operator, + /// C++ [over.match.copy]: + /// Copy-initialization of an object of class type by user-defined + /// conversion. + CSK_InitByUserDefinedConversion, + /// C++ [over.match.ctor], [over.match.list] + /// Initialization of an object of class type by constructor, + /// using either a parenthesized or braced list of arguments. + CSK_InitByConstructor, }; private: @@ -795,7 +804,7 @@ namespace clang { } /// \brief Clear out all of the candidates. - void clear(); + void clear(CandidateSetKind CSK); typedef SmallVectorImpl<OverloadCandidate>::iterator iterator; iterator begin() { return Candidates.begin(); } @@ -835,8 +844,7 @@ namespace clang { /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator& Best, - bool UserDefinedConversion = false); + OverloadCandidateSet::iterator& Best); void NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, @@ -848,10 +856,10 @@ namespace clang { }; bool isBetterOverloadCandidate(Sema &S, - const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, SourceLocation Loc, - bool UserDefinedConversion = false); + OverloadCandidateSet::CandidateSetKind Kind); struct ConstructorInfo { DeclAccessPair FoundDecl; diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h index 848837a1deccd..1e35316fd5dd5 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h @@ -107,8 +107,7 @@ namespace clang { namespace llvm { template <class T> - class PointerLikeTypeTraits<clang::OpaquePtr<T> > { - public: + struct PointerLikeTypeTraits<clang::OpaquePtr<T> > { static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) { // FIXME: Doesn't work? return P.getAs< void >(); return P.getAsOpaquePtr(); diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Scope.h b/contrib/llvm/tools/clang/include/clang/Sema/Scope.h index d0b006b82ec6e..cd58a9910f98e 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Scope.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Scope.h @@ -124,6 +124,12 @@ public: /// We are currently in the filter expression of an SEH except block. SEHFilterScope = 0x200000, + + /// This is a compound statement scope. + CompoundStmtScope = 0x400000, + + /// We are between inheritance colon and the real class/struct definition scope. + ClassInheritanceScope = 0x800000, }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -429,6 +435,11 @@ public: /// \brief Determine whether this scope is a SEH '__except' block. bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; } + /// \brief Determine whether this scope is a compound statement scope. + bool isCompoundStmtScope() const { + return getFlags() & Scope::CompoundStmtScope; + } + /// \brief Returns if rhs has a higher scope depth than this. /// /// The caller is responsible for calling this only if one of the two scopes diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h index 215f30a8d2838..c707a3e8ef074 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h @@ -834,6 +834,12 @@ public: return FSI->Kind == SK_Lambda; } + /// Is this scope known to be for a generic lambda? (This will be false until + /// we parse the first 'auto'-typed parameter. + bool isGenericLambda() const { + return !AutoTemplateParams.empty() || GLTemplateParameterList; + } + /// /// \brief Add a variable that might potentially be captured by the /// lambda and therefore the enclosing lambdas. diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h index 5a708545705c0..47cea3029bd9f 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h @@ -64,7 +64,7 @@ namespace llvm { template <typename ValueT> struct DenseMapInfo; template <typename ValueT, typename ValueInfoT> class DenseSet; class SmallBitVector; - class InlineAsmIdentifierInfo; + struct InlineAsmIdentifierInfo; } namespace clang { @@ -208,6 +208,7 @@ namespace sema { class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; + class SemaPPCallbacks; class TemplateDeductionInfo; } @@ -228,6 +229,10 @@ struct FileNullability { /// not have a corresponding nullability annotation. SourceLocation PointerLoc; + /// The end location for the first pointer declarator in the file. Used for + /// placing fix-its. + SourceLocation PointerEndLoc; + /// Which kind of pointer declarator we saw. uint8_t PointerKind; @@ -280,15 +285,21 @@ class Sema { bool isVisibleSlow(const NamedDecl *D); + /// Determine whether two declarations should be linked together, given that + /// the old declaration might not be visible and the new declaration might + /// not have external linkage. bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { - // We are about to link these. It is now safe to compute the linkage of - // the new decl. If the new decl has external linkage, we will - // link it with the hidden decl (which also has external linkage) and - // it will keep having external linkage. If it has internal linkage, we - // will not link it. Since it has no previous decls, it will remain - // with internal linkage. - return isVisible(Old) || New->isExternallyVisible(); + if (isVisible(Old)) + return true; + // See comment in below overload for why it's safe to compute the linkage + // of the new declaration here. + if (New->isExternallyDeclarable()) { + assert(Old->isExternallyDeclarable() && + "should not have found a non-externally-declarable previous decl"); + return true; + } + return false; } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); @@ -381,11 +392,12 @@ public: llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; - Slot(llvm::StringRef StackSlotLabel, - ValueType Value, - SourceLocation PragmaLocation) - : StackSlotLabel(StackSlotLabel), Value(Value), - PragmaLocation(PragmaLocation) {} + SourceLocation PragmaPushLocation; + Slot(llvm::StringRef StackSlotLabel, ValueType Value, + SourceLocation PragmaLocation, SourceLocation PragmaPushLocation) + : StackSlotLabel(StackSlotLabel), Value(Value), + PragmaLocation(PragmaLocation), + PragmaPushLocation(PragmaPushLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, @@ -416,6 +428,8 @@ public: explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} + bool hasValue() const { return CurrentValue != DefaultValue; } + SmallVector<Slot, 2> Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; @@ -437,6 +451,13 @@ public: // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack<unsigned> PackStack; + // The current #pragma pack values and locations at each #include. + struct PackIncludeState { + unsigned CurrentValue; + SourceLocation CurrentPragmaLocation; + bool HasNonDefaultValue, ShouldWarnOnInclude; + }; + SmallVector<PackIncludeState, 8> PackIncludeStack; // Segment #pragmas. PragmaStack<StringLiteral *> DataSegStack; PragmaStack<StringLiteral *> BSSSegStack; @@ -1075,6 +1096,11 @@ public: /// definition in this translation unit. llvm::MapVector<NamedDecl *, SourceLocation> UndefinedButUsed; + /// Determine if VD, which must be a variable or function, is an external + /// symbol that nonetheless can't be referenced from outside this translation + /// unit because its type has no linkage and it's not extern "C". + bool isExternalWithNoLinkageType(ValueDecl *VD); + /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined); @@ -1110,12 +1136,13 @@ public: CXXInvalid }; - typedef std::pair<CXXRecordDecl*, CXXSpecialMember> SpecialMemberDecl; + typedef llvm::PointerIntPair<CXXRecordDecl *, 3, CXXSpecialMember> + SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. - llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + llvm::SmallPtrSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; /// The function definitions which were renamed as part of typo-correction /// to match their respective declarations. We want to keep track of them @@ -1357,6 +1384,8 @@ public: SourceRange Brackets, DeclarationName Entity); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); + QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); @@ -1504,7 +1533,8 @@ private: TypeDiagnoser *Diagnoser); struct ModuleScope { - clang::Module *Module; + clang::Module *Module = nullptr; + bool ModuleInterface = false; VisibleModuleSet OuterVisibleModules; }; /// The modules we're currently parsing. @@ -1525,7 +1555,7 @@ public: /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); - bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); } + bool isModuleVisible(const Module *M) { return VisibleModules.isVisible(M); } /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { @@ -1694,7 +1724,6 @@ public: ExprResult Expr; TemplateName Template; ParsedType Type; - const IdentifierInfo *Keyword; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} @@ -1703,8 +1732,7 @@ public: NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} - NameClassification(const IdentifierInfo *Keyword) - : Kind(NC_Keyword), Keyword(Keyword) { } + NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {} static NameClassification Error() { return NameClassification(NC_Error); @@ -2022,9 +2050,9 @@ public: SourceLocation SemiLoc); enum class ModuleDeclKind { - Module, ///< 'module X;' + Interface, ///< 'export module X;' + Implementation, ///< 'module X;' Partition, ///< 'module partition X;' - Implementation, ///< 'module implementation X;' }; /// The parser has processed a module-declaration that begins the definition @@ -2677,7 +2705,8 @@ public: OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, - bool PartialOverloading = false); + bool PartialOverloading = false, + bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, @@ -2725,13 +2754,15 @@ public: CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -2771,6 +2802,14 @@ public: EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, bool MissingImplicitThis = false); + /// Find the failed Boolean condition within a given Boolean + /// constant expression, and describe it with a string. + /// + /// \param AllowTopLevelCond Whether to allow the result to be the + /// complete top-level condition. + std::pair<Expr *, std::string> + findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond); + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// non-ArgDependent DiagnoseIfAttrs. /// @@ -2881,12 +2920,13 @@ public: ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *input); + Expr *input, bool RequiresADL = true); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS); + Expr *LHS, Expr *RHS, + bool RequiresADL = true); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, @@ -3001,14 +3041,31 @@ public: /// purpose of redeclaring the name. NotForRedeclaration = 0, /// \brief The lookup results will be used for redeclaration of a name, - /// if an entity by that name already exists. - ForRedeclaration + /// if an entity by that name already exists and is visible. + ForVisibleRedeclaration, + /// \brief The lookup results will be used for redeclaration of a name + /// with external linkage; non-visible lookup results with external linkage + /// may also be found. + ForExternalRedeclaration }; + RedeclarationKind forRedeclarationInCurContext() { + // A declaration with an owning module for linkage can never link against + // anything that is not visible. We don't need to check linkage here; if + // the context has internal linkage, redeclaration lookup won't find things + // from other TUs, and we can't safely compute linkage yet in general. + if (cast<Decl>(CurContext) + ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) + return ForVisibleRedeclaration; + return ForExternalRedeclaration; + } + /// \brief The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. LOLR_Error, + /// \brief The lookup found no match but no diagnostic was issued. + LOLR_ErrorNoDiagnostic, /// \brief The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, @@ -3133,7 +3190,8 @@ public: ArrayRef<QualType> ArgTys, bool AllowRaw, bool AllowTemplate, - bool AllowStringTemplate); + bool AllowStringTemplate, + bool DiagnoseMissing); bool isKnownName(StringRef name); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, @@ -3229,6 +3287,8 @@ public: void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); + bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); + void DiagnoseAmbiguousLookup(LookupResult &Result); //@} @@ -3271,7 +3331,7 @@ public: unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); - void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); + bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceAttr::Spelling SemanticSpelling); @@ -3754,15 +3814,15 @@ public: Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc); + void FillInlineAsmIdentifierInfo(Expr *Res, + llvm::InlineAsmIdentifierInfo &Info); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, - llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, - llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef<Token> AsmToks, @@ -6038,7 +6098,7 @@ public: SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ArrayRef<Decl *> Params, + ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, Expr *RequiresClause); @@ -7368,13 +7428,16 @@ public: unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; + bool PrevLastDiagnosticIgnored; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), - PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), + PrevLastDiagnosticIgnored( + SemaRef.getDiagnostics().isLastDiagnosticIgnored()) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; @@ -7386,6 +7449,8 @@ public: SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + SemaRef.getDiagnostics().setLastDiagnosticIgnored( + PrevLastDiagnosticIgnored); } /// \brief Determine whether any SFINAE errors have been trapped. @@ -7725,11 +7790,6 @@ public: VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); - void InstantiateStaticDataMemberDefinition( - SourceLocation PointOfInstantiation, - VarDecl *Var, - bool Recursive = false, - bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, @@ -8182,6 +8242,15 @@ public: void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); + enum class PragmaPackDiagnoseKind { + NonDefaultStateAtInclude, + ChangedStateAtExit + }; + + void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind, + SourceLocation IncludeLoc); + void DiagnoseUnterminatedPragmaPack(); + /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); @@ -8467,6 +8536,10 @@ private: /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; + /// Adjusts the function scopes index for the target-based regions. + void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, + unsigned Level) const; + /// Push new OpenMP function region for non-capturing function. void pushOpenMPFunctionRegion(); @@ -8507,6 +8580,11 @@ public: /// is performed. bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level); + /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) + /// for \p FD based on DSA for the provided corresponding captured declaration + /// \p D. + void setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level); + /// \brief Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. @@ -8559,9 +8637,11 @@ public: /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// \brief Initialize declare reduction construct initializer. - void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); + /// \return omp_priv variable. + VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. - void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer); + void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, + VarDecl *OmpPrivParm); /// \brief Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); @@ -8576,11 +8656,20 @@ public: OMPDeclareTargetDeclAttr::MapTypeTy MT, NamedDeclSetType &SameDirectiveDecls); /// Check declaration inside target region. - void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); - /// Return true inside OpenMP target region. + void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, + SourceLocation IdLoc = SourceLocation()); + /// Return true inside OpenMP declare target region. bool isInOpenMPDeclareTargetContext() const { return IsInOpenMPDeclareTargetContext; } + /// Return true inside OpenMP target region. + bool isInOpenMPTargetExecutionDirective() const; + /// Return true if (un)supported features for the current target should be + /// diagnosed if OpenMP (offloading) is enabled. + bool shouldDiagnoseTargetSupportFromOpenMP() const { + return !getLangOpts().OpenMPIsDevice || isInOpenMPDeclareTargetContext() || + isInOpenMPTargetExecutionDirective(); + } /// Return the number of captured regions created for an OpenMP directive. static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); @@ -8710,12 +8799,14 @@ public: /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc); + SourceLocation EndLoc, + Stmt *AStmt); /// \brief Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc); + SourceLocation EndLoc, + Stmt *AStmt); /// \brief Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, @@ -8764,7 +8855,8 @@ public: /// \brief Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc); + SourceLocation EndLoc, + Stmt *AStmt); /// \brief Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( @@ -9029,6 +9121,13 @@ public: CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions = llvm::None); + /// Called on well-formed 'in_reduction' clause. + OMPClause *ActOnOpenMPInReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = llvm::None); /// \brief Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, @@ -10126,8 +10225,7 @@ public: void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); - void CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, + void CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, @@ -10211,7 +10309,7 @@ private: bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStartARM(CallExpr *Call); + bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinVSX(CallExpr *TheCall); @@ -10362,7 +10460,8 @@ private: /// \brief Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, - const Expr * const *ExprArgs); + const ArrayRef<const Expr *> ExprArgs, + SourceLocation CallSiteLoc); /// \brief Check if we are taking the address of a packed field /// as this may be a problem if the pointer value is dereferenced. @@ -10383,6 +10482,12 @@ private: IdentifierInfo *Ident_NSError = nullptr; + /// \brief The handler for the FileChanged preprocessor events. + /// + /// Used for diagnostics that implement custom semantic analysis for #include + /// directives, like -Wpragma-pack. + sema::SemaPPCallbacks *SemaPPCallbackHandler; + protected: friend class Parser; friend class InitializationSequence; @@ -10446,6 +10551,36 @@ public: SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses; private: + class SavePendingParsedClassStateRAII { + public: + SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); } + + ~SavePendingParsedClassStateRAII() { + assert(S.DelayedExceptionSpecChecks.empty() && + "there shouldn't be any pending delayed exception spec checks"); + assert(S.DelayedDefaultedMemberExceptionSpecs.empty() && + "there shouldn't be any pending delayed defaulted member " + "exception specs"); + assert(S.DelayedDllExportClasses.empty() && + "there shouldn't be any pending delayed DLL export classes"); + swapSavedState(); + } + + private: + Sema &S; + decltype(DelayedExceptionSpecChecks) SavedExceptionSpecChecks; + decltype(DelayedDefaultedMemberExceptionSpecs) + SavedDefaultedMemberExceptionSpecs; + decltype(DelayedDllExportClasses) SavedDllExportClasses; + + void swapSavedState() { + SavedExceptionSpecChecks.swap(S.DelayedExceptionSpecChecks); + SavedDefaultedMemberExceptionSpecs.swap( + S.DelayedDefaultedMemberExceptionSpecs); + SavedDllExportClasses.swap(S.DelayedDllExportClasses); + } + }; + /// \brief Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { diff --git a/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h index a01e8d639f603..4dc215ba21cb7 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/SemaInternal.h @@ -73,7 +73,8 @@ inline void MarkVarDeclODRUsed(VarDecl *Var, // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && - (!Var->isExternallyVisible() || Var->isInline()) && + (!Var->isExternallyVisible() || Var->isInline() || + SemaRef.isExternalWithNoLinkageType(Var)) && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h index 9227b33d2c53c..34a7bb330174b 100644 --- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h @@ -14,17 +14,23 @@ // respective lists. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_SERIALIZATION_ASTBITCODES_H #define LLVM_CLANG_SERIALIZATION_ASTBITCODES_H #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" -#include "llvm/ADT/DenseMap.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Bitcode/BitCodes.h" -#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <cstdint> namespace clang { - namespace serialization { +namespace serialization { + /// \brief AST file major version number supported by this version of /// Clang. /// @@ -52,7 +58,7 @@ namespace clang { /// /// The ID numbers of identifiers are consecutive (in order of discovery) /// and start at 1. 0 is reserved for NULL. - typedef uint32_t IdentifierID; + using IdentifierID = uint32_t; /// \brief An ID number that refers to a declaration in an AST file. /// @@ -60,12 +66,12 @@ namespace clang { /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. /// At the start of a chain of precompiled headers, declaration ID 1 is /// used for the translation unit declaration. - typedef uint32_t DeclID; + using DeclID = uint32_t; // FIXME: Turn these into classes so we can have some type safety when // we go from local ID to global and vice-versa. - typedef DeclID LocalDeclID; - typedef DeclID GlobalDeclID; + using LocalDeclID = DeclID; + using GlobalDeclID = DeclID; /// \brief An ID number that refers to a type in an AST file. /// @@ -77,22 +83,25 @@ namespace clang { /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are /// other types that have serialized representations. - typedef uint32_t TypeID; + using TypeID = uint32_t; /// \brief A type index; the type ID with the qualifier bits removed. class TypeIdx { - uint32_t Idx; + uint32_t Idx = 0; + public: - TypeIdx() : Idx(0) { } - explicit TypeIdx(uint32_t index) : Idx(index) { } + TypeIdx() = default; + explicit TypeIdx(uint32_t index) : Idx(index) {} uint32_t getIndex() const { return Idx; } + TypeID asTypeID(unsigned FastQuals) const { if (Idx == uint32_t(-1)) return TypeID(-1); return (Idx << Qualifiers::FastWidth) | FastQuals; } + static TypeIdx fromTypeID(TypeID ID) { if (ID == TypeID(-1)) return TypeIdx(-1); @@ -104,14 +113,17 @@ namespace clang { /// A structure for putting "fast"-unqualified QualTypes into a /// DenseMap. This uses the standard pointer hash function. struct UnsafeQualTypeDenseMapInfo { - static inline bool isEqual(QualType A, QualType B) { return A == B; } - static inline QualType getEmptyKey() { + static bool isEqual(QualType A, QualType B) { return A == B; } + + static QualType getEmptyKey() { return QualType::getFromOpaquePtr((void*) 1); } - static inline QualType getTombstoneKey() { + + static QualType getTombstoneKey() { return QualType::getFromOpaquePtr((void*) 2); } - static inline unsigned getHashValue(QualType T) { + + static unsigned getHashValue(QualType T) { assert(!T.getLocalFastQualifiers() && "hash invalid for types with fast quals"); uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); @@ -120,44 +132,44 @@ namespace clang { }; /// \brief An ID number that refers to an identifier in an AST file. - typedef uint32_t IdentID; + using IdentID = uint32_t; /// \brief The number of predefined identifier IDs. const unsigned int NUM_PREDEF_IDENT_IDS = 1; /// \brief An ID number that refers to a macro in an AST file. - typedef uint32_t MacroID; + using MacroID = uint32_t; /// \brief A global ID number that refers to a macro in an AST file. - typedef uint32_t GlobalMacroID; + using GlobalMacroID = uint32_t; /// \brief A local to a module ID number that refers to a macro in an /// AST file. - typedef uint32_t LocalMacroID; + using LocalMacroID = uint32_t; /// \brief The number of predefined macro IDs. const unsigned int NUM_PREDEF_MACRO_IDS = 1; /// \brief An ID number that refers to an ObjC selector in an AST file. - typedef uint32_t SelectorID; + using SelectorID = uint32_t; /// \brief The number of predefined selector IDs. const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an /// AST file. - typedef uint32_t CXXBaseSpecifiersID; + using CXXBaseSpecifiersID = uint32_t; /// \brief An ID number that refers to a list of CXXCtorInitializers in an /// AST file. - typedef uint32_t CXXCtorInitializersID; + using CXXCtorInitializersID = uint32_t; /// \brief An ID number that refers to an entity in the detailed /// preprocessing record. - typedef uint32_t PreprocessedEntityID; + using PreprocessedEntityID = uint32_t; /// \brief An ID number that refers to a submodule in a module file. - typedef uint32_t SubmoduleID; + using SubmoduleID = uint32_t; /// \brief The number of predefined submodule IDs. const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; @@ -166,18 +178,21 @@ namespace clang { struct PPEntityOffset { /// \brief Raw source location of beginning of range. unsigned Begin; + /// \brief Raw source location of end of range. unsigned End; + /// \brief Offset in the AST file. uint32_t BitOffset; PPEntityOffset(SourceRange R, uint32_t BitOffset) : Begin(R.getBegin().getRawEncoding()), - End(R.getEnd().getRawEncoding()), - BitOffset(BitOffset) { } + End(R.getEnd().getRawEncoding()), BitOffset(BitOffset) {} + SourceLocation getBegin() const { return SourceLocation::getFromRawEncoding(Begin); } + SourceLocation getEnd() const { return SourceLocation::getFromRawEncoding(End); } @@ -186,17 +201,19 @@ namespace clang { /// \brief Source range/offset of a preprocessed entity. struct DeclOffset { /// \brief Raw source location. - unsigned Loc; + unsigned Loc = 0; + /// \brief Offset in the AST file. - uint32_t BitOffset; + uint32_t BitOffset = 0; - DeclOffset() : Loc(0), BitOffset(0) { } + DeclOffset() = default; DeclOffset(SourceLocation Loc, uint32_t BitOffset) - : Loc(Loc.getRawEncoding()), - BitOffset(BitOffset) { } + : Loc(Loc.getRawEncoding()), BitOffset(BitOffset) {} + void setLocation(SourceLocation L) { Loc = L.getRawEncoding(); } + SourceLocation getLocation() const { return SourceLocation::getFromRawEncoding(Loc); } @@ -617,17 +634,21 @@ namespace clang { /// \brief Describes a source location entry (SLocEntry) for a /// file. SM_SLOC_FILE_ENTRY = 1, + /// \brief Describes a source location entry (SLocEntry) for a /// buffer. SM_SLOC_BUFFER_ENTRY = 2, + /// \brief Describes a blob that contains the data for a buffer /// entry. This kind of record always directly follows a /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an /// overridden buffer. SM_SLOC_BUFFER_BLOB = 3, + /// \brief Describes a zlib-compressed blob that contains the data for /// a buffer entry. SM_SLOC_BUFFER_BLOB_COMPRESSED = 4, + /// \brief Describes a source location entry (SLocEntry) for a /// macro expansion. SM_SLOC_EXPANSION_ENTRY = 5 @@ -676,46 +697,66 @@ namespace clang { enum SubmoduleRecordTypes { /// \brief Metadata for submodules as a whole. SUBMODULE_METADATA = 0, + /// \brief Defines the major attributes of a submodule, including its /// name and parent. SUBMODULE_DEFINITION = 1, + /// \brief Specifies the umbrella header used to create this module, /// if any. SUBMODULE_UMBRELLA_HEADER = 2, + /// \brief Specifies a header that falls into this (sub)module. SUBMODULE_HEADER = 3, + /// \brief Specifies a top-level header that falls into this (sub)module. SUBMODULE_TOPHEADER = 4, + /// \brief Specifies an umbrella directory. SUBMODULE_UMBRELLA_DIR = 5, + /// \brief Specifies the submodules that are imported by this /// submodule. SUBMODULE_IMPORTS = 6, + /// \brief Specifies the submodules that are re-exported from this /// submodule. SUBMODULE_EXPORTS = 7, + /// \brief Specifies a required feature. SUBMODULE_REQUIRES = 8, + /// \brief Specifies a header that has been explicitly excluded /// from this submodule. SUBMODULE_EXCLUDED_HEADER = 9, + /// \brief Specifies a library or framework to link against. SUBMODULE_LINK_LIBRARY = 10, + /// \brief Specifies a configuration macro for this module. SUBMODULE_CONFIG_MACRO = 11, + /// \brief Specifies a conflict with another module. SUBMODULE_CONFLICT = 12, + /// \brief Specifies a header that is private to this submodule. SUBMODULE_PRIVATE_HEADER = 13, + /// \brief Specifies a header that is part of the module but must be /// textually included. SUBMODULE_TEXTUAL_HEADER = 14, + /// \brief Specifies a header that is private to this submodule but /// must be textually included. SUBMODULE_PRIVATE_TEXTUAL_HEADER = 15, + /// \brief Specifies some declarations with initializers that must be /// emitted to initialize the module. SUBMODULE_INITIALIZERS = 16, + + /// \brief Specifies the name of the module that will eventually + /// re-export the entities in this module. + SUBMODULE_EXPORT_AS = 17, }; /// \brief Record types used within a comments block. @@ -740,92 +781,139 @@ namespace clang { enum PredefinedTypeIDs { /// \brief The NULL type. PREDEF_TYPE_NULL_ID = 0, + /// \brief The void type. PREDEF_TYPE_VOID_ID = 1, + /// \brief The 'bool' or '_Bool' type. PREDEF_TYPE_BOOL_ID = 2, + /// \brief The 'char' type, when it is unsigned. PREDEF_TYPE_CHAR_U_ID = 3, + /// \brief The 'unsigned char' type. PREDEF_TYPE_UCHAR_ID = 4, + /// \brief The 'unsigned short' type. PREDEF_TYPE_USHORT_ID = 5, + /// \brief The 'unsigned int' type. PREDEF_TYPE_UINT_ID = 6, + /// \brief The 'unsigned long' type. PREDEF_TYPE_ULONG_ID = 7, + /// \brief The 'unsigned long long' type. PREDEF_TYPE_ULONGLONG_ID = 8, + /// \brief The 'char' type, when it is signed. PREDEF_TYPE_CHAR_S_ID = 9, + /// \brief The 'signed char' type. PREDEF_TYPE_SCHAR_ID = 10, + /// \brief The C++ 'wchar_t' type. PREDEF_TYPE_WCHAR_ID = 11, + /// \brief The (signed) 'short' type. PREDEF_TYPE_SHORT_ID = 12, + /// \brief The (signed) 'int' type. PREDEF_TYPE_INT_ID = 13, + /// \brief The (signed) 'long' type. PREDEF_TYPE_LONG_ID = 14, + /// \brief The (signed) 'long long' type. PREDEF_TYPE_LONGLONG_ID = 15, + /// \brief The 'float' type. PREDEF_TYPE_FLOAT_ID = 16, + /// \brief The 'double' type. PREDEF_TYPE_DOUBLE_ID = 17, + /// \brief The 'long double' type. PREDEF_TYPE_LONGDOUBLE_ID = 18, + /// \brief The placeholder type for overloaded function sets. PREDEF_TYPE_OVERLOAD_ID = 19, + /// \brief The placeholder type for dependent types. PREDEF_TYPE_DEPENDENT_ID = 20, + /// \brief The '__uint128_t' type. PREDEF_TYPE_UINT128_ID = 21, + /// \brief The '__int128_t' type. PREDEF_TYPE_INT128_ID = 22, + /// \brief The type of 'nullptr'. PREDEF_TYPE_NULLPTR_ID = 23, + /// \brief The C++ 'char16_t' type. PREDEF_TYPE_CHAR16_ID = 24, + /// \brief The C++ 'char32_t' type. PREDEF_TYPE_CHAR32_ID = 25, + /// \brief The ObjC 'id' type. PREDEF_TYPE_OBJC_ID = 26, + /// \brief The ObjC 'Class' type. PREDEF_TYPE_OBJC_CLASS = 27, + /// \brief The ObjC 'SEL' type. PREDEF_TYPE_OBJC_SEL = 28, + /// \brief The 'unknown any' placeholder type. PREDEF_TYPE_UNKNOWN_ANY = 29, + /// \brief The placeholder type for bound member functions. PREDEF_TYPE_BOUND_MEMBER = 30, + /// \brief The "auto" deduction type. PREDEF_TYPE_AUTO_DEDUCT = 31, + /// \brief The "auto &&" deduction type. PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, + /// \brief The OpenCL 'half' / ARM NEON __fp16 type. PREDEF_TYPE_HALF_ID = 33, + /// \brief ARC's unbridged-cast placeholder type. PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, + /// \brief The pseudo-object placeholder type. PREDEF_TYPE_PSEUDO_OBJECT = 35, + /// \brief The placeholder type for builtin functions. PREDEF_TYPE_BUILTIN_FN = 36, + /// \brief OpenCL event type. PREDEF_TYPE_EVENT_ID = 37, + /// \brief OpenCL clk event type. PREDEF_TYPE_CLK_EVENT_ID = 38, + /// \brief OpenCL sampler type. PREDEF_TYPE_SAMPLER_ID = 39, + /// \brief OpenCL queue type. PREDEF_TYPE_QUEUE_ID = 40, + /// \brief OpenCL reserve_id type. PREDEF_TYPE_RESERVE_ID_ID = 41, + /// \brief The placeholder type for OpenMP array section. PREDEF_TYPE_OMP_ARRAY_SECTION = 42, + /// \brief The '__float128' type PREDEF_TYPE_FLOAT128_ID = 43, + + /// \brief The '_Float16' type + PREDEF_TYPE_FLOAT16_ID = 44, + /// \brief OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, @@ -848,94 +936,141 @@ namespace clang { enum TypeCode { /// \brief An ExtQualType record. TYPE_EXT_QUAL = 1, + /// \brief A ComplexType record. TYPE_COMPLEX = 3, + /// \brief A PointerType record. TYPE_POINTER = 4, + /// \brief A BlockPointerType record. TYPE_BLOCK_POINTER = 5, + /// \brief An LValueReferenceType record. TYPE_LVALUE_REFERENCE = 6, + /// \brief An RValueReferenceType record. TYPE_RVALUE_REFERENCE = 7, + /// \brief A MemberPointerType record. TYPE_MEMBER_POINTER = 8, + /// \brief A ConstantArrayType record. TYPE_CONSTANT_ARRAY = 9, + /// \brief An IncompleteArrayType record. TYPE_INCOMPLETE_ARRAY = 10, + /// \brief A VariableArrayType record. TYPE_VARIABLE_ARRAY = 11, + /// \brief A VectorType record. TYPE_VECTOR = 12, + /// \brief An ExtVectorType record. TYPE_EXT_VECTOR = 13, + /// \brief A FunctionNoProtoType record. TYPE_FUNCTION_NO_PROTO = 14, + /// \brief A FunctionProtoType record. TYPE_FUNCTION_PROTO = 15, + /// \brief A TypedefType record. TYPE_TYPEDEF = 16, + /// \brief A TypeOfExprType record. TYPE_TYPEOF_EXPR = 17, + /// \brief A TypeOfType record. TYPE_TYPEOF = 18, + /// \brief A RecordType record. TYPE_RECORD = 19, + /// \brief An EnumType record. TYPE_ENUM = 20, + /// \brief An ObjCInterfaceType record. TYPE_OBJC_INTERFACE = 21, + /// \brief An ObjCObjectPointerType record. TYPE_OBJC_OBJECT_POINTER = 22, + /// \brief a DecltypeType record. TYPE_DECLTYPE = 23, + /// \brief An ElaboratedType record. TYPE_ELABORATED = 24, + /// \brief A SubstTemplateTypeParmType record. TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, + /// \brief An UnresolvedUsingType record. TYPE_UNRESOLVED_USING = 26, + /// \brief An InjectedClassNameType record. TYPE_INJECTED_CLASS_NAME = 27, + /// \brief An ObjCObjectType record. TYPE_OBJC_OBJECT = 28, + /// \brief An TemplateTypeParmType record. TYPE_TEMPLATE_TYPE_PARM = 29, + /// \brief An TemplateSpecializationType record. TYPE_TEMPLATE_SPECIALIZATION = 30, + /// \brief A DependentNameType record. TYPE_DEPENDENT_NAME = 31, + /// \brief A DependentTemplateSpecializationType record. TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, + /// \brief A DependentSizedArrayType record. TYPE_DEPENDENT_SIZED_ARRAY = 33, + /// \brief A ParenType record. TYPE_PAREN = 34, + /// \brief A PackExpansionType record. TYPE_PACK_EXPANSION = 35, + /// \brief An AttributedType record. TYPE_ATTRIBUTED = 36, + /// \brief A SubstTemplateTypeParmPackType record. TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, + /// \brief A AutoType record. TYPE_AUTO = 38, + /// \brief A UnaryTransformType record. TYPE_UNARY_TRANSFORM = 39, + /// \brief An AtomicType record. TYPE_ATOMIC = 40, + /// \brief A DecayedType record. TYPE_DECAYED = 41, + /// \brief An AdjustedType record. TYPE_ADJUSTED = 42, + /// \brief A PipeType record. TYPE_PIPE = 43, + /// \brief An ObjCTypeParamType record. TYPE_OBJC_TYPE_PARAM = 44, + /// \brief A DeducedTemplateSpecializationType record. TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45, + /// \brief A DependentSizedExtVectorType record. - TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46 + TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46, + + /// \brief A DependentAddressSpaceType record. + TYPE_DEPENDENT_ADDRESS_SPACE = 47 }; /// \brief The type IDs for special types constructed by semantic @@ -946,18 +1081,25 @@ namespace clang { enum SpecialTypeIDs { /// \brief CFConstantString type SPECIAL_TYPE_CF_CONSTANT_STRING = 0, + /// \brief C FILE typedef type SPECIAL_TYPE_FILE = 1, + /// \brief C jmp_buf typedef type SPECIAL_TYPE_JMP_BUF = 2, + /// \brief C sigjmp_buf typedef type SPECIAL_TYPE_SIGJMP_BUF = 3, + /// \brief Objective-C "id" redefinition type SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4, + /// \brief Objective-C "Class" redefinition type SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5, + /// \brief Objective-C "SEL" redefinition type SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, + /// \brief C ucontext_t typedef type SPECIAL_TYPE_UCONTEXT_T = 7 }; @@ -1048,57 +1190,84 @@ namespace clang { /// \brief A TypedefDecl record. DECL_TYPEDEF = 51, /// \brief A TypeAliasDecl record. + DECL_TYPEALIAS, + /// \brief An EnumDecl record. DECL_ENUM, + /// \brief A RecordDecl record. DECL_RECORD, + /// \brief An EnumConstantDecl record. DECL_ENUM_CONSTANT, + /// \brief A FunctionDecl record. DECL_FUNCTION, + /// \brief A ObjCMethodDecl record. DECL_OBJC_METHOD, + /// \brief A ObjCInterfaceDecl record. DECL_OBJC_INTERFACE, + /// \brief A ObjCProtocolDecl record. DECL_OBJC_PROTOCOL, + /// \brief A ObjCIvarDecl record. DECL_OBJC_IVAR, + /// \brief A ObjCAtDefsFieldDecl record. DECL_OBJC_AT_DEFS_FIELD, + /// \brief A ObjCCategoryDecl record. DECL_OBJC_CATEGORY, + /// \brief A ObjCCategoryImplDecl record. DECL_OBJC_CATEGORY_IMPL, + /// \brief A ObjCImplementationDecl record. DECL_OBJC_IMPLEMENTATION, + /// \brief A ObjCCompatibleAliasDecl record. DECL_OBJC_COMPATIBLE_ALIAS, + /// \brief A ObjCPropertyDecl record. DECL_OBJC_PROPERTY, + /// \brief A ObjCPropertyImplDecl record. DECL_OBJC_PROPERTY_IMPL, + /// \brief A FieldDecl record. DECL_FIELD, + /// \brief A MSPropertyDecl record. DECL_MS_PROPERTY, + /// \brief A VarDecl record. DECL_VAR, + /// \brief An ImplicitParamDecl record. DECL_IMPLICIT_PARAM, + /// \brief A ParmVarDecl record. DECL_PARM_VAR, + /// \brief A DecompositionDecl record. DECL_DECOMPOSITION, + /// \brief A BindingDecl record. DECL_BINDING, + /// \brief A FileScopeAsmDecl record. DECL_FILE_SCOPE_ASM, + /// \brief A BlockDecl record. DECL_BLOCK, + /// \brief A CapturedDecl record. DECL_CAPTURED, + /// \brief A record that stores the set of declarations that are /// lexically stored within a given DeclContext. /// @@ -1108,6 +1277,7 @@ namespace clang { /// the contents of a DeclContext, e.g., via /// DeclContext::decls_begin() and DeclContext::decls_end(). DECL_CONTEXT_LEXICAL, + /// \brief A record that stores the set of declarations that are /// visible from a given DeclContext. /// @@ -1116,104 +1286,151 @@ namespace clang { /// IDs. This data is used when performing qualified name lookup /// into a DeclContext via DeclContext::lookup. DECL_CONTEXT_VISIBLE, + /// \brief A LabelDecl record. DECL_LABEL, + /// \brief A NamespaceDecl record. DECL_NAMESPACE, + /// \brief A NamespaceAliasDecl record. DECL_NAMESPACE_ALIAS, + /// \brief A UsingDecl record. DECL_USING, + /// \brief A UsingPackDecl record. DECL_USING_PACK, + /// \brief A UsingShadowDecl record. DECL_USING_SHADOW, + /// \brief A ConstructorUsingShadowDecl record. DECL_CONSTRUCTOR_USING_SHADOW, + /// \brief A UsingDirecitveDecl record. DECL_USING_DIRECTIVE, + /// \brief An UnresolvedUsingValueDecl record. DECL_UNRESOLVED_USING_VALUE, + /// \brief An UnresolvedUsingTypenameDecl record. DECL_UNRESOLVED_USING_TYPENAME, + /// \brief A LinkageSpecDecl record. DECL_LINKAGE_SPEC, + /// \brief An ExportDecl record. DECL_EXPORT, + /// \brief A CXXRecordDecl record. DECL_CXX_RECORD, + /// \brief A CXXDeductionGuideDecl record. DECL_CXX_DEDUCTION_GUIDE, + /// \brief A CXXMethodDecl record. DECL_CXX_METHOD, + /// \brief A CXXConstructorDecl record. DECL_CXX_CONSTRUCTOR, + /// \brief A CXXConstructorDecl record for an inherited constructor. DECL_CXX_INHERITED_CONSTRUCTOR, + /// \brief A CXXDestructorDecl record. DECL_CXX_DESTRUCTOR, + /// \brief A CXXConversionDecl record. DECL_CXX_CONVERSION, + /// \brief An AccessSpecDecl record. DECL_ACCESS_SPEC, /// \brief A FriendDecl record. DECL_FRIEND, + /// \brief A FriendTemplateDecl record. DECL_FRIEND_TEMPLATE, + /// \brief A ClassTemplateDecl record. DECL_CLASS_TEMPLATE, + /// \brief A ClassTemplateSpecializationDecl record. DECL_CLASS_TEMPLATE_SPECIALIZATION, + /// \brief A ClassTemplatePartialSpecializationDecl record. DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A VarTemplateDecl record. DECL_VAR_TEMPLATE, + /// \brief A VarTemplateSpecializationDecl record. DECL_VAR_TEMPLATE_SPECIALIZATION, + /// \brief A VarTemplatePartialSpecializationDecl record. DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A FunctionTemplateDecl record. DECL_FUNCTION_TEMPLATE, + /// \brief A TemplateTypeParmDecl record. DECL_TEMPLATE_TYPE_PARM, + /// \brief A NonTypeTemplateParmDecl record. DECL_NON_TYPE_TEMPLATE_PARM, + /// \brief A TemplateTemplateParmDecl record. DECL_TEMPLATE_TEMPLATE_PARM, + /// \brief A TypeAliasTemplateDecl record. DECL_TYPE_ALIAS_TEMPLATE, + /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, + /// \brief A record containing CXXBaseSpecifiers. DECL_CXX_BASE_SPECIFIERS, + /// \brief A record containing CXXCtorInitializers. DECL_CXX_CTOR_INITIALIZERS, + /// \brief A IndirectFieldDecl record. DECL_INDIRECTFIELD, + /// \brief A NonTypeTemplateParmDecl record that stores an expanded /// non-type template parameter pack. DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, + /// \brief A TemplateTemplateParmDecl record that stores an expanded /// template template parameter pack. DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, + /// \brief A ClassScopeFunctionSpecializationDecl record a class scope /// function specialization. (Microsoft extension). DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, + /// \brief An ImportDecl recording a module import. DECL_IMPORT, + /// \brief An OMPThreadPrivateDecl record. DECL_OMP_THREADPRIVATE, + /// \brief An EmptyDecl record. DECL_EMPTY, + /// \brief An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, + /// \brief An OMPCapturedExprDecl record. DECL_OMP_CAPTUREDEXPR, + /// \brief A PragmaCommentDecl record. DECL_PRAGMA_COMMENT, + /// \brief A PragmaDetectMismatchDecl record. DECL_PRAGMA_DETECT_MISMATCH, + /// \brief An OMPDeclareReductionDecl record. DECL_OMP_DECLARE_REDUCTION, }; @@ -1229,128 +1446,190 @@ namespace clang { /// \brief A marker record that indicates that we are at the end /// of an expression. STMT_STOP = 128, + /// \brief A NULL expression. STMT_NULL_PTR, + /// \brief A reference to a previously [de]serialized Stmt record. STMT_REF_PTR, + /// \brief A NullStmt record. STMT_NULL, + /// \brief A CompoundStmt record. STMT_COMPOUND, + /// \brief A CaseStmt record. STMT_CASE, + /// \brief A DefaultStmt record. STMT_DEFAULT, + /// \brief A LabelStmt record. STMT_LABEL, + /// \brief An AttributedStmt record. STMT_ATTRIBUTED, + /// \brief An IfStmt record. STMT_IF, + /// \brief A SwitchStmt record. STMT_SWITCH, + /// \brief A WhileStmt record. STMT_WHILE, + /// \brief A DoStmt record. STMT_DO, + /// \brief A ForStmt record. STMT_FOR, + /// \brief A GotoStmt record. STMT_GOTO, + /// \brief An IndirectGotoStmt record. STMT_INDIRECT_GOTO, + /// \brief A ContinueStmt record. STMT_CONTINUE, + /// \brief A BreakStmt record. STMT_BREAK, + /// \brief A ReturnStmt record. STMT_RETURN, + /// \brief A DeclStmt record. STMT_DECL, + /// \brief A CapturedStmt record. STMT_CAPTURED, + /// \brief A GCC-style AsmStmt record. STMT_GCCASM, + /// \brief A MS-style AsmStmt record. STMT_MSASM, + /// \brief A PredefinedExpr record. EXPR_PREDEFINED, + /// \brief A DeclRefExpr record. EXPR_DECL_REF, + /// \brief An IntegerLiteral record. EXPR_INTEGER_LITERAL, + /// \brief A FloatingLiteral record. EXPR_FLOATING_LITERAL, + /// \brief An ImaginaryLiteral record. EXPR_IMAGINARY_LITERAL, + /// \brief A StringLiteral record. EXPR_STRING_LITERAL, + /// \brief A CharacterLiteral record. EXPR_CHARACTER_LITERAL, + /// \brief A ParenExpr record. EXPR_PAREN, + /// \brief A ParenListExpr record. EXPR_PAREN_LIST, + /// \brief A UnaryOperator record. EXPR_UNARY_OPERATOR, + /// \brief An OffsetOfExpr record. EXPR_OFFSETOF, + /// \brief A SizefAlignOfExpr record. EXPR_SIZEOF_ALIGN_OF, + /// \brief An ArraySubscriptExpr record. EXPR_ARRAY_SUBSCRIPT, + /// \brief A CallExpr record. EXPR_CALL, + /// \brief A MemberExpr record. EXPR_MEMBER, + /// \brief A BinaryOperator record. EXPR_BINARY_OPERATOR, + /// \brief A CompoundAssignOperator record. EXPR_COMPOUND_ASSIGN_OPERATOR, + /// \brief A ConditionOperator record. EXPR_CONDITIONAL_OPERATOR, + /// \brief An ImplicitCastExpr record. EXPR_IMPLICIT_CAST, + /// \brief A CStyleCastExpr record. EXPR_CSTYLE_CAST, + /// \brief A CompoundLiteralExpr record. EXPR_COMPOUND_LITERAL, + /// \brief An ExtVectorElementExpr record. EXPR_EXT_VECTOR_ELEMENT, + /// \brief An InitListExpr record. EXPR_INIT_LIST, + /// \brief A DesignatedInitExpr record. EXPR_DESIGNATED_INIT, + /// \brief A DesignatedInitUpdateExpr record. EXPR_DESIGNATED_INIT_UPDATE, + /// \brief An NoInitExpr record. EXPR_NO_INIT, + /// \brief An ArrayInitLoopExpr record. EXPR_ARRAY_INIT_LOOP, + /// \brief An ArrayInitIndexExpr record. EXPR_ARRAY_INIT_INDEX, + /// \brief An ImplicitValueInitExpr record. EXPR_IMPLICIT_VALUE_INIT, + /// \brief A VAArgExpr record. EXPR_VA_ARG, + /// \brief An AddrLabelExpr record. EXPR_ADDR_LABEL, + /// \brief A StmtExpr record. EXPR_STMT, + /// \brief A ChooseExpr record. EXPR_CHOOSE, + /// \brief A GNUNullExpr record. EXPR_GNU_NULL, + /// \brief A ShuffleVectorExpr record. EXPR_SHUFFLE_VECTOR, + /// \brief A ConvertVectorExpr record. EXPR_CONVERT_VECTOR, + /// \brief BlockExpr EXPR_BLOCK, + /// \brief A GenericSelectionExpr record. EXPR_GENERIC_SELECTION, + /// \brief A PseudoObjectExpr record. EXPR_PSEUDO_OBJECT, + /// \brief An AtomicExpr record. EXPR_ATOMIC, @@ -1362,45 +1641,61 @@ namespace clang { EXPR_OBJC_BOXED_EXPRESSION, EXPR_OBJC_ARRAY_LITERAL, EXPR_OBJC_DICTIONARY_LITERAL, - - + /// \brief An ObjCEncodeExpr record. EXPR_OBJC_ENCODE, + /// \brief An ObjCSelectorExpr record. EXPR_OBJC_SELECTOR_EXPR, + /// \brief An ObjCProtocolExpr record. EXPR_OBJC_PROTOCOL_EXPR, + /// \brief An ObjCIvarRefExpr record. EXPR_OBJC_IVAR_REF_EXPR, + /// \brief An ObjCPropertyRefExpr record. EXPR_OBJC_PROPERTY_REF_EXPR, + /// \brief An ObjCSubscriptRefExpr record. EXPR_OBJC_SUBSCRIPT_REF_EXPR, + /// \brief UNUSED EXPR_OBJC_KVC_REF_EXPR, + /// \brief An ObjCMessageExpr record. EXPR_OBJC_MESSAGE_EXPR, + /// \brief An ObjCIsa Expr record. EXPR_OBJC_ISA, + /// \brief An ObjCIndirectCopyRestoreExpr record. EXPR_OBJC_INDIRECT_COPY_RESTORE, /// \brief An ObjCForCollectionStmt record. STMT_OBJC_FOR_COLLECTION, + /// \brief An ObjCAtCatchStmt record. STMT_OBJC_CATCH, + /// \brief An ObjCAtFinallyStmt record. STMT_OBJC_FINALLY, + /// \brief An ObjCAtTryStmt record. STMT_OBJC_AT_TRY, + /// \brief An ObjCAtSynchronizedStmt record. STMT_OBJC_AT_SYNCHRONIZED, + /// \brief An ObjCAtThrowStmt record. STMT_OBJC_AT_THROW, + /// \brief An ObjCAutoreleasePoolStmt record. STMT_OBJC_AUTORELEASE_POOL, + /// \brief An ObjCBoolLiteralExpr record. EXPR_OBJC_BOOL_LITERAL, + /// \brief An ObjCAvailabilityCheckExpr record. EXPR_OBJC_AVAILABILITY_CHECK, @@ -1408,37 +1703,52 @@ namespace clang { /// \brief A CXXCatchStmt record. STMT_CXX_CATCH, + /// \brief A CXXTryStmt record. STMT_CXX_TRY, /// \brief A CXXForRangeStmt record. + STMT_CXX_FOR_RANGE, /// \brief A CXXOperatorCallExpr record. EXPR_CXX_OPERATOR_CALL, + /// \brief A CXXMemberCallExpr record. EXPR_CXX_MEMBER_CALL, + /// \brief A CXXConstructExpr record. EXPR_CXX_CONSTRUCT, + /// \brief A CXXInheritedCtorInitExpr record. EXPR_CXX_INHERITED_CTOR_INIT, + /// \brief A CXXTemporaryObjectExpr record. EXPR_CXX_TEMPORARY_OBJECT, + /// \brief A CXXStaticCastExpr record. EXPR_CXX_STATIC_CAST, + /// \brief A CXXDynamicCastExpr record. EXPR_CXX_DYNAMIC_CAST, + /// \brief A CXXReinterpretCastExpr record. EXPR_CXX_REINTERPRET_CAST, + /// \brief A CXXConstCastExpr record. EXPR_CXX_CONST_CAST, + /// \brief A CXXFunctionalCastExpr record. EXPR_CXX_FUNCTIONAL_CAST, + /// \brief A UserDefinedLiteral record. EXPR_USER_DEFINED_LITERAL, + /// \brief A CXXStdInitializerListExpr record. EXPR_CXX_STD_INITIALIZER_LIST, + /// \brief A CXXBoolLiteralExpr record. EXPR_CXX_BOOL_LITERAL, + EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). @@ -1560,11 +1870,14 @@ namespace clang { enum DesignatorTypes { /// \brief Field designator where only the field name is known. DESIG_FIELD_NAME = 0, + /// \brief Field designator where the field has been resolved to /// a declaration. DESIG_FIELD_DECL = 1, + /// \brief Array designator. DESIG_ARRAY = 2, + /// \brief GNU array range designator. DESIG_ARRAY_RANGE = 3 }; @@ -1580,8 +1893,11 @@ namespace clang { /// \brief Describes the redeclarations of a declaration. struct LocalRedeclarationsInfo { - DeclID FirstID; // The ID of the first declaration - unsigned Offset; // Offset into the array of redeclaration chains. + // The ID of the first declaration + DeclID FirstID; + + // Offset into the array of redeclaration chains. + unsigned Offset; friend bool operator<(const LocalRedeclarationsInfo &X, const LocalRedeclarationsInfo &Y) { @@ -1606,8 +1922,11 @@ namespace clang { /// \brief Describes the categories of an Objective-C class. struct ObjCCategoriesInfo { - DeclID DefinitionID; // The ID of the definition - unsigned Offset; // Offset into the array of category lists. + // The ID of the definition + DeclID DefinitionID; + + // Offset into the array of category lists. + unsigned Offset; friend bool operator<(const ObjCCategoriesInfo &X, const ObjCCategoriesInfo &Y) { @@ -1636,15 +1955,14 @@ namespace clang { /// same key can occasionally represent multiple names (for names that /// contain types, in particular). class DeclarationNameKey { - typedef unsigned NameKind; + using NameKind = unsigned; - NameKind Kind; - uint64_t Data; + NameKind Kind = 0; + uint64_t Data = 0; public: - DeclarationNameKey() : Kind(), Data() {} + DeclarationNameKey() = default; DeclarationNameKey(DeclarationName Name); - DeclarationNameKey(NameKind Kind, uint64_t Data) : Kind(Kind), Data(Data) {} @@ -1656,12 +1974,14 @@ namespace clang { Kind == DeclarationName::CXXDeductionGuideName); return (IdentifierInfo *)Data; } + Selector getSelector() const { assert(Kind == DeclarationName::ObjCZeroArgSelector || Kind == DeclarationName::ObjCOneArgSelector || Kind == DeclarationName::ObjCMultiArgSelector); return Selector(Data); } + OverloadedOperatorKind getOperatorKind() const { assert(Kind == DeclarationName::CXXOperatorName); return (OverloadedOperatorKind)Data; @@ -1677,26 +1997,32 @@ namespace clang { }; /// @} - } -} // end namespace clang + +} // namespace serialization +} // namespace clang namespace llvm { + template <> struct DenseMapInfo<clang::serialization::DeclarationNameKey> { static clang::serialization::DeclarationNameKey getEmptyKey() { return clang::serialization::DeclarationNameKey(-1, 1); } + static clang::serialization::DeclarationNameKey getTombstoneKey() { return clang::serialization::DeclarationNameKey(-1, 2); } + static unsigned getHashValue(const clang::serialization::DeclarationNameKey &Key) { return Key.getHash(); } + static bool isEqual(const clang::serialization::DeclarationNameKey &L, const clang::serialization::DeclarationNameKey &R) { return L == R; } }; -} -#endif +} // namespace llvm + +#endif // LLVM_CLANG_SERIALIZATION_ASTBITCODES_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h index eafa051758325..7b71fee95de27 100644 --- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h @@ -1,4 +1,4 @@ -//===--- ASTReader.h - AST File Reader --------------------------*- C++ -*-===// +//===- ASTReader.h - AST File Reader ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,13 +17,21 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Token.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Serialization/ASTBitCodes.h" @@ -31,70 +39,86 @@ #include "clang/Serialization/Module.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/ModuleManager.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/TinyPtrVector.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <ctime> #include <deque> #include <memory> +#include <set> #include <string> #include <utility> #include <vector> -namespace llvm { - class BitstreamCursor; - class MemoryBuffer; - class APInt; - class APSInt; - class APFloat; -} - namespace clang { -class SourceManager; -class HeaderSearchOptions; -class FileManager; -class AddrLabelExpr; class ASTConsumer; class ASTContext; -class ASTIdentifierIterator; -class ASTUnit; // FIXME: Layering violation and egregious hack. -class Attr; -class Decl; -class DeclContext; -class DefMacroDirective; -class DiagnosticOptions; -class NestedNameSpecifier; +class ASTDeserializationListener; +class ASTReader; +class ASTRecordReader; class CXXBaseSpecifier; class CXXConstructorDecl; class CXXCtorInitializer; +class CXXTemporary; +class Decl; +class DeclaratorDecl; +class DeclContext; +class EnumDecl; +class Expr; +class FieldDecl; +class FileEntry; +class FileManager; +class FileSystemOptions; +class FunctionDecl; class GlobalModuleIndex; -class GotoStmt; -class MacroDefinition; -class MacroDirective; -class ModuleMacro; +struct HeaderFileInfo; +class HeaderSearchOptions; +class LangOptions; +class LazyASTUnresolvedSet; +class MacroInfo; +class MemoryBufferCache; class NamedDecl; -class OpaqueValueExpr; +class NamespaceDecl; +class NestedNameSpecifier; +class ObjCCategoryDecl; +class ObjCInterfaceDecl; +class PCHContainerReader; class Preprocessor; class PreprocessorOptions; +struct QualifierInfo; class Sema; +class SourceManager; +class Stmt; class SwitchCase; -class ASTDeserializationListener; -class ASTWriter; -class ASTReader; -class ASTDeclReader; -class ASTStmtReader; -class ASTRecordReader; -class TypeLocReader; -struct HeaderFileInfo; -class VersionTuple; class TargetOptions; -class LazyASTUnresolvedSet; +class TemplateParameterList; +class TypedefNameDecl; +class TypeSourceInfo; +class ValueDecl; +class VarDecl; /// \brief Abstract interface for callback invocations by the ASTReader. /// @@ -189,9 +213,11 @@ public: /// \brief Returns true if this \c ASTReaderListener wants to receive the /// input files of the AST file via \c visitInputFile, false otherwise. virtual bool needsInputFileVisitation() { return false; } + /// \brief Returns true if this \c ASTReaderListener wants to receive the /// system input files of the AST file via \c visitInputFile, false otherwise. virtual bool needsSystemInputFileVisitation() { return false; } + /// \brief if \c needsInputFileVisitation returns true, this is called for /// each non-system input file of the AST File. If /// \c needsSystemInputFileVisitation is true, then it is called for all @@ -206,6 +232,7 @@ public: /// \brief Returns true if this \c ASTReaderListener wants to receive the /// imports of the AST file via \c visitImport, false otherwise. virtual bool needsImportVisitation() const { return false; } + /// \brief If needsImportVisitation returns \c true, this is called for each /// AST file imported by this AST file. virtual void visitImport(StringRef Filename) {} @@ -306,12 +333,15 @@ namespace serialization { class ReadMethodPoolVisitor; namespace reader { - class ASTIdentifierLookupTrait; - /// \brief The on-disk hash table(s) used for DeclContext name lookup. - struct DeclContextLookupTable; -} -} // end namespace serialization +class ASTIdentifierLookupTrait; + +/// \brief The on-disk hash table(s) used for DeclContext name lookup. +struct DeclContextLookupTable; + +} // namespace reader + +} // namespace serialization /// \brief Reads an AST files chain containing the contents of a translation /// unit. @@ -334,8 +364,20 @@ class ASTReader public ExternalSLocEntrySource { public: - typedef SmallVector<uint64_t, 64> RecordData; - typedef SmallVectorImpl<uint64_t> RecordDataImpl; + /// \brief Types of AST files. + friend class ASTDeclReader; + friend class ASTIdentifierIterator; + friend class ASTRecordReader; + friend class ASTStmtReader; + friend class ASTUnit; // ASTUnit needs to remap source locations. + friend class ASTWriter; + friend class PCHValidator; + friend class serialization::reader::ASTIdentifierLookupTrait; + friend class serialization::ReadMethodPoolVisitor; + friend class TypeLocReader; + + using RecordData = SmallVector<uint64_t, 64>; + using RecordDataImpl = SmallVectorImpl<uint64_t>; /// \brief The result of reading the control block of an AST file, which /// can fail for various reasons. @@ -343,41 +385,34 @@ public: /// \brief The control block was read successfully. Aside from failures, /// the AST file is safe to read into the current context. Success, + /// \brief The AST file itself appears corrupted. Failure, + /// \brief The AST file was missing. Missing, + /// \brief The AST file is out-of-date relative to its input files, /// and needs to be regenerated. OutOfDate, + /// \brief The AST file was written by a different version of Clang. VersionMismatch, + /// \brief The AST file was writtten with a different language/target /// configuration. ConfigurationMismatch, + /// \brief The AST file has errors. HadErrors }; - /// \brief Types of AST files. - friend class PCHValidator; - friend class ASTDeclReader; - friend class ASTStmtReader; - friend class ASTIdentifierIterator; - friend class serialization::reader::ASTIdentifierLookupTrait; - friend class TypeLocReader; - friend class ASTRecordReader; - friend class ASTWriter; - friend class ASTUnit; // ASTUnit needs to remap source locations. - friend class serialization::ReadMethodPoolVisitor; - - typedef serialization::ModuleFile ModuleFile; - typedef serialization::ModuleKind ModuleKind; - typedef serialization::ModuleManager ModuleManager; - - typedef ModuleManager::ModuleIterator ModuleIterator; - typedef ModuleManager::ModuleConstIterator ModuleConstIterator; - typedef ModuleManager::ModuleReverseIterator ModuleReverseIterator; + using ModuleFile = serialization::ModuleFile; + using ModuleKind = serialization::ModuleKind; + using ModuleManager = serialization::ModuleManager; + using ModuleIterator = ModuleManager::ModuleIterator; + using ModuleConstIterator = ModuleManager::ModuleConstIterator; + using ModuleReverseIterator = ModuleManager::ModuleReverseIterator; private: /// \brief The receiver of some callbacks invoked by ASTReader. @@ -385,6 +420,7 @@ private: /// \brief The receiver of deserialization events. ASTDeserializationListener *DeserializationListener = nullptr; + bool OwnsDeserializationListener = false; SourceManager &SourceMgr; @@ -436,7 +472,8 @@ private: /// \brief A map of negated SLocEntryIDs to the modules containing them. ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocEntryMap; - typedef ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocOffsetMapType; + using GlobalSLocOffsetMapType = + ContinuousRangeMap<unsigned, ModuleFile *, 64>; /// \brief A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset) /// SourceLocation offsets to the modules containing them. @@ -448,8 +485,8 @@ private: /// ID = (I + 1) << FastQual::Width has already been loaded std::vector<QualType> TypesLoaded; - typedef ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4> - GlobalTypeMapType; + using GlobalTypeMapType = + ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4>; /// \brief Mapping from global type IDs to the module in which the /// type resides along with the offset that should be added to the @@ -462,17 +499,17 @@ private: /// = I + 1 has already been loaded. std::vector<Decl *> DeclsLoaded; - typedef ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4> - GlobalDeclMapType; + using GlobalDeclMapType = + ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4>; /// \brief Mapping from global declaration IDs to the module in which the /// declaration resides. GlobalDeclMapType GlobalDeclMap; - typedef std::pair<ModuleFile *, uint64_t> FileOffset; - typedef SmallVector<FileOffset, 2> FileOffsetsTy; - typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy> - DeclUpdateOffsetsMap; + using FileOffset = std::pair<ModuleFile *, uint64_t>; + using FileOffsetsTy = SmallVector<FileOffset, 2>; + using DeclUpdateOffsetsMap = + llvm::DenseMap<serialization::DeclID, FileOffsetsTy>; /// \brief Declarations that have modifications residing in a later file /// in the chain. @@ -481,12 +518,15 @@ private: struct PendingUpdateRecord { Decl *D; serialization::GlobalDeclID ID; + // Whether the declaration was just deserialized. bool JustLoaded; + PendingUpdateRecord(serialization::GlobalDeclID ID, Decl *D, bool JustLoaded) : D(D), ID(ID), JustLoaded(JustLoaded) {} }; + /// \brief Declaration updates for already-loaded declarations that we need /// to apply once we finish processing an import. llvm::SmallVector<PendingUpdateRecord, 16> PendingUpdateRecords; @@ -505,7 +545,7 @@ private: /// \brief Declarations that have been imported and have typedef names for /// linkage purposes. - llvm::DenseMap<std::pair<DeclContext*, IdentifierInfo*>, NamedDecl*> + llvm::DenseMap<std::pair<DeclContext *, IdentifierInfo *>, NamedDecl *> ImportedTypedefNamesForLinkage; /// \brief Mergeable declaration contexts that have anonymous declarations @@ -514,10 +554,10 @@ private: AnonymousDeclarationsForMerging; struct FileDeclsInfo { - ModuleFile *Mod; + ModuleFile *Mod = nullptr; ArrayRef<serialization::LocalDeclID> Decls; - FileDeclsInfo() : Mod(nullptr) {} + FileDeclsInfo() = default; FileDeclsInfo(ModuleFile *Mod, ArrayRef<serialization::LocalDeclID> Decls) : Mod(Mod), Decls(Decls) {} }; @@ -527,7 +567,7 @@ private: /// \brief An array of lexical contents of a declaration context, as a sequence of /// Decl::Kind, DeclID pairs. - typedef ArrayRef<llvm::support::unaligned_uint32_t> LexicalContents; + using LexicalContents = ArrayRef<llvm::support::unaligned_uint32_t>; /// \brief Map from a DeclContext to its lexical contents. llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>> @@ -548,7 +588,7 @@ private: ModuleFile *Mod; const unsigned char *Data; }; - typedef SmallVector<PendingVisibleUpdate, 1> DeclContextVisibleUpdates; + using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>; /// \brief Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. @@ -559,22 +599,23 @@ private: /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet<Decl *, 4> PendingDefinitions; - typedef llvm::MapVector<Decl *, uint64_t, - llvm::SmallDenseMap<Decl *, unsigned, 4>, - SmallVector<std::pair<Decl *, uint64_t>, 4> > - PendingBodiesMap; + using PendingBodiesMap = + llvm::MapVector<Decl *, uint64_t, + llvm::SmallDenseMap<Decl *, unsigned, 4>, + SmallVector<std::pair<Decl *, uint64_t>, 4>>; /// \brief Functions or methods that have bodies that will be attached. PendingBodiesMap PendingBodies; /// \brief Definitions for which we have added merged definitions but not yet /// performed deduplication. - llvm::SetVector<NamedDecl*> PendingMergedDefinitionsToDeduplicate; + llvm::SetVector<NamedDecl *> PendingMergedDefinitionsToDeduplicate; /// \brief Read the record that describes the lexical contents of a DC. bool ReadLexicalDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, uint64_t Offset, DeclContext *DC); + /// \brief Read the record that describes the visible contents of a DC. bool ReadVisibleDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, @@ -588,8 +629,8 @@ private: /// been loaded. std::vector<IdentifierInfo *> IdentifiersLoaded; - typedef ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4> - GlobalIdentifierMapType; + using GlobalIdentifierMapType = + ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4>; /// \brief Mapping from global identifier IDs to the module in which the /// identifier resides along with the offset that should be added to the @@ -604,16 +645,16 @@ private: /// been loaded. std::vector<MacroInfo *> MacrosLoaded; - typedef std::pair<IdentifierInfo *, serialization::SubmoduleID> - LoadedMacroInfo; + using LoadedMacroInfo = + std::pair<IdentifierInfo *, serialization::SubmoduleID>; /// \brief A set of #undef directives that we have loaded; used to /// deduplicate the same #undef information coming from multiple module /// files. llvm::DenseSet<LoadedMacroInfo> LoadedUndefs; - typedef ContinuousRangeMap<serialization::MacroID, ModuleFile *, 4> - GlobalMacroMapType; + using GlobalMacroMapType = + ContinuousRangeMap<serialization::MacroID, ModuleFile *, 4>; /// \brief Mapping from global macro IDs to the module in which the /// macro resides along with the offset that should be added to the @@ -626,8 +667,8 @@ private: /// indicate that the particular submodule ID has not yet been loaded. SmallVector<Module *, 2> SubmodulesLoaded; - typedef ContinuousRangeMap<serialization::SubmoduleID, ModuleFile *, 4> - GlobalSubmoduleMapType; + using GlobalSubmoduleMapType = + ContinuousRangeMap<serialization::SubmoduleID, ModuleFile *, 4>; /// \brief Mapping from global submodule IDs to the module file in which the /// submodule resides along with the offset that should be added to the @@ -635,14 +676,13 @@ private: GlobalSubmoduleMapType GlobalSubmoduleMap; /// \brief A set of hidden declarations. - typedef SmallVector<Decl*, 2> HiddenNames; - typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType; + using HiddenNames = SmallVector<Decl *, 2>; + using HiddenNamesMapType = llvm::DenseMap<Module *, HiddenNames>; /// \brief A mapping from each of the hidden submodules to the deserialized /// declarations in that submodule that could be made visible. HiddenNamesMapType HiddenNamesMap; - /// \brief A module import, export, or conflict that hasn't yet been resolved. struct UnresolvedModuleRef { /// \brief The file in which this module resides. @@ -675,11 +715,10 @@ private: /// been loaded. SmallVector<Selector, 16> SelectorsLoaded; - typedef ContinuousRangeMap<serialization::SelectorID, ModuleFile *, 4> - GlobalSelectorMapType; + using GlobalSelectorMapType = + ContinuousRangeMap<serialization::SelectorID, ModuleFile *, 4>; /// \brief Mapping from global selector IDs to the module in which the - /// global selector ID to produce a local ID. GlobalSelectorMapType GlobalSelectorMap; @@ -699,15 +738,15 @@ private: : M(M), MacroDirectivesOffset(MacroDirectivesOffset) {} }; - typedef llvm::MapVector<IdentifierInfo *, SmallVector<PendingMacroInfo, 2> > - PendingMacroIDsMap; + using PendingMacroIDsMap = + llvm::MapVector<IdentifierInfo *, SmallVector<PendingMacroInfo, 2>>; /// \brief Mapping from identifiers that have a macro history to the global /// IDs have not yet been deserialized to the global IDs of those macros. PendingMacroIDsMap PendingMacroIDs; - typedef ContinuousRangeMap<unsigned, ModuleFile *, 4> - GlobalPreprocessedEntityMapType; + using GlobalPreprocessedEntityMapType = + ContinuousRangeMap<unsigned, ModuleFile *, 4>; /// \brief Mapping from global preprocessing entity IDs to the module in /// which the preprocessed entity resides along with the offset that should be @@ -825,6 +864,7 @@ private: struct PragmaPackStackEntry { unsigned Value; SourceLocation Location; + SourceLocation PushLocation; StringRef SlotLabel; }; llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack; @@ -867,9 +907,6 @@ private: SmallVector<ImportedSubmodule, 2> ImportedModules; //@} - /// \brief The directory that the PCH we are reading is stored in. - std::string CurrentDir; - /// \brief The system include root to be used when loading the /// precompiled header. std::string isysroot; @@ -897,7 +934,8 @@ private: ///\brief Whether we are currently processing update records. bool ProcessingUpdateRecords = false; - typedef llvm::DenseMap<unsigned, SwitchCase *> SwitchCaseMapTy; + using SwitchCaseMapTy = llvm::DenseMap<unsigned, SwitchCase *>; + /// \brief Mapping from switch-case IDs in the chain to switch-case statements /// /// Statements usually don't have IDs, but switch cases need them, so that the @@ -981,7 +1019,7 @@ private: /// /// The declarations on the identifier chain for these identifiers will be /// loaded once the recursive loading has completed. - llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> > + llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4>> PendingIdentifierInfos; /// \brief The set of lookup results that we have faked in order to support @@ -1000,7 +1038,9 @@ private: public: InterestingDecl(Decl *D, bool HasBody) : D(D), DeclHasPendingBody(HasBody) {} + Decl *getDecl() { return D; } + /// Whether the declaration has a pending body. bool hasPendingBody() { return DeclHasPendingBody; } }; @@ -1045,8 +1085,11 @@ private: /// once recursing loading has been completed. llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks; + using DataPointers = + std::pair<CXXRecordDecl *, struct CXXRecordDecl::DefinitionData *>; + /// \brief Record definitions in which we found an ODR violation. - llvm::SmallDenseMap<CXXRecordDecl *, llvm::TinyPtrVector<CXXRecordDecl *>, 2> + llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, 2>, 2> PendingOdrMergeFailures; /// \brief DeclContexts in which we have diagnosed an ODR violation. @@ -1061,8 +1104,8 @@ private: /// module is loaded. SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded; - typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> > - KeyDeclsMap; + using KeyDeclsMap = + llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2>>; /// \brief A mapping from canonical declarations to the set of global /// declaration IDs for key declaration that have been merged with that @@ -1096,15 +1139,14 @@ private: ASTReader &Reader; enum ReadingKind PrevKind; - ReadingKindTracker(const ReadingKindTracker &) = delete; - void operator=(const ReadingKindTracker &) = delete; - public: ReadingKindTracker(enum ReadingKind newKind, ASTReader &reader) : Reader(reader), PrevKind(Reader.ReadingKind) { Reader.ReadingKind = newKind; } + ReadingKindTracker(const ReadingKindTracker &) = delete; + ReadingKindTracker &operator=(const ReadingKindTracker &) = delete; ~ReadingKindTracker() { Reader.ReadingKind = PrevKind; } }; @@ -1113,15 +1155,15 @@ private: ASTReader &Reader; bool PrevState; - ProcessingUpdatesRAIIObj(const ProcessingUpdatesRAIIObj &) = delete; - void operator=(const ProcessingUpdatesRAIIObj &) = delete; - public: ProcessingUpdatesRAIIObj(ASTReader &reader) : Reader(reader), PrevState(Reader.ProcessingUpdateRecords) { Reader.ProcessingUpdateRecords = true; } + ProcessingUpdatesRAIIObj(const ProcessingUpdatesRAIIObj &) = delete; + ProcessingUpdatesRAIIObj & + operator=(const ProcessingUpdatesRAIIObj &) = delete; ~ProcessingUpdatesRAIIObj() { Reader.ProcessingUpdateRecords = PrevState; } }; @@ -1135,7 +1177,7 @@ private: /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; - llvm::DenseMap<const Decl *, bool> BodySource; + llvm::DenseMap<const Decl *, bool> DefinitionSource; /// \brief Reads a statement from the specified cursor. Stmt *ReadStmtFromStream(ModuleFile &F); @@ -1204,7 +1246,7 @@ private: ImportedModule(ModuleFile *Mod, ModuleFile *ImportedBy, SourceLocation ImportLoc) - : Mod(Mod), ImportedBy(ImportedBy), ImportLoc(ImportLoc) { } + : Mod(Mod), ImportedBy(ImportedBy), ImportLoc(ImportLoc) {} }; ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type, @@ -1265,10 +1307,11 @@ private: std::string &SuggestedPredefines); struct RecordLocation { - RecordLocation(ModuleFile *M, uint64_t O) - : F(M), Offset(O) {} ModuleFile *F; uint64_t Offset; + + RecordLocation(ModuleFile *M, uint64_t O) + : F(M), Offset(O) {} }; QualType readTypeRecord(unsigned Index); @@ -1327,12 +1370,11 @@ public: ModuleDeclIterator, const serialization::LocalDeclID *, std::random_access_iterator_tag, const Decl *, ptrdiff_t, const Decl *, const Decl *> { - ASTReader *Reader; - ModuleFile *Mod; + ASTReader *Reader = nullptr; + ModuleFile *Mod = nullptr; public: - ModuleDeclIterator() - : iterator_adaptor_base(nullptr), Reader(nullptr), Mod(nullptr) {} + ModuleDeclIterator() : iterator_adaptor_base(nullptr) {} ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod, const serialization::LocalDeclID *Pos) @@ -1341,6 +1383,7 @@ public: value_type operator*() const { return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *I)); } + value_type operator->() const { return **this; } bool operator==(const ModuleDeclIterator &RHS) const { @@ -1377,8 +1420,6 @@ private: void Error(unsigned DiagID, StringRef Arg1 = StringRef(), StringRef Arg2 = StringRef()) const; - ASTReader(const ASTReader &) = delete; - void operator=(const ASTReader &) = delete; public: /// \brief Load the AST file and validate its contents against the given /// Preprocessor. @@ -1427,7 +1468,8 @@ public: bool AllowConfigurationMismatch = false, bool ValidateSystemInputs = false, bool UseGlobalIndex = true, std::unique_ptr<llvm::Timer> ReadTimer = {}); - + ASTReader(const ASTReader &) = delete; + ASTReader &operator=(const ASTReader &) = delete; ~ASTReader() override; SourceManager &getSourceManager() const { return SourceMgr; } @@ -1442,15 +1484,19 @@ public: enum LoadFailureCapabilities { /// \brief The client can't handle any AST loading failures. ARR_None = 0, + /// \brief The client can handle an AST file that cannot load because it /// is missing. ARR_Missing = 0x1, + /// \brief The client can handle an AST file that cannot load because it /// is out-of-date relative to its input files. ARR_OutOfDate = 0x2, + /// \brief The client can handle an AST file that cannot load because it /// was built with a different version of Clang. ARR_VersionMismatch = 0x4, + /// \brief The client can handle an AST file that cannot load because it's /// compiled configuration doesn't match that of the context it was /// loaded into. @@ -1521,11 +1567,11 @@ public: /// RAII object to temporarily add an AST callback listener. class ListenerScope { ASTReader &Reader; - bool Chained; + bool Chained = false; public: ListenerScope(ASTReader &Reader, std::unique_ptr<ASTReaderListener> L) - : Reader(Reader), Chained(false) { + : Reader(Reader) { auto Old = Reader.takeListener(); if (Old) { Chained = true; @@ -1534,6 +1580,7 @@ public: } Reader.setListener(std::move(L)); } + ~ListenerScope() { auto New = Reader.takeListener(); if (Chained) @@ -1932,16 +1979,16 @@ public: llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override; void ReadReferencedSelectors( - SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) override; + SmallVectorImpl<std::pair<Selector, SourceLocation>> &Sels) override; void ReadWeakUndeclaredIdentifiers( - SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) override; + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo>> &WI) override; void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override; void ReadPendingInstantiations( - SmallVectorImpl<std::pair<ValueDecl *, - SourceLocation> > &Pending) override; + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation>> &Pending) override; void ReadLateParsedTemplates( llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> @@ -2144,9 +2191,19 @@ public: // \brief Read a string static std::string ReadString(const RecordData &Record, unsigned &Idx); + // \brief Skip a string + static void SkipString(const RecordData &Record, unsigned &Idx) { + Idx += Record[Idx] + 1; + } + // \brief Read a path std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx); + // \brief Skip a path + static void SkipPath(const RecordData &Record, unsigned &Idx) { + SkipString(Record, Idx); + } + /// \brief Read a version tuple. static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx); @@ -2264,20 +2321,19 @@ public: /// \brief An object for streaming information from a record. class ASTRecordReader { - typedef serialization::ModuleFile ModuleFile; + using ModuleFile = serialization::ModuleFile; ASTReader *Reader; ModuleFile *F; unsigned Idx = 0; ASTReader::RecordData Record; - typedef ASTReader::RecordData RecordData; - typedef ASTReader::RecordDataImpl RecordDataImpl; + using RecordData = ASTReader::RecordData; + using RecordDataImpl = ASTReader::RecordDataImpl; public: /// Construct an ASTRecordReader that uses the default encoding scheme. - ASTRecordReader(ASTReader &Reader, ModuleFile &F) - : Reader(&Reader), F(&F) {} + ASTRecordReader(ASTReader &Reader, ModuleFile &F) : Reader(&Reader), F(&F) {} /// \brief Reads a record with id AbbrevID from Cursor, resetting the /// internal state. @@ -2291,17 +2347,20 @@ public: /// \brief The current position in this record. unsigned getIdx() const { return Idx; } + /// \brief The length of this record. size_t size() const { return Record.size(); } /// \brief An arbitrary index in this record. const uint64_t &operator[](size_t N) { return Record[N]; } + /// \brief The last element in this record. const uint64_t &back() const { return Record.back(); } /// \brief Returns the current value in this record, and advances to the /// next value. const uint64_t &readInt() { return Record[Idx++]; } + /// \brief Returns the current value in this record, without advancing. const uint64_t &peekInt() { return Record[Idx]; } @@ -2555,7 +2614,7 @@ public: /// then restores it when destroyed. struct SavedStreamPosition { explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) - : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } + : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) {} ~SavedStreamPosition() { Cursor.JumpToBit(Offset); @@ -2570,6 +2629,6 @@ inline void PCHValidator::Error(const char *Msg) { Reader.Error(Msg); } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h index f14dfc73baa98..9437bf7f2c9f1 100644 --- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h @@ -1,4 +1,4 @@ -//===--- ASTWriter.h - AST File Writer --------------------------*- C++ -*-===// +//===- ASTWriter.h - AST File Writer ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,67 +11,89 @@ // containing a serialized representation of a translation unit. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_SERIALIZATION_ASTWRITER_H #define LLVM_CLANG_SERIALIZATION_ASTWRITER_H #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Bitcode/BitstreamWriter.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <ctime> +#include <memory> #include <queue> +#include <string> +#include <utility> #include <vector> namespace llvm { - class APFloat; - class APInt; -} + +class APFloat; +class APInt; +class APSInt; + +} // namespace llvm namespace clang { -class DeclarationName; class ASTContext; +class ASTReader; +class ASTUnresolvedSet; class Attr; -class NestedNameSpecifier; class CXXBaseSpecifier; class CXXCtorInitializer; +class CXXRecordDecl; +class CXXTemporary; class FileEntry; class FPOptions; +class FunctionDecl; class HeaderSearch; class HeaderSearchOptions; class IdentifierResolver; +class LangOptions; class MacroDefinitionRecord; -class MacroDirective; class MacroInfo; -class OpaqueValueExpr; -class OpenCLOptions; -class ASTReader; class MemoryBufferCache; class Module; class ModuleFileExtension; class ModuleFileExtensionWriter; -class PreprocessedEntity; +class NamedDecl; +class NestedNameSpecifier; +class ObjCInterfaceDecl; class PreprocessingRecord; class Preprocessor; +struct QualifierInfo; class RecordDecl; class Sema; class SourceManager; +class Stmt; struct StoredDeclsList; class SwitchCase; -class TargetInfo; +class TemplateParameterList; class Token; +class TypeSourceInfo; class VersionTuple; -class ASTUnresolvedSet; - -namespace SrcMgr { class SLocEntry; } /// \brief Writes an AST file containing the contents of a translation unit. /// @@ -82,14 +104,15 @@ namespace SrcMgr { class SLocEntry; } class ASTWriter : public ASTDeserializationListener, public ASTMutationListener { public: - typedef SmallVector<uint64_t, 64> RecordData; - typedef SmallVectorImpl<uint64_t> RecordDataImpl; - typedef ArrayRef<uint64_t> RecordDataRef; - friend class ASTDeclWriter; + friend class ASTRecordWriter; friend class ASTStmtWriter; friend class ASTTypeWriter; - friend class ASTRecordWriter; + + using RecordData = SmallVector<uint64_t, 64>; + using RecordDataImpl = SmallVectorImpl<uint64_t>; + using RecordDataRef = ArrayRef<uint64_t>; + private: /// \brief Map that provides the ID numbers of each type within the /// output stream, plus those deserialized from a chained PCH. @@ -100,9 +123,8 @@ private: /// allow for the const/volatile qualifiers. /// /// Keys in the map never have const/volatile qualifiers. - typedef llvm::DenseMap<QualType, serialization::TypeIdx, - serialization::UnsafeQualTypeDenseMapInfo> - TypeIdxMap; + using TypeIdxMap = llvm::DenseMap<QualType, serialization::TypeIdx, + serialization::UnsafeQualTypeDenseMapInfo>; /// \brief The bitstream writer used to emit this precompiled header. llvm::BitstreamWriter &Stream; @@ -152,8 +174,8 @@ private: /// \brief Stores a declaration or a type to be written to the AST file. class DeclOrType { public: - DeclOrType(Decl *D) : Stored(D), IsType(false) { } - DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) { } + DeclOrType(Decl *D) : Stored(D), IsType(false) {} + DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) {} bool isType() const { return IsType; } bool isDecl() const { return !IsType; } @@ -195,15 +217,16 @@ private: std::vector<serialization::DeclOffset> DeclOffsets; /// \brief Sorted (by file offset) vector of pairs of file offset/DeclID. - typedef SmallVector<std::pair<unsigned, serialization::DeclID>, 64> - LocDeclIDsTy; + using LocDeclIDsTy = + SmallVector<std::pair<unsigned, serialization::DeclID>, 64>; struct DeclIDInFileInfo { LocDeclIDsTy DeclIDs; + /// \brief Set when the DeclIDs vectors from all files are joined, this /// indicates the index that this particular vector has in the global one. unsigned FirstDeclIndex; }; - typedef llvm::DenseMap<FileID, DeclIDInFileInfo *> FileDeclIDsTy; + using FileDeclIDsTy = llvm::DenseMap<FileID, DeclIDInFileInfo *>; /// \brief Map from file SLocEntries to info about the file-level declarations /// that it contains. @@ -260,6 +283,7 @@ private: MacroInfo *MI; serialization::MacroID ID; }; + /// \brief The macro infos to emit. std::vector<MacroInfoToEmitData> MacroInfosToEmit; @@ -331,31 +355,33 @@ private: : Kind(Kind), Type(Type.getAsOpaquePtr()) {} DeclUpdate(unsigned Kind, SourceLocation Loc) : Kind(Kind), Loc(Loc.getRawEncoding()) {} - DeclUpdate(unsigned Kind, unsigned Val) - : Kind(Kind), Val(Val) {} - DeclUpdate(unsigned Kind, Module *M) - : Kind(Kind), Mod(M) {} + DeclUpdate(unsigned Kind, unsigned Val) : Kind(Kind), Val(Val) {} + DeclUpdate(unsigned Kind, Module *M) : Kind(Kind), Mod(M) {} DeclUpdate(unsigned Kind, const Attr *Attribute) : Kind(Kind), Attribute(Attribute) {} unsigned getKind() const { return Kind; } const Decl *getDecl() const { return Dcl; } QualType getType() const { return QualType::getFromOpaquePtr(Type); } + SourceLocation getLoc() const { return SourceLocation::getFromRawEncoding(Loc); } + unsigned getNumber() const { return Val; } Module *getModule() const { return Mod; } const Attr *getAttr() const { return Attribute; } }; - typedef SmallVector<DeclUpdate, 1> UpdateRecord; - typedef llvm::MapVector<const Decl *, UpdateRecord> DeclUpdateMap; + using UpdateRecord = SmallVector<DeclUpdate, 1>; + using DeclUpdateMap = llvm::MapVector<const Decl *, UpdateRecord>; + /// \brief Mapping from declarations that came from a chained PCH to the /// record containing modifications to them. DeclUpdateMap DeclUpdates; - typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap; + using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>; + /// \brief Map of first declarations from a chained PCH that point to the /// most recent declarations in another PCH. FirstLatestDeclMap FirstLatestDecls; @@ -600,7 +626,6 @@ public: /// \brief Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordDataImpl &Record); - /// \brief Force a declaration to be emitted and get its ID. serialization::DeclID GetDeclRef(const Decl *D); @@ -651,6 +676,7 @@ public: unsigned getTypeExtQualAbbrev() const { return TypeExtQualAbbrev; } + unsigned getTypeFunctionProtoAbbrev() const { return TypeFunctionProtoAbbrev; } @@ -698,12 +724,14 @@ private: void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) override; + const FunctionDecl *Delete, + Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; - void StaticDataMemberInstantiated(const VarDecl *D) override; + void InstantiationRequested(const ValueDecl *D) override; + void VariableDefinitionInstantiated(const VarDecl *D) override; + void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; - void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; void DeclarationMarkedUsed(const Decl *D) override; @@ -756,8 +784,8 @@ public: : Writer(Parent.Writer), Record(&Record) {} /// Copying an ASTRecordWriter is almost certainly a bug. - ASTRecordWriter(const ASTRecordWriter&) = delete; - void operator=(const ASTRecordWriter&) = delete; + ASTRecordWriter(const ASTRecordWriter &) = delete; + ASTRecordWriter &operator=(const ASTRecordWriter &) = delete; /// \brief Extract the underlying record storage. ASTWriter::RecordDataImpl &getRecordData() const { return *Record; } @@ -909,7 +937,7 @@ public: void AddUnresolvedSet(const ASTUnresolvedSet &Set); /// \brief Emit a CXXCtorInitializer array. - void AddCXXCtorInitializers(ArrayRef<CXXCtorInitializer*> CtorInits); + void AddCXXCtorInitializers(ArrayRef<CXXCtorInitializer *> CtorInits); void AddCXXDefinitionData(const CXXRecordDecl *D); @@ -955,6 +983,7 @@ public: ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, bool AllowASTWithErrors = false, bool IncludeTimestamps = true); ~PCHGenerator() override; + void InitializeSema(Sema &S) override { SemaPtr = &S; } void HandleTranslationUnit(ASTContext &Ctx) override; ASTMutationListener *GetASTMutationListener() override; @@ -962,6 +991,6 @@ public: bool hasEmittedPCH() const { return Buffer->IsComplete; } }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_SERIALIZATION_ASTWRITER_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h b/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h index 244b01b22aa18..24bfadd0f8677 100644 --- a/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h @@ -1,4 +1,4 @@ -//===--- ContinuousRangeMap.h - Map with int range as key -------*- C++ -*-===// +//===- ContinuousRangeMap.h - Map with int range as key ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,6 +18,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/SmallVector.h" #include <algorithm> +#include <cassert> #include <utility> namespace clang { @@ -35,14 +36,15 @@ namespace clang { template <typename Int, typename V, unsigned InitialCapacity> class ContinuousRangeMap { public: - typedef std::pair<Int, V> value_type; - typedef value_type &reference; - typedef const value_type &const_reference; - typedef value_type *pointer; - typedef const value_type *const_pointer; + using value_type = std::pair<Int, V>; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = value_type *; + using const_pointer = const value_type *; private: - typedef SmallVector<value_type, InitialCapacity> Representation; + using Representation = SmallVector<value_type, InitialCapacity>; + Representation Rep; struct Compare { @@ -52,7 +54,7 @@ private: bool operator ()(Int L, const_reference R) const { return L < R.first; } - bool operator ()(Int L, Int R) const { + bool operator ()(Int L, Int R) const { return L < R; } bool operator ()(const_reference L, const_reference R) const { @@ -80,8 +82,8 @@ public: Rep.insert(I, Val); } - typedef typename Representation::iterator iterator; - typedef typename Representation::const_iterator const_iterator; + using iterator = typename Representation::iterator; + using const_iterator = typename Representation::const_iterator; iterator begin() { return Rep.begin(); } iterator end() { return Rep.end(); } @@ -108,13 +110,12 @@ public: /// from a set of values. class Builder { ContinuousRangeMap &Self; - + + public: + explicit Builder(ContinuousRangeMap &Self) : Self(Self) {} Builder(const Builder&) = delete; Builder &operator=(const Builder&) = delete; - public: - explicit Builder(ContinuousRangeMap &Self) : Self(Self) { } - ~Builder() { std::sort(Self.Rep.begin(), Self.Rep.end(), Compare()); std::unique(Self.Rep.begin(), Self.Rep.end(), @@ -131,9 +132,10 @@ public: Self.Rep.push_back(Val); } }; + friend class Builder; }; -} +} // namespace clang -#endif +#endif // LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h index fae387cac7e21..147a6910aa295 100644 --- a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h +++ b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h @@ -1,4 +1,4 @@ -//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +//===- ModuleManager.cpp - Module Manager -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,15 +15,30 @@ #ifndef LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H #define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H -#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Serialization/Module.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include <cstdint> +#include <ctime> +#include <memory> +#include <string> +#include <utility> -namespace clang { +namespace clang { +class FileEntry; +class FileManager; class GlobalModuleIndex; +class HeaderSearch; class MemoryBufferCache; class ModuleMap; class PCHContainerReader; @@ -58,6 +73,9 @@ class ModuleManager { /// \brief Knows how to unwrap module containers. const PCHContainerReader &PCHContainerRdr; + /// \brief Preprocessor's HeaderSearchInfo containing the module map. + const HeaderSearch &HeaderSearchInfo; + /// \brief A lookup of in-memory (virtual file) buffers llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>> InMemoryBuffers; @@ -79,14 +97,12 @@ class ModuleManager { /// /// The global module index will actually be owned by the ASTReader; this is /// just an non-owning pointer. - GlobalModuleIndex *GlobalIndex; + GlobalModuleIndex *GlobalIndex = nullptr; /// \brief State used by the "visit" operation to avoid malloc traffic in /// calls to visit(). struct VisitState { - explicit VisitState(unsigned N) - : VisitNumber(N, 0), NextVisitNumber(1), NextState(nullptr) - { + explicit VisitState(unsigned N) : VisitNumber(N, 0) { Stack.reserve(N); } @@ -103,46 +119,47 @@ class ModuleManager { SmallVector<unsigned, 4> VisitNumber; /// \brief The next visit number to use to mark visited module files. - unsigned NextVisitNumber; + unsigned NextVisitNumber = 1; /// \brief The next visit state. - VisitState *NextState; + VisitState *NextState = nullptr; }; /// \brief The first visit() state in the chain. - VisitState *FirstVisitState; + VisitState *FirstVisitState = nullptr; VisitState *allocateVisitState(); void returnVisitState(VisitState *State); public: - typedef llvm::pointee_iterator< - SmallVectorImpl<std::unique_ptr<ModuleFile>>::iterator> - ModuleIterator; - typedef llvm::pointee_iterator< - SmallVectorImpl<std::unique_ptr<ModuleFile>>::const_iterator> - ModuleConstIterator; - typedef llvm::pointee_iterator< - SmallVectorImpl<std::unique_ptr<ModuleFile>>::reverse_iterator> - ModuleReverseIterator; - typedef std::pair<uint32_t, StringRef> ModuleOffset; + using ModuleIterator = llvm::pointee_iterator< + SmallVectorImpl<std::unique_ptr<ModuleFile>>::iterator>; + using ModuleConstIterator = llvm::pointee_iterator< + SmallVectorImpl<std::unique_ptr<ModuleFile>>::const_iterator>; + using ModuleReverseIterator = llvm::pointee_iterator< + SmallVectorImpl<std::unique_ptr<ModuleFile>>::reverse_iterator>; + using ModuleOffset = std::pair<uint32_t, StringRef>; explicit ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, - const PCHContainerReader &PCHContainerRdr); + const PCHContainerReader &PCHContainerRdr, + const HeaderSearch &HeaderSearchInfo); ~ModuleManager(); /// \brief Forward iterator to traverse all loaded modules. ModuleIterator begin() { return Chain.begin(); } + /// \brief Forward iterator end-point to traverse all loaded modules ModuleIterator end() { return Chain.end(); } /// \brief Const forward iterator to traverse all loaded modules. ModuleConstIterator begin() const { return Chain.begin(); } + /// \brief Const forward iterator end-point to traverse all loaded modules ModuleConstIterator end() const { return Chain.end(); } /// \brief Reverse iterator to traverse all loaded modules. ModuleReverseIterator rbegin() { return Chain.rbegin(); } + /// \brief Reverse iterator end-point to traverse all loaded modules. ModuleReverseIterator rend() { return Chain.rend(); } @@ -163,8 +180,11 @@ public: /// \brief Returns the module associated with the given index ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; } - /// \brief Returns the module associated with the given name - ModuleFile *lookup(StringRef Name) const; + /// \brief Returns the module associated with the given file name. + ModuleFile *lookupByFileName(StringRef FileName) const; + + /// \brief Returns the module associated with the given module name. + ModuleFile *lookupByModuleName(StringRef ModName) const; /// \brief Returns the module associated with the given module file. ModuleFile *lookup(const FileEntry *File) const; @@ -179,15 +199,18 @@ public: enum AddModuleResult { /// \brief The module file had already been loaded. AlreadyLoaded, + /// \brief The module file was just loaded in response to this call. NewlyLoaded, + /// \brief The module file is missing. Missing, + /// \brief The module file is out-of-date. OutOfDate }; - typedef ASTFileSignature(*ASTFileSignatureReader)(StringRef); + using ASTFileSignatureReader = ASTFileSignature (*)(StringRef); /// \brief Attempts to create a new module and add it to the list of known /// modules. @@ -298,6 +321,8 @@ public: MemoryBufferCache &getPCMCache() const { return *PCMCache; } }; -} } // end namespace clang::serialization +} // namespace serialization + +} // namespace clang -#endif +#endif // LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 82ab720af8dc7..e510e84e938af 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -132,6 +132,10 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">, HelpText<"Generate dynamic type information">, DescFile<"DynamicTypePropagation.cpp">; +def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">, + HelpText<"Assume that const string-like globals are non-null">, + DescFile<"NonilStringConstantsChecker.cpp">; + } // end "core" let ParentPackage = CoreAlpha in { @@ -184,6 +188,10 @@ def DynamicTypeChecker : Checker<"DynamicTypeChecker">, HelpText<"Check for cases where the dynamic and the static type of an object are unrelated.">, DescFile<"DynamicTypeChecker.cpp">; +def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">, + HelpText<"Check that addresses to stack memory do not escape the function">, + DescFile<"StackAddrEscapeChecker.cpp">; + } // end "alpha.core" let ParentPackage = Nullability in { @@ -284,6 +292,11 @@ def VirtualCallChecker : Checker<"VirtualCall">, let ParentPackage = CplusplusAlpha in { +def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">, + HelpText<"Reports destructions of polymorphic objects with a non-virtual " + "destructor in their base class">, + DescFile<"DeleteWithNonVirtualDtorChecker.cpp">; + def IteratorRangeChecker : Checker<"IteratorRange">, HelpText<"Check for iterators used outside their valid ranges">, DescFile<"IteratorChecker.cpp">; @@ -740,10 +753,6 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">, HelpText<"View Exploded Graphs using GraphViz">, DescFile<"DebugCheckers.cpp">; -def BugHashDumper : Checker<"DumpBugHash">, - HelpText<"Dump the bug hash for all statements.">, - DescFile<"DebugCheckers.cpp">; - } // end "debug" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h index 25886545e2f7b..e5e857e970297 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h @@ -145,9 +145,11 @@ public: /// Indicates that the tracked object is an Objective-C object. ObjC, /// Indicates that the tracked object could be a CF or Objective-C object. - AnyObj + AnyObj, + /// Indicates that the tracked object is a generalized object. + Generalized }; - + private: Kind K; ObjKind O; diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def index 04bf41bfde4f0..281a2ac3a66fe 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def @@ -28,9 +28,10 @@ ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3Con #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 5dd6bdf384968..ce50cc582d1e0 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -214,6 +214,9 @@ private: /// \sa IncludeLifetimeInCFG Optional<bool> IncludeLifetimeInCFG; + /// \sa IncludeLoopExitInCFG + Optional<bool> IncludeLoopExitInCFG; + /// \sa mayInlineCXXStandardLibrary Optional<bool> InlineCXXStandardLibrary; @@ -275,6 +278,9 @@ private: /// \sa shouldWidenLoops Optional<bool> WidenLoops; + /// \sa shouldUnrollLoops + Optional<bool> UnrollLoops; + /// \sa shouldDisplayNotesAsEvents Optional<bool> DisplayNotesAsEvents; @@ -415,6 +421,13 @@ public: /// the values "true" and "false". bool includeLifetimeInCFG(); + /// Returns whether or not the end of the loop information should be included + /// in the CFG. + /// + /// This is controlled by the 'cfg-loopexit' config option, which accepts + /// the values "true" and "false". + bool includeLoopExitInCFG(); + /// Returns whether or not C++ standard library functions may be considered /// for inlining. /// @@ -560,6 +573,10 @@ public: /// This is controlled by the 'widen-loops' config option. bool shouldWidenLoops(); + /// Returns true if the analysis should try to unroll loops with known bounds. + /// This is controlled by the 'unroll-loops' config option. + bool shouldUnrollLoops(); + /// Returns true if the bug reporter should transparently treat extra note /// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic /// consumer doesn't support the extra note pieces. diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 0f1eb096c4958..cd1355d03b639 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -17,7 +17,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h index b72bce5fc9f82..2043896fd26fe 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -1,4 +1,4 @@ -//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===// +//===--- BugReporterVisitors.h - Generate PathDiagnostics -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H -#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/FoldingSet.h" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 3e0913ec4eeaa..15b930bc3f1eb 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index fa7ee62ab704d..9fec217aca725 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -19,7 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -436,20 +436,7 @@ public: return cast<FunctionDecl>(CallEvent::getDecl()); } - RuntimeDefinition getRuntimeDefinition() const override { - const FunctionDecl *FD = getDecl(); - // Note that the AnalysisDeclContext will have the FunctionDecl with - // the definition (if one exists). - if (FD) { - AnalysisDeclContext *AD = - getLocationContext()->getAnalysisDeclContext()-> - getManager()->getContext(FD); - if (AD->getBody()) - return RuntimeDefinition(AD->getDecl()); - } - - return RuntimeDefinition(); - } + RuntimeDefinition getRuntimeDefinition() const override; bool argumentsMayEscape() const override; diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index e380982d43ea7..78d38a3d598dc 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -196,6 +196,13 @@ public: return getState()->getSVal(S, getLocationContext()); } + /// \brief Returns true if the value of \p E is greater than or equal to \p + /// Val under unsigned comparison + bool isGreaterOrEqual(const Expr *E, unsigned long long Val); + + /// Returns true if the value of \p E is negative. + bool isNegative(const Expr *E); + /// \brief Generates a new transition in the program state graph /// (ExplodedGraph). Uses the default CheckerContext predecessor node. /// diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 12ec5b6c64a4d..7472a7147fca6 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index a66e1a1aed016..c63ed4a013aa6 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ImmutableMap.h" diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index a710ae68be604..dcea5e461d27c 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -20,14 +20,14 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H #include "clang/AST/Decl.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include <memory> @@ -404,7 +404,7 @@ private: }; class ExplodedNodeSet { - typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; + typedef llvm::SmallSetVector<ExplodedNode*, 4> ImplTy; ImplTy Impl; public: @@ -424,7 +424,7 @@ public: unsigned size() const { return Impl.size(); } bool empty() const { return Impl.empty(); } - bool erase(ExplodedNode *N) { return Impl.erase(N); } + bool erase(ExplodedNode *N) { return Impl.remove(N); } void clear() { Impl.clear(); } void insert(const ExplodedNodeSet &S) { diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 067d706108689..712cd6361e118 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -196,6 +196,8 @@ public: void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred); + void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); @@ -330,9 +332,9 @@ public: void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex, - ExplodedNode *Pred, - ExplodedNodeSet &Dst); + void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); /// VisitGCCAsmStmt - Transfer function logic for inline asm. void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h new file mode 100644 index 0000000000000..a4c505ce5f237 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h @@ -0,0 +1,50 @@ +//===--- LoopUnrolling.h - Unroll loops -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This header contains the declarations of functions which are used to decide +/// which loops should be completely unrolled and mark their corresponding +/// CFGBlocks. It is done by tracking a stack of loops in the ProgramState. This +/// way specific loops can be marked as completely unrolled. For considering a +/// loop to be completely unrolled it has to fulfill the following requirements: +/// - Currently only forStmts can be considered. +/// - The bound has to be known. +/// - The counter variable has not escaped before/in the body of the loop and +/// changed only in the increment statement corresponding to the loop. It also +/// has to be initialized by a literal in the corresponding initStmt. +/// - Does not contain goto, switch and returnStmt. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H + +#include "clang/Analysis/CFG.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +namespace clang { +namespace ento { +class AnalysisManager; + +/// Returns if the given State indicates that is inside a completely unrolled +/// loop. +bool isUnrolledState(ProgramStateRef State); + +/// Updates the stack of loops contained by the ProgramState. +ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx, + ExplodedNode* Pred, unsigned maxVisitOnPath); + +/// Updates the given ProgramState. In current implementation it removes the top +/// element of the stack of loops. +ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 29b1c4cdca04e..8ab6656230888 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -21,7 +21,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/FoldingSet.h" @@ -1412,21 +1412,18 @@ public: bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const; bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const; }; - -} // end GR namespace - -} // end clang namespace //===----------------------------------------------------------------------===// // Pretty-printing regions. //===----------------------------------------------------------------------===// - -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::MemRegion* R) { +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::MemRegion *R) { R->dumpToStream(os); return os; } -} // end llvm namespace + +} // namespace ento + +} // namespace clang #endif diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index e3a2164b11ff0..dd2564b0a3c3e 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -308,8 +308,12 @@ public: /// \brief Return the value bound to the specified location. /// Returns UnknownVal() if none found. - SVal getSVal(const MemRegion* R) const; + SVal getSVal(const MemRegion* R, QualType T = QualType()) const; + /// \brief Return the value bound to the specified location, assuming + /// that the value is a scalar integer or an enumeration or a pointer. + /// Returns UnknownVal() if none found or the region is not known to hold + /// a value of such type. SVal getSValAsScalarOrLoc(const MemRegion *R) const; /// \brief Visits the symbols reachable from the given SVal using the provided @@ -758,9 +762,10 @@ inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const { return getStateManager().StoreMgr->getBinding(getStore(), LV, T); } -inline SVal ProgramState::getSVal(const MemRegion* R) const { +inline SVal ProgramState::getSVal(const MemRegion* R, QualType T) const { return getStateManager().StoreMgr->getBinding(getStore(), - loc::MemRegionVal(R)); + loc::MemRegionVal(R), + T); } inline BasicValueFactory &ProgramState::getBasicVals() const { diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 935f0018324a2..06132587b4aaf 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -103,9 +103,6 @@ public: return *static_cast<const T *>(this); } - /// BufferTy - A temporary buffer to hold a set of SVals. - typedef SmallVector<SVal,5> BufferTy; - inline unsigned getRawKind() const { return Kind; } inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } @@ -198,6 +195,10 @@ public: } }; +inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) { + V.dumpToStream(os); + return os; +} class UndefinedVal : public SVal { public: @@ -622,11 +623,6 @@ private: } // end clang namespace namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - clang::ento::SVal V) { - V.dumpToStream(os); - return os; -} template <typename T> struct isPodLike; template <> struct isPodLike<clang::ento::SVal> { diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 7619f22f40139..25d20a17afaa7 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -51,7 +51,7 @@ public: virtual ~StoreManager() {} /// Return the value bound to specified location in a given state. - /// \param[in] store The analysis state. + /// \param[in] store The store in which to make the lookup. /// \param[in] loc The symbolic memory location. /// \param[in] T An optional type that provides a hint indicating the /// expected type of the returned value. This is used if the value is @@ -83,12 +83,12 @@ public: return getDefaultBinding(lcv.getStore(), lcv.getRegion()); } - /// Return a state with the specified value bound to the given location. - /// \param[in] store The analysis state. + /// Return a store with the specified value bound to the given location. + /// \param[in] store The store in which to make the binding. /// \param[in] loc The symbolic memory location. /// \param[in] val The value to bind to location \c loc. - /// \return A pointer to a ProgramState object that contains the same - /// bindings as \c state with the addition of having the value specified + /// \return A StoreRef object that contains the same + /// bindings as \c store with the addition of having the value specified /// by \c val bound to the location given for \c loc. virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h index f72033955ec31..9780d0144746e 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h @@ -98,6 +98,12 @@ public: virtual const MemRegion *getOriginRegion() const { return nullptr; } }; +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} + typedef const SymExpr *SymbolRef; typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index e9701142cd9e2..7d2e5ad8ba915 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -17,7 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" @@ -633,11 +633,4 @@ public: } // end clang namespace -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::SymExpr *SE) { - SE->dumpToStream(os); - return os; -} -} // end llvm namespace #endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiff.h b/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiff.h new file mode 100644 index 0000000000000..dd11c91ac0dde --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiff.h @@ -0,0 +1,127 @@ +//===- ASTDiff.h - AST differencing API -----------------------*- C++ -*- -===// +// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file specifies an interface that can be used to compare C++ syntax +// trees. +// +// We use the gumtree algorithm which combines a heuristic top-down search that +// is able to match large subtrees that are equivalent, with an optimal +// algorithm to match small subtrees. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H +#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H + +#include "clang/Tooling/ASTDiff/ASTDiffInternal.h" + +namespace clang { +namespace diff { + +enum ChangeKind { + None, + Delete, // (Src): delete node Src. + Update, // (Src, Dst): update the value of node Src to match Dst. + Insert, // (Src, Dst, Pos): insert Src as child of Dst at offset Pos. + Move, // (Src, Dst, Pos): move Src to be a child of Dst at offset Pos. + UpdateMove // Same as Move plus Update. +}; + +/// Represents a Clang AST node, alongside some additional information. +struct Node { + NodeId Parent, LeftMostDescendant, RightMostDescendant; + int Depth, Height, Shift = 0; + ast_type_traits::DynTypedNode ASTNode; + SmallVector<NodeId, 4> Children; + ChangeKind Change = None; + + ast_type_traits::ASTNodeKind getType() const; + StringRef getTypeLabel() const; + bool isLeaf() const { return Children.empty(); } + llvm::Optional<StringRef> getIdentifier() const; + llvm::Optional<std::string> getQualifiedIdentifier() const; +}; + +class ASTDiff { +public: + ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options); + ~ASTDiff(); + + // Returns the ID of the node that is mapped to the given node in SourceTree. + NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const; + + class Impl; + +private: + std::unique_ptr<Impl> DiffImpl; +}; + +/// SyntaxTree objects represent subtrees of the AST. +/// They can be constructed from any Decl or Stmt. +class SyntaxTree { +public: + /// Constructs a tree from a translation unit. + SyntaxTree(ASTContext &AST); + /// Constructs a tree from any AST node. + template <class T> + SyntaxTree(T *Node, ASTContext &AST) + : TreeImpl(llvm::make_unique<Impl>(this, Node, AST)) {} + SyntaxTree(SyntaxTree &&Other) = default; + ~SyntaxTree(); + + const ASTContext &getASTContext() const; + StringRef getFilename() const; + + int getSize() const; + NodeId getRootId() const; + using PreorderIterator = NodeId; + PreorderIterator begin() const; + PreorderIterator end() const; + + const Node &getNode(NodeId Id) const; + int findPositionInParent(NodeId Id) const; + + // Returns the starting and ending offset of the node in its source file. + std::pair<unsigned, unsigned> getSourceRangeOffsets(const Node &N) const; + + /// Serialize the node attributes to a string representation. This should + /// uniquely distinguish nodes of the same kind. Note that this function just + /// returns a representation of the node value, not considering descendants. + std::string getNodeValue(NodeId Id) const; + std::string getNodeValue(const Node &Node) const; + + class Impl; + std::unique_ptr<Impl> TreeImpl; +}; + +struct ComparisonOptions { + /// During top-down matching, only consider nodes of at least this height. + int MinHeight = 2; + + /// During bottom-up matching, match only nodes with at least this value as + /// the ratio of their common descendants. + double MinSimilarity = 0.5; + + /// Whenever two subtrees are matched in the bottom-up phase, the optimal + /// mapping is computed, unless the size of either subtrees exceeds this. + int MaxSize = 100; + + bool StopAfterTopDown = false; + + /// Returns false if the nodes should never be matched. + bool isMatchingAllowed(const Node &N1, const Node &N2) const { + return N1.getType().isSame(N2.getType()); + } +}; + +} // end namespace diff +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiffInternal.h b/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiffInternal.h new file mode 100644 index 0000000000000..a76ad37336a68 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/ASTDiff/ASTDiffInternal.h @@ -0,0 +1,48 @@ +//===- ASTDiffInternal.h --------------------------------------*- C++ -*- -===// +// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H +#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H + +#include "clang/AST/ASTTypeTraits.h" + +namespace clang { +namespace diff { + +using DynTypedNode = ast_type_traits::DynTypedNode; + +class SyntaxTree; +class SyntaxTreeImpl; +struct ComparisonOptions; + +/// Within a tree, this identifies a node by its preorder offset. +struct NodeId { +private: + static constexpr int InvalidNodeId = -1; + +public: + int Id; + + NodeId() : Id(InvalidNodeId) {} + NodeId(int Id) : Id(Id) {} + + operator int() const { return Id; } + NodeId &operator++() { return ++Id, *this; } + NodeId &operator--() { return --Id, *this; } + // Support defining iterators on NodeId. + NodeId &operator*() { return *this; } + + bool isValid() const { return Id != InvalidNodeId; } + bool isInvalid() const { return Id == InvalidNodeId; } +}; + +} // end namespace diff +} // end namespace clang +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h b/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h index 3d630c5f7609c..15e8161dd76fb 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/CommonOptionsParser.h @@ -27,8 +27,10 @@ #ifndef LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H #define LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H +#include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" namespace clang { namespace tooling { @@ -84,14 +86,19 @@ public: /// /// All options not belonging to \p Category become hidden. /// - /// I also allows calls to set the required number of positional parameters. - /// - /// This constructor exits program in case of error. + /// It also allows calls to set the required number of positional parameters. CommonOptionsParser(int &argc, const char **argv, llvm::cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview = nullptr); + /// \brief A factory method that is similar to the above constructor, except + /// this returns an error instead exiting the program on error. + static llvm::Expected<CommonOptionsParser> + create(int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview = nullptr); + /// Returns a reference to the loaded compilations database. CompilationDatabase &getCompilations() { return *Compilations; @@ -102,13 +109,46 @@ public: return SourcePathList; } + /// Returns the argument adjuster calculated from "--extra-arg" and + //"--extra-arg-before" options. + ArgumentsAdjuster getArgumentsAdjuster() { return Adjuster; } + static const char *const HelpMessage; private: + CommonOptionsParser() = default; + + llvm::Error init(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview); + std::unique_ptr<CompilationDatabase> Compilations; std::vector<std::string> SourcePathList; - std::vector<std::string> ExtraArgsBefore; - std::vector<std::string> ExtraArgsAfter; + ArgumentsAdjuster Adjuster; +}; + +class ArgumentsAdjustingCompilations : public CompilationDatabase { +public: + ArgumentsAdjustingCompilations( + std::unique_ptr<CompilationDatabase> Compilations) + : Compilations(std::move(Compilations)) {} + + void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster); + + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override; + + std::vector<std::string> getAllFiles() const override; + + std::vector<CompileCommand> getAllCompileCommands() const override; + +private: + std::unique_ptr<CompilationDatabase> Compilations; + std::vector<ArgumentsAdjuster> Adjusters; + + std::vector<CompileCommand> + adjustCommands(std::vector<CompileCommand> Commands) const; }; } // namespace tooling diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h index e988b84b6eaea..bc3e67b77de25 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h @@ -64,10 +64,12 @@ struct CompileCommand { /// \brief Interface for compilation databases. /// -/// A compilation database allows the user to retrieve all compile command lines -/// that a specified file is compiled with in a project. -/// The retrieved compile command lines can be used to run clang tools over -/// a subset of the files in a project. +/// A compilation database allows the user to retrieve compile command lines +/// for the files in a project. +/// +/// Many implementations are enumerable, allowing all command lines to be +/// retrieved. These can be used to run clang tools over a subset of the files +/// in a project. class CompilationDatabase { public: virtual ~CompilationDatabase(); @@ -104,7 +106,7 @@ public: /// \brief Returns all compile commands in which the specified file was /// compiled. /// - /// This includes compile comamnds that span multiple source files. + /// This includes compile commands that span multiple source files. /// For example, consider a project with the following compilations: /// $ clang++ -o test a.cc b.cc t.cc /// $ clang++ -o production a.cc b.cc -DPRODUCTION @@ -114,7 +116,10 @@ public: StringRef FilePath) const = 0; /// \brief Returns the list of all files available in the compilation database. - virtual std::vector<std::string> getAllFiles() const = 0; + /// + /// By default, returns nothing. Implementations should override this if they + /// can enumerate their source files. + virtual std::vector<std::string> getAllFiles() const { return {}; } /// \brief Returns all compile commands for all the files in the compilation /// database. @@ -122,7 +127,10 @@ public: /// FIXME: Add a layer in Tooling that provides an interface to run a tool /// over all files in a compilation database. Not all build systems have the /// ability to provide a feasible implementation for \c getAllCompileCommands. - virtual std::vector<CompileCommand> getAllCompileCommands() const = 0; + /// + /// By default, this is implemented in terms of getAllFiles() and + /// getCompileCommands(). Subclasses may override this for efficiency. + virtual std::vector<CompileCommand> getAllCompileCommands() const; }; /// \brief Interface for compilation database plugins. @@ -149,6 +157,7 @@ public: /// \brief A compilation database that returns a single compile command line. /// /// Useful when we want a tool to behave more like a compiler invocation. +/// This compilation database is not enumerable: getAllFiles() returns {}. class FixedCompilationDatabase : public CompilationDatabase { public: /// \brief Creates a FixedCompilationDatabase from the arguments after "--". @@ -182,6 +191,11 @@ public: int &Argc, const char *const *Argv, std::string &ErrorMsg, Twine Directory = "."); + /// Reads flags from the given file, one-per line. + /// Returns nullptr and sets ErrorMessage if we can't read the file. + static std::unique_ptr<FixedCompilationDatabase> + loadFromFile(StringRef Path, std::string &ErrorMsg); + /// \brief Constructs a compilation data base from a specified directory /// and command line. FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine); @@ -194,17 +208,6 @@ public: std::vector<CompileCommand> getCompileCommands(StringRef FilePath) const override; - /// \brief Returns the list of all files available in the compilation database. - /// - /// Note: This is always an empty list for the fixed compilation database. - std::vector<std::string> getAllFiles() const override; - - /// \brief Returns all compile commands for all the files in the compilation - /// database. - /// - /// Note: This is always an empty list for the fixed compilation database. - std::vector<CompileCommand> getAllCompileCommands() const override; - private: /// This is built up to contain a single entry vector to be returned from /// getCompileCommands after adding the positional argument. diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h index 8d4a22adf3680..3fea9aee604ca 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Replacement.h @@ -255,7 +255,7 @@ class Replacements { /// \brief Merges \p Replaces into the current replacements. \p Replaces /// refers to code after applying the current replacements. - Replacements merge(const Replacements &Replaces) const; + LLVM_NODISCARD Replacements merge(const Replacements &Replaces) const; // Returns the affected ranges in the changed code. std::vector<Range> getAffectedRanges() const; diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Execution.h b/contrib/llvm/tools/clang/include/clang/Tooling/Execution.h new file mode 100644 index 0000000000000..1a44c4788c492 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Execution.h @@ -0,0 +1,175 @@ +//===--- Execution.h - Executing clang frontend actions -*- 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 framework for executing clang frontend actions. +// +// The framework can be extended to support different execution plans including +// standalone execution on the given TUs or parallel execution on all TUs in +// the codebase. +// +// In order to enable multiprocessing execution, tool actions are expected to +// output result into the ToolResults provided by the executor. The +// `ToolResults` is an interface that abstracts how results are stored e.g. +// in-memory for standalone execution or on-disk for large-scale execution. +// +// New executors can be registered as ToolExecutorPlugins via the +// `ToolExecutorPluginRegistry`. CLI tools can use +// `createExecutorFromCommandLineArgs` to create a specific registered executor +// according to the command-line arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_EXECUTION_H +#define LLVM_CLANG_TOOLING_EXECUTION_H + +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +/// \brief An abstraction for the result of a tool execution. For example, the +/// underlying result can be in-memory or on-disk. +/// +/// Results should be string key-value pairs. For example, a refactoring tool +/// can use source location as key and a replacement in YAML format as value. +class ToolResults { +public: + virtual ~ToolResults() = default; + virtual void addResult(StringRef Key, StringRef Value) = 0; + virtual std::vector<std::pair<std::string, std::string>> AllKVResults() = 0; + virtual void forEachResult( + llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) = 0; +}; + +class InMemoryToolResults : public ToolResults { +public: + void addResult(StringRef Key, StringRef Value) override; + std::vector<std::pair<std::string, std::string>> AllKVResults() override; + void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)> + Callback) override; + +private: + std::vector<std::pair<std::string, std::string>> KVResults; +}; + +/// \brief The context of an execution, including the information about +/// compilation and results. +class ExecutionContext { +public: + virtual ~ExecutionContext() {} + + /// \brief Initializes a context. This does not take ownership of `Results`. + explicit ExecutionContext(ToolResults *Results) : Results(Results) {} + + /// \brief Adds a KV pair to the result container of this execution. + void reportResult(StringRef Key, StringRef Value); + + // Returns the source control system's revision number if applicable. + // Otherwise returns an empty string. + virtual std::string getRevision() { return ""; } + + // Returns the corpus being analyzed, e.g. "llvm" for the LLVM codebase, if + // applicable. + virtual std::string getCorpus() { return ""; } + + // Returns the currently processed compilation unit if available. + virtual std::string getCurrentCompilationUnit() { return ""; } + +private: + ToolResults *Results; +}; + +/// \brief Interface for executing clang frontend actions. +/// +/// This can be extended to support running tool actions in different +/// execution mode, e.g. on a specific set of TUs or many TUs in parallel. +/// +/// New executors can be registered as ToolExecutorPlugins via the +/// `ToolExecutorPluginRegistry`. CLI tools can use +/// `createExecutorFromCommandLineArgs` to create a specific registered +/// executor according to the command-line arguments. +class ToolExecutor { +public: + virtual ~ToolExecutor() {} + + /// \brief Returns the name of a specific executor. + virtual StringRef getExecutorName() const = 0; + + /// \brief Executes each action with a corresponding arguments adjuster. + virtual llvm::Error + execute(llvm::ArrayRef< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions) = 0; + + /// \brief Convenient functions for the above `execute`. + llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action); + /// Executes an action with an argument adjuster. + llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action, + ArgumentsAdjuster Adjuster); + + /// \brief Returns a reference to the execution context. + /// + /// This should be passed to tool callbacks, and tool callbacks should report + /// results via the returned context. + virtual ExecutionContext *getExecutionContext() = 0; + + /// \brief Returns a reference to the result container. + /// + /// NOTE: This should only be used after the execution finishes. Tool + /// callbacks should report results via `ExecutionContext` instead. + virtual ToolResults *getToolResults() = 0; + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A buffer of the file's content. + virtual void mapVirtualFile(StringRef FilePath, StringRef Content) = 0; +}; + +/// \brief Interface for factories that create specific executors. This is also +/// used as a plugin to be registered into ToolExecutorPluginRegistry. +class ToolExecutorPlugin { +public: + virtual ~ToolExecutorPlugin() {} + + /// \brief Create an `ToolExecutor`. + /// + /// `OptionsParser` can be consumed (e.g. moved) if the creation succeeds. + virtual llvm::Expected<std::unique_ptr<ToolExecutor>> + create(CommonOptionsParser &OptionsParser) = 0; +}; + +/// \brief This creates a ToolExecutor that is in the global registry based on +/// commandline arguments. +/// +/// This picks the right executor based on the `--executor` option. This parses +/// the commandline arguments with `CommonOptionsParser`, so caller does not +/// need to parse again. +/// +/// By default, this creates a `StandaloneToolExecutor` ("standalone") if +/// `--executor` is not provided. +llvm::Expected<std::unique_ptr<ToolExecutor>> +createExecutorFromCommandLineArgs(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview = nullptr); + +namespace internal { +llvm::Expected<std::unique_ptr<ToolExecutor>> +createExecutorFromCommandLineArgsImpl(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview = nullptr); +} // end namespace internal + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_EXECUTION_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/ASTSelection.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/ASTSelection.h new file mode 100644 index 0000000000000..aa02a6899e8fc --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/ASTSelection.h @@ -0,0 +1,155 @@ +//===--- ASTSelection.h - Clang refactoring library -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include <vector> + +namespace clang { + +class ASTContext; + +namespace tooling { + +enum class SourceSelectionKind { + /// A node that's not selected. + None, + + /// A node that's considered to be selected because the whole selection range + /// is inside of its source range. + ContainsSelection, + /// A node that's considered to be selected because the start of the selection + /// range is inside its source range. + ContainsSelectionStart, + /// A node that's considered to be selected because the end of the selection + /// range is inside its source range. + ContainsSelectionEnd, + + /// A node that's considered to be selected because the node is entirely in + /// the selection range. + InsideSelection, +}; + +/// Represents a selected AST node. +/// +/// AST selection is represented using a tree of \c SelectedASTNode. The tree +/// follows the top-down shape of the actual AST. Each selected node has +/// a selection kind. The kind might be none as the node itself might not +/// actually be selected, e.g. a statement in macro whose child is in a macro +/// argument. +struct SelectedASTNode { + ast_type_traits::DynTypedNode Node; + SourceSelectionKind SelectionKind; + std::vector<SelectedASTNode> Children; + + SelectedASTNode(const ast_type_traits::DynTypedNode &Node, + SourceSelectionKind SelectionKind) + : Node(Node), SelectionKind(SelectionKind) {} + SelectedASTNode(SelectedASTNode &&) = default; + SelectedASTNode &operator=(SelectedASTNode &&) = default; + + void dump(llvm::raw_ostream &OS = llvm::errs()) const; + + using ReferenceType = std::reference_wrapper<const SelectedASTNode>; +}; + +/// Traverses the given ASTContext and creates a tree of selected AST nodes. +/// +/// \returns None if no nodes are selected in the AST, or a selected AST node +/// that corresponds to the TranslationUnitDecl otherwise. +Optional<SelectedASTNode> findSelectedASTNodes(const ASTContext &Context, + SourceRange SelectionRange); + +/// An AST selection value that corresponds to a selection of a set of +/// statements that belong to one body of code (like one function). +/// +/// For example, the following selection in the source. +/// +/// \code +/// void function() { +/// // selection begin: +/// int x = 0; +/// { +/// // selection end +/// x = 1; +/// } +/// x = 2; +/// } +/// \endcode +/// +/// Would correspond to a code range selection of statements "int x = 0" +/// and the entire compound statement that follows it. +/// +/// A \c CodeRangeASTSelection value stores references to the full +/// \c SelectedASTNode tree and should not outlive it. +class CodeRangeASTSelection { +public: + CodeRangeASTSelection(CodeRangeASTSelection &&) = default; + CodeRangeASTSelection &operator=(CodeRangeASTSelection &&) = default; + + /// Returns the parent hierarchy (top to bottom) for the selected nodes. + ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; } + + /// Returns the number of selected statements. + size_t size() const { + if (!AreChildrenSelected) + return 1; + return SelectedNode.get().Children.size(); + } + + const Stmt *operator[](size_t I) const { + if (!AreChildrenSelected) { + assert(I == 0 && "Invalid index"); + return SelectedNode.get().Node.get<Stmt>(); + } + return SelectedNode.get().Children[I].Node.get<Stmt>(); + } + + /// Returns true when a selected code range is in a function-like body + /// of code, like a function, method or a block. + /// + /// This function can be used to test against selected expressions that are + /// located outside of a function, e.g. global variable initializers, default + /// argument values, or even template arguments. + /// + /// Use the \c getFunctionLikeNearestParent to get the function-like parent + /// declaration. + bool isInFunctionLikeBodyOfCode() const; + + /// Returns the nearest function-like parent declaration or null if such + /// declaration doesn't exist. + const Decl *getFunctionLikeNearestParent() const; + + static Optional<CodeRangeASTSelection> + create(SourceRange SelectionRange, const SelectedASTNode &ASTSelection); + +private: + CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode, + ArrayRef<SelectedASTNode::ReferenceType> Parents, + bool AreChildrenSelected) + : SelectedNode(SelectedNode), Parents(Parents.begin(), Parents.end()), + AreChildrenSelected(AreChildrenSelected) {} + + /// The reference to the selected node (or reference to the selected + /// child nodes). + SelectedASTNode::ReferenceType SelectedNode; + /// The parent hierarchy (top to bottom) for the selected noe. + llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents; + /// True only when the children of the selected node are actually selected. + bool AreChildrenSelected; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h index 9cccd78677b15..8a468a6de84ef 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H #include "clang/Basic/SourceManager.h" +#include "clang/Format/Format.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -45,6 +46,14 @@ public: AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key) : Key(Key), FilePath(FilePath) {} + AtomicChange(AtomicChange &&) = default; + AtomicChange(const AtomicChange &) = default; + + AtomicChange &operator=(AtomicChange &&) = default; + AtomicChange &operator=(const AtomicChange &) = default; + + bool operator==(const AtomicChange &Other) const; + /// \brief Returns the atomic change as a YAML string. std::string toYAMLString(); @@ -129,6 +138,41 @@ private: tooling::Replacements Replaces; }; +using AtomicChanges = std::vector<AtomicChange>; + +// Defines specs for applying changes. +struct ApplyChangesSpec { + // If true, cleans up redundant/erroneous code around changed code with + // clang-format's cleanup functionality, e.g. redundant commas around deleted + // parameter or empty namespaces introduced by deletions. + bool Cleanup = true; + + format::FormatStyle Style = format::getNoStyle(); + + // Options for selectively formatting changes with clang-format: + // kAll: Format all changed lines. + // kNone: Don't format anything. + // kViolations: Format lines exceeding the `ColumnLimit` in `Style`. + enum FormatOption { kAll, kNone, kViolations }; + + FormatOption Format = kNone; +}; + +/// \brief Applies all AtomicChanges in \p Changes to the \p Code. +/// +/// This completely ignores the file path in each change and replaces them with +/// \p FilePath, i.e. callers are responsible for ensuring all changes are for +/// the same file. +/// +/// \returns The changed code if all changes are applied successfully; +/// otherwise, an llvm::Error carrying llvm::StringError is returned (the Error +/// message can be converted to string with `llvm::toString()` and the +/// error_code should be ignored). +llvm::Expected<std::string> +applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code, + llvm::ArrayRef<AtomicChange> Changes, + const ApplyChangesSpec &Spec); + } // end namespace tooling } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Extract/Extract.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Extract/Extract.h new file mode 100644 index 0000000000000..2fd76d252c62b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Extract/Extract.h @@ -0,0 +1,53 @@ +//===--- Extract.h - Clang refactoring library ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H +#define LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H + +#include "clang/Tooling/Refactoring/ASTSelection.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" + +namespace clang { +namespace tooling { + +/// An "Extract Function" refactoring moves code into a new function that's +/// then called from the place where the original code was. +class ExtractFunction final : public SourceChangeRefactoringRule { +public: + /// Initiates the extract function refactoring operation. + /// + /// \param Code The selected set of statements. + /// \param DeclName The name name of the extract function. If None, + /// "extracted" is used. + static Expected<ExtractFunction> initiate(RefactoringRuleContext &Context, + CodeRangeASTSelection Code, + Optional<std::string> DeclName); + + static const RefactoringDescriptor &describe(); + +private: + ExtractFunction(CodeRangeASTSelection Code, Optional<std::string> DeclName) + : Code(std::move(Code)), + DeclName(DeclName ? std::move(*DeclName) : "extracted") {} + + Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) override; + + CodeRangeASTSelection Code; + + // FIXME: Account for naming collisions: + // - error when name is specified by user. + // - rename to "extractedN" when name is implicit. + std::string DeclName; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h index 8b01a61256f6b..d96ad78ad8768 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h @@ -70,6 +70,18 @@ public: return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc()); } + bool VisitOffsetOfExpr(const OffsetOfExpr *S) { + for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) { + const OffsetOfNode &Component = S->getComponent(I); + if (Component.getKind() == OffsetOfNode::Field) { + if (!visit(Component.getField(), Component.getLocEnd())) + return false; + } + // FIXME: Try to resolve dependent field references. + } + return true; + } + // Other visitors: bool VisitTypeLoc(const TypeLoc Loc) { diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringAction.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringAction.h new file mode 100644 index 0000000000000..c4080237f1c35 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringAction.h @@ -0,0 +1,64 @@ +//===--- RefactoringAction.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" +#include <vector> + +namespace clang { +namespace tooling { + +/// A refactoring action is a class that defines a set of related refactoring +/// action rules. These rules get grouped under a common umbrella - a single +/// clang-refactor subcommand. +/// +/// A subclass of \c RefactoringAction is responsible for creating the set of +/// grouped refactoring action rules that represent one refactoring operation. +/// Although the rules in one action may have a number of different +/// implementations, they should strive to produce a similar result. It should +/// be easy for users to identify which refactoring action produced the result +/// regardless of which refactoring action rule was used. +/// +/// The distinction between actions and rules enables the creation of action +/// that uses very different rules, for example: +/// - local vs global: a refactoring operation like +/// "add missing switch cases" can be applied to one switch when it's +/// selected in an editor, or to all switches in a project when an enum +/// constant is added to an enum. +/// - tool vs editor: some refactoring operation can be initiated in the +/// editor when a declaration is selected, or in a tool when the name of +/// the declaration is passed using a command-line argument. +class RefactoringAction { +public: + virtual ~RefactoringAction() {} + + /// Returns the name of the subcommand that's used by clang-refactor for this + /// action. + virtual StringRef getCommand() const = 0; + + virtual StringRef getDescription() const = 0; + + RefactoringActionRules createActiveActionRules(); + +protected: + /// Returns a set of refactoring actions rules that are defined by this + /// action. + virtual RefactoringActionRules createActionRules() const = 0; +}; + +/// Returns the list of all the available refactoring actions. +std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions(); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h new file mode 100644 index 0000000000000..4130e29d8dea5 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h @@ -0,0 +1,74 @@ +//===--- RefactoringActionRule.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { +namespace tooling { + +class RefactoringOptionVisitor; +class RefactoringResultConsumer; +class RefactoringRuleContext; + +struct RefactoringDescriptor { + /// A unique identifier for the specific refactoring. + StringRef Name; + /// A human readable title for the refactoring. + StringRef Title; + /// A human readable description of what the refactoring does. + StringRef Description; +}; + +/// A common refactoring action rule interface that defines the 'invoke' +/// function that performs the refactoring operation (either fully or +/// partially). +class RefactoringActionRuleBase { +public: + virtual ~RefactoringActionRuleBase() {} + + /// Initiates and performs a specific refactoring action. + /// + /// The specific rule will invoke an appropriate \c handle method on a + /// consumer to propagate the result of the refactoring action. + virtual void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) = 0; + + /// Returns the structure that describes the refactoring. + // static const RefactoringDescriptor &describe() = 0; +}; + +/// A refactoring action rule is a wrapper class around a specific refactoring +/// action rule (SourceChangeRefactoringRule, etc) that, in addition to invoking +/// the action, describes the requirements that determine when the action can be +/// initiated. +class RefactoringActionRule : public RefactoringActionRuleBase { +public: + /// Returns true when the rule has a source selection requirement that has + /// to be fullfilled before refactoring can be performed. + virtual bool hasSelectionRequirement() = 0; + + /// Traverses each refactoring option used by the rule and invokes the + /// \c visit callback in the consumer for each option. + /// + /// Options are visited in the order of use, e.g. if a rule has two + /// requirements that use options, the options from the first requirement + /// are visited before the options in the second requirement. + virtual void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) = 0; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h new file mode 100644 index 0000000000000..355a6a55f22fd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h @@ -0,0 +1,123 @@ +//===--- RefactoringActionRuleRequirements.h - Clang refactoring library --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" +#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" +#include "clang/Tooling/Refactoring/RefactoringOption.h" +#include "clang/Tooling/Refactoring/RefactoringRuleContext.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +/// A refactoring action rule requirement determines when a refactoring action +/// rule can be invoked. The rule can be invoked only when all of the +/// requirements are satisfied. +/// +/// Subclasses must implement the +/// 'Expected<T> evaluate(RefactoringRuleContext &) const' member function. +/// \c T is used to determine the return type that is passed to the +/// refactoring rule's constructor. +/// For example, the \c SourceRangeSelectionRequirement subclass defines +/// 'Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const' +/// function. When this function returns a non-error value, the resulting +/// source range is passed to the specific refactoring action rule +/// constructor (provided all other requirements are satisfied). +class RefactoringActionRuleRequirement { + // Expected<T> evaluate(RefactoringRuleContext &Context) const; +}; + +/// A base class for any requirement that expects some part of the source to be +/// selected in an editor (or the refactoring tool with the -selection option). +class SourceSelectionRequirement : public RefactoringActionRuleRequirement {}; + +/// A selection requirement that is satisfied when any portion of the source +/// text is selected. +class SourceRangeSelectionRequirement : public SourceSelectionRequirement { +public: + Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const { + if (Context.getSelectionRange().isValid()) + return Context.getSelectionRange(); + return Context.createDiagnosticError(diag::err_refactor_no_selection); + } +}; + +/// An AST selection requirement is satisfied when any portion of the AST +/// overlaps with the selection range. +/// +/// The requirement will be evaluated only once during the initiation and +/// search of matching refactoring action rules. +class ASTSelectionRequirement : public SourceRangeSelectionRequirement { +public: + Expected<SelectedASTNode> evaluate(RefactoringRuleContext &Context) const; +}; + +/// A selection requirement that is satisfied when the selection range overlaps +/// with a number of neighbouring statements in the AST. The statemenst must be +/// contained in declaration like a function. The selection range must be a +/// non-empty source selection (i.e. cursors won't be accepted). +/// +/// The requirement will be evaluated only once during the initiation and search +/// of matching refactoring action rules. +/// +/// \see CodeRangeASTSelection +class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement { +public: + Expected<CodeRangeASTSelection> + evaluate(RefactoringRuleContext &Context) const; +}; + +/// A base class for any requirement that requires some refactoring options. +class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement { +public: + virtual ~RefactoringOptionsRequirement() {} + + /// Returns the set of refactoring options that are used when evaluating this + /// requirement. + virtual ArrayRef<std::shared_ptr<RefactoringOption>> + getRefactoringOptions() const = 0; +}; + +/// A requirement that evaluates to the value of the given \c OptionType when +/// the \c OptionType is a required option. When the \c OptionType is an +/// optional option, the requirement will evaluate to \c None if the option is +/// not specified or to an appropriate value otherwise. +template <typename OptionType> +class OptionRequirement : public RefactoringOptionsRequirement { +public: + OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {} + + ArrayRef<std::shared_ptr<RefactoringOption>> + getRefactoringOptions() const final override { + return Opt; + } + + Expected<typename OptionType::ValueType> + evaluate(RefactoringRuleContext &) const { + return static_cast<OptionType *>(Opt.get())->getValue(); + } + +private: + /// The partially-owned option. + /// + /// The ownership of the option is shared among the different requirements + /// because the same option can be used by multiple rules in one refactoring + /// action. + std::shared_ptr<RefactoringOption> Opt; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h new file mode 100644 index 0000000000000..33206d9a5dd1e --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRules.h @@ -0,0 +1,94 @@ +//===--- RefactoringActionRules.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H + +#include "clang/Tooling/Refactoring/RefactoringActionRule.h" +#include "clang/Tooling/Refactoring/RefactoringActionRulesInternal.h" + +namespace clang { +namespace tooling { + +/// Creates a new refactoring action rule that constructs and invokes the +/// \c RuleType rule when all of the requirements are satisfied. +/// +/// This function takes in a list of values whose type derives from +/// \c RefactoringActionRuleRequirement. These values describe the initiation +/// requirements that have to be satisfied by the refactoring engine before +/// the provided action rule can be constructed and invoked. The engine +/// verifies that the requirements are satisfied by evaluating them (using the +/// 'evaluate' member function) and checking that the results don't contain +/// any errors. Once all requirements are satisfied, the provided refactoring +/// rule is constructed by passing in the values returned by the requirements' +/// evaluate functions as arguments to the constructor. The rule is then invoked +/// immediately after construction. +/// +/// The separation of requirements, their evaluation and the invocation of the +/// refactoring action rule allows the refactoring clients to: +/// - Disable refactoring action rules whose requirements are not supported. +/// - Gather the set of options and define a command-line / visual interface +/// that allows users to input these options without ever invoking the +/// action. +template <typename RuleType, typename... RequirementTypes> +std::unique_ptr<RefactoringActionRule> +createRefactoringActionRule(const RequirementTypes &... Requirements); + +/// A set of refactoring action rules that should have unique initiation +/// requirements. +using RefactoringActionRules = + std::vector<std::unique_ptr<RefactoringActionRule>>; + +/// A type of refactoring action rule that produces source replacements in the +/// form of atomic changes. +/// +/// This action rule is typically used for local refactorings that replace +/// source in a single AST unit. +class SourceChangeRefactoringRule : public RefactoringActionRuleBase { +public: + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) final override { + Expected<AtomicChanges> Changes = createSourceReplacements(Context); + if (!Changes) + Consumer.handleError(Changes.takeError()); + else + Consumer.handle(std::move(*Changes)); + } + +private: + virtual Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) = 0; +}; + +/// A type of refactoring action rule that finds a set of symbol occurrences +/// that reference a particular symbol. +/// +/// This action rule is typically used for an interactive rename that allows +/// users to specify the new name and the set of selected occurrences during +/// the refactoring. +class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase { +public: + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) final override { + Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context); + if (!Occurrences) + Consumer.handleError(Occurrences.takeError()); + else + Consumer.handle(std::move(*Occurrences)); + } + +private: + virtual Expected<SymbolOccurrences> + findSymbolOccurrences(RefactoringRuleContext &Context) = 0; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h new file mode 100644 index 0000000000000..75b6c8f70d173 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h @@ -0,0 +1,158 @@ +//===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRule.h" +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" +#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" +#include "clang/Tooling/Refactoring/RefactoringRuleContext.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { +namespace internal { + +inline llvm::Error findError() { return llvm::Error::success(); } + +inline void ignoreError() {} + +template <typename FirstT, typename... RestT> +void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) { + if (!First) + llvm::consumeError(First.takeError()); + ignoreError(Rest...); +} + +/// Scans the tuple and returns a valid \c Error if any of the values are +/// invalid. +template <typename FirstT, typename... RestT> +llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) { + if (!First) { + ignoreError(Rest...); + return First.takeError(); + } + return findError(Rest...); +} + +template <typename RuleType, typename... RequirementTypes, size_t... Is> +void invokeRuleAfterValidatingRequirements( + RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context, + const std::tuple<RequirementTypes...> &Requirements, + llvm::index_sequence<Is...>) { + // Check if the requirements we're interested in can be evaluated. + auto Values = + std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...); + auto Err = findError(std::get<Is>(Values)...); + if (Err) + return Consumer.handleError(std::move(Err)); + // Construct the target action rule by extracting the evaluated + // requirements from Expected<> wrappers and then run it. + auto Rule = + RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...); + if (!Rule) + return Consumer.handleError(Rule.takeError()); + Rule->invoke(Consumer, Context); +} + +inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {} + +/// Scans the list of requirements in a rule and visits all the refactoring +/// options that are used by all the requirements. +template <typename FirstT, typename... RestT> +void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor, + const FirstT &First, const RestT &... Rest) { + struct OptionGatherer { + RefactoringOptionVisitor &Visitor; + + void operator()(const RefactoringOptionsRequirement &Requirement) { + for (const auto &Option : Requirement.getRefactoringOptions()) + Option->passToVisitor(Visitor); + } + void operator()(const RefactoringActionRuleRequirement &) {} + }; + (OptionGatherer{Visitor})(First); + return visitRefactoringOptionsImpl(Visitor, Rest...); +} + +template <typename... RequirementTypes, size_t... Is> +void visitRefactoringOptions( + RefactoringOptionVisitor &Visitor, + const std::tuple<RequirementTypes...> &Requirements, + llvm::index_sequence<Is...>) { + visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...); +} + +/// A type trait that returns true when the given type list has at least one +/// type whose base is the given base type. +template <typename Base, typename First, typename... Rest> +struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value || + HasBaseOf<Base, Rest...>::value, + std::true_type, std::false_type>::type {}; + +template <typename Base, typename T> +struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {}; + +/// A type trait that returns true when the given type list contains types that +/// derive from Base. +template <typename Base, typename First, typename... Rest> +struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value && + AreBaseOf<Base, Rest...>::value, + std::true_type, std::false_type>::type {}; + +template <typename Base, typename T> +struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {}; + +} // end namespace internal + +template <typename RuleType, typename... RequirementTypes> +std::unique_ptr<RefactoringActionRule> +createRefactoringActionRule(const RequirementTypes &... Requirements) { + static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value, + "Expected a refactoring action rule type"); + static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement, + RequirementTypes...>::value, + "Expected a list of refactoring action rules"); + + class Rule final : public RefactoringActionRule { + public: + Rule(std::tuple<RequirementTypes...> Requirements) + : Requirements(Requirements) {} + + void invoke(RefactoringResultConsumer &Consumer, + RefactoringRuleContext &Context) override { + internal::invokeRuleAfterValidatingRequirements<RuleType>( + Consumer, Context, Requirements, + llvm::index_sequence_for<RequirementTypes...>()); + } + + bool hasSelectionRequirement() override { + return internal::HasBaseOf<SourceSelectionRequirement, + RequirementTypes...>::value; + } + + void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override { + internal::visitRefactoringOptions( + Visitor, Requirements, + llvm::index_sequence_for<RequirementTypes...>()); + } + private: + std::tuple<RequirementTypes...> Requirements; + }; + + return llvm::make_unique<Rule>(std::make_tuple(Requirements...)); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h new file mode 100644 index 0000000000000..6767dc708e017 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h @@ -0,0 +1,30 @@ +//===--- RefactoringDiagnostic.h - ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H +#define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" + +namespace clang { +namespace diag { +enum { +#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY) \ + ENUM, +#define REFACTORINGSTART +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +#undef DIAG + NUM_BUILTIN_REFACTORING_DIAGNOSTICS +}; +} // end namespace diag +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOption.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOption.h new file mode 100644 index 0000000000000..5011223cce690 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOption.h @@ -0,0 +1,64 @@ +//===--- RefactoringOption.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H + +#include "clang/Basic/LLVM.h" +#include <memory> +#include <type_traits> + +namespace clang { +namespace tooling { + +class RefactoringOptionVisitor; + +/// A refactoring option is an interface that describes a value that +/// has an impact on the outcome of a refactoring. +/// +/// Refactoring options can be specified using command-line arguments when +/// the clang-refactor tool is used. +class RefactoringOption { +public: + virtual ~RefactoringOption() {} + + /// Returns the name of the refactoring option. + /// + /// Each refactoring option must have a unique name. + virtual StringRef getName() const = 0; + + virtual StringRef getDescription() const = 0; + + /// True when this option must be specified before invoking the refactoring + /// action. + virtual bool isRequired() const = 0; + + /// Invokes the \c visit method in the option consumer that's appropriate + /// for the option's value type. + /// + /// For example, if the option stores a string value, this method will + /// invoke the \c visit method with a reference to an std::string value. + virtual void passToVisitor(RefactoringOptionVisitor &Visitor) = 0; +}; + +/// Constructs a refactoring option of the given type. +/// +/// The ownership of options is shared among requirements that use it because +/// one option can be used by multiple rules in a refactoring action. +template <typename OptionType> +std::shared_ptr<OptionType> createRefactoringOption() { + static_assert(std::is_base_of<RefactoringOption, OptionType>::value, + "invalid option type"); + return std::make_shared<OptionType>(); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h new file mode 100644 index 0000000000000..aea8fa549392b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h @@ -0,0 +1,62 @@ +//===--- RefactoringOptionVisitor.h - Clang refactoring library -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H + +#include "clang/Basic/LLVM.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +class RefactoringOption; + +/// An interface that declares functions that handle different refactoring +/// option types. +/// +/// A valid refactoring option type must have a corresponding \c visit +/// declaration in this interface. +class RefactoringOptionVisitor { +public: + virtual ~RefactoringOptionVisitor() {} + + virtual void visit(const RefactoringOption &Opt, + Optional<std::string> &Value) = 0; +}; + +namespace traits { +namespace internal { + +template <typename T> struct HasHandle { +private: + template <typename ClassT> + static auto check(ClassT *) -> typename std::is_same< + decltype(std::declval<RefactoringOptionVisitor>().visit( + std::declval<RefactoringOption>(), *std::declval<Optional<T> *>())), + void>::type; + + template <typename> static std::false_type check(...); + +public: + using Type = decltype(check<RefactoringOptionVisitor>(nullptr)); +}; + +} // end namespace internal + +/// A type trait that returns true iff the given type is a type that can be +/// stored in a refactoring option. +template <typename T> +struct IsValidOptionType : internal::HasHandle<T>::Type {}; + +} // end namespace traits +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h new file mode 100644 index 0000000000000..e45c0a09fd67b --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringOptions.h @@ -0,0 +1,58 @@ +//===--- RefactoringOptions.h - Clang refactoring library -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" +#include "clang/Tooling/Refactoring/RefactoringOption.h" +#include "clang/Tooling/Refactoring/RefactoringOptionVisitor.h" +#include "llvm/Support/Error.h" +#include <type_traits> + +namespace clang { +namespace tooling { + +/// A refactoring option that stores a value of type \c T. +template <typename T, typename = typename std::enable_if< + traits::IsValidOptionType<T>::value>::type> +class OptionalRefactoringOption : public RefactoringOption { +public: + void passToVisitor(RefactoringOptionVisitor &Visitor) final override { + Visitor.visit(*this, Value); + } + + bool isRequired() const override { return false; } + + using ValueType = Optional<T>; + + const ValueType &getValue() const { return Value; } + +protected: + Optional<T> Value; +}; + +/// A required refactoring option that stores a value of type \c T. +template <typename T, typename = typename std::enable_if< + traits::IsValidOptionType<T>::value>::type> +class RequiredRefactoringOption : public OptionalRefactoringOption<T> { +public: + using ValueType = T; + + const ValueType &getValue() const { + return *OptionalRefactoringOption<T>::Value; + } + bool isRequired() const final override { return true; } +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h new file mode 100644 index 0000000000000..fe7738e734997 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h @@ -0,0 +1,52 @@ +//===--- RefactoringResultConsumer.h - Clang refactoring library ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace tooling { + +/// An abstract interface that consumes the various refactoring results that can +/// be produced by refactoring actions. +/// +/// A valid refactoring result must be handled by a \c handle method. +class RefactoringResultConsumer { +public: + virtual ~RefactoringResultConsumer() {} + + /// Handles an initation or an invication error. An initiation error typically + /// has a \c DiagnosticError payload that describes why initation failed. + virtual void handleError(llvm::Error Err) = 0; + + /// Handles the source replacements that are produced by a refactoring action. + virtual void handle(AtomicChanges SourceReplacements) { + defaultResultHandler(); + } + + /// Handles the symbol occurrences that are found by an interactive + /// refactoring action. + virtual void handle(SymbolOccurrences Occurrences) { defaultResultHandler(); } + +private: + void defaultResultHandler() { + handleError(llvm::make_error<llvm::StringError>( + "unsupported refactoring result", llvm::inconvertibleErrorCode())); + } +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h new file mode 100644 index 0000000000000..882ab824b6390 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h @@ -0,0 +1,90 @@ +//===--- RefactoringRuleContext.h - Clang refactoring library -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H +#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H + +#include "clang/Basic/DiagnosticError.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" + +namespace clang { + +class ASTContext; + +namespace tooling { + +/// The refactoring rule context stores all of the inputs that might be needed +/// by a refactoring action rule. It can create the specialized +/// \c ASTRefactoringOperation or \c PreprocessorRefactoringOperation values +/// that can be used by the refactoring action rules. +/// +/// The following inputs are stored by the operation: +/// +/// - SourceManager: a reference to a valid source manager. +/// +/// - SelectionRange: an optional source selection ranges that can be used +/// to represent a selection in an editor. +class RefactoringRuleContext { +public: + RefactoringRuleContext(const SourceManager &SM) : SM(SM) {} + + const SourceManager &getSources() const { return SM; } + + /// Returns the current source selection range as set by the + /// refactoring engine. Can be invalid. + SourceRange getSelectionRange() const { return SelectionRange; } + + void setSelectionRange(SourceRange R) { SelectionRange = R; } + + bool hasASTContext() const { return AST; } + + ASTContext &getASTContext() const { + assert(AST && "no AST!"); + return *AST; + } + + void setASTContext(ASTContext &Context) { AST = &Context; } + + /// Creates an llvm::Error value that contains a diagnostic. + /// + /// The errors should not outlive the context. + llvm::Error createDiagnosticError(SourceLocation Loc, unsigned DiagID) { + return DiagnosticError::create(Loc, PartialDiagnostic(DiagID, DiagStorage)); + } + + llvm::Error createDiagnosticError(unsigned DiagID) { + return createDiagnosticError(SourceLocation(), DiagID); + } + + void setASTSelection(std::unique_ptr<SelectedASTNode> Node) { + ASTNodeSelection = std::move(Node); + } + +private: + /// The source manager for the translation unit / file on which a refactoring + /// action might operate on. + const SourceManager &SM; + /// An optional source selection range that's commonly used to represent + /// a selection in an editor. + SourceRange SelectionRange; + /// An optional AST for the translation unit on which a refactoring action + /// might operate on. + ASTContext *AST = nullptr; + /// The allocator for diagnostics. + PartialDiagnostic::StorageAllocator DiagStorage; + + // FIXME: Remove when memoized. + std::unique_ptr<SelectedASTNode> ASTNodeSelection; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h index 099eaca6c42ae..734b624d777ba 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h @@ -16,6 +16,11 @@ #define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H #include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" +#include "clang/Tooling/Refactoring/RefactoringOptions.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/Support/Error.h" namespace clang { class ASTConsumer; @@ -42,6 +47,53 @@ private: bool PrintLocations; }; +class RenameOccurrences final : public SourceChangeRefactoringRule { +public: + static Expected<RenameOccurrences> initiate(RefactoringRuleContext &Context, + SourceRange SelectionRange, + std::string NewName); + + static const RefactoringDescriptor &describe(); + +private: + RenameOccurrences(const NamedDecl *ND, std::string NewName) + : ND(ND), NewName(std::move(NewName)) {} + + Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) override; + + const NamedDecl *ND; + std::string NewName; +}; + +class QualifiedRenameRule final : public SourceChangeRefactoringRule { +public: + static Expected<QualifiedRenameRule> initiate(RefactoringRuleContext &Context, + std::string OldQualifiedName, + std::string NewQualifiedName); + + static const RefactoringDescriptor &describe(); + +private: + QualifiedRenameRule(const NamedDecl *ND, + std::string NewQualifiedName) + : ND(ND), NewQualifiedName(std::move(NewQualifiedName)) {} + + Expected<AtomicChanges> + createSourceReplacements(RefactoringRuleContext &Context) override; + + // A NamedDecl which indentifies the the symbol being renamed. + const NamedDecl *ND; + // The new qualified name to change the symbol to. + std::string NewQualifiedName; +}; + +/// Returns source replacements that correspond to the rename of the given +/// symbol occurrences. +llvm::Expected<std::vector<AtomicChange>> +createRenameReplacements(const SymbolOccurrences &Occurrences, + const SourceManager &SM, const SymbolName &NewName); + /// Rename all symbols identified by the given USRs. class QualifiedRenamingAction { public: diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolName.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolName.h new file mode 100644 index 0000000000000..e69d2908b5d30 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolName.h @@ -0,0 +1,49 @@ +//===--- SymbolName.h - Clang refactoring library -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace tooling { + +/// A name of a symbol. +/// +/// Symbol's name can be composed of multiple strings. For example, Objective-C +/// methods can contain multiple argument lables: +/// +/// \code +/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y; +/// // ^~ string 0 ~~~~~ ^~ string 1 ~~~~~ +/// \endcode +class SymbolName { +public: + explicit SymbolName(StringRef Name) { + // While empty symbol names are valid (Objective-C selectors can have empty + // name pieces), occurrences Objective-C selectors are created using an + // array of strings instead of just one string. + assert(!Name.empty() && "Invalid symbol name!"); + this->Name.push_back(Name.str()); + } + + ArrayRef<std::string> getNamePieces() const { return Name; } + +private: + llvm::SmallVector<std::string, 1> Name; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h new file mode 100644 index 0000000000000..0f853011978f1 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h @@ -0,0 +1,91 @@ +//===--- SymbolOccurrences.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { +namespace tooling { + +class SymbolName; + +/// An occurrence of a symbol in the source. +/// +/// Occurrences can have difference kinds, that describe whether this occurrence +/// is an exact semantic match, or whether this is a weaker textual match that's +/// not guaranteed to represent the exact declaration. +/// +/// A single occurrence of a symbol can span more than one source range. For +/// example, Objective-C selectors can contain multiple argument labels: +/// +/// \code +/// [object selectorPiece1: ... selectorPiece2: ...]; +/// // ^~~ range 0 ~~ ^~~ range 1 ~~ +/// \endcode +/// +/// We have to replace the text in both range 0 and range 1 when renaming the +/// Objective-C method 'selectorPiece1:selectorPiece2'. +class SymbolOccurrence { +public: + enum OccurrenceKind { + /// This occurrence is an exact match and can be renamed automatically. + /// + /// Note: + /// Symbol occurrences in macro arguments that expand to different + /// declarations get marked as exact matches, and thus the renaming engine + /// will rename them e.g.: + /// + /// \code + /// #define MACRO(x) x + ns::x + /// int foo(int var) { + /// return MACRO(var); // var is renamed automatically here when + /// // either var or ns::var is renamed. + /// }; + /// \endcode + /// + /// The user will have to fix their code manually after performing such a + /// rename. + /// FIXME: The rename verifier should notify user about this issue. + MatchingSymbol + }; + + SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, + ArrayRef<SourceLocation> Locations); + + SymbolOccurrence(SymbolOccurrence &&) = default; + SymbolOccurrence &operator=(SymbolOccurrence &&) = default; + + OccurrenceKind getKind() const { return Kind; } + + ArrayRef<SourceRange> getNameRanges() const { + if (MultipleRanges) { + return llvm::makeArrayRef(MultipleRanges.get(), + RangeOrNumRanges.getBegin().getRawEncoding()); + } + return RangeOrNumRanges; + } + +private: + OccurrenceKind Kind; + std::unique_ptr<SourceRange[]> MultipleRanges; + SourceRange RangeOrNumRanges; +}; + +using SymbolOccurrences = std::vector<SymbolOccurrence>; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h index 8aafee95bc097..f1c5ae60f875c 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h @@ -23,11 +23,25 @@ namespace clang { class ASTConsumer; +class ASTContext; class CompilerInstance; class NamedDecl; namespace tooling { +/// Returns the canonical declaration that best represents a symbol that can be +/// renamed. +/// +/// The following canonicalization rules are currently used: +/// +/// - A constructor is canonicalized to its class. +/// - A destructor is canonicalized to its class. +const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl); + +/// Returns the set of USRs that correspond to the given declaration. +std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND, + ASTContext &Context); + struct USRFindingAction { USRFindingAction(ArrayRef<unsigned> SymbolOffsets, ArrayRef<std::string> QualifiedNames, bool Force) diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h index 733ea1a6ac9ed..801a8ad9e99c6 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h @@ -19,6 +19,7 @@ #include "clang/AST/AST.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" #include "llvm/ADT/StringRef.h" #include <string> #include <vector> @@ -38,10 +39,13 @@ std::vector<tooling::AtomicChange> createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, llvm::StringRef NewName, Decl *TranslationUnitDecl); -// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree! -std::vector<SourceLocation> -getLocationsOfUSRs(const std::vector<std::string> &USRs, - llvm::StringRef PrevName, Decl *Decl); +/// Finds the symbol occurrences for the symbol that's identified by the given +/// USR set. +/// +/// \return SymbolOccurrences that can be converted to AtomicChanges when +/// renaming. +SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, + StringRef PrevName, Decl *Decl); } // end namespace tooling } // end namespace clang diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/StandaloneExecution.h b/contrib/llvm/tools/clang/include/clang/Tooling/StandaloneExecution.h new file mode 100644 index 0000000000000..f5f32d737a452 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/StandaloneExecution.h @@ -0,0 +1,97 @@ +//===--- StandaloneExecution.h - Standalone execution. -*- 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 standalone execution of clang tools. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H +#define LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H + +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Tooling/Execution.h" + +namespace clang { +namespace tooling { + +/// \brief A standalone executor that runs FrontendActions on a given set of +/// TUs in sequence. +/// +/// By default, this executor uses the following arguments adjusters (as defined +/// in `clang/Tooling/ArgumentsAdjusters.h`): +/// - `getClangStripOutputAdjuster()` +/// - `getClangSyntaxOnlyAdjuster()` +/// - `getClangStripDependencyFileAdjuster()` +class StandaloneToolExecutor : public ToolExecutor { +public: + static const char *ExecutorName; + + /// \brief Init with \p CompilationDatabase and the paths of all files to be + /// proccessed. + StandaloneToolExecutor( + const CompilationDatabase &Compilations, + llvm::ArrayRef<std::string> SourcePaths, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + /// \brief Init with \p CommonOptionsParser. This is expected to be used by + /// `createExecutorFromCommandLineArgs` based on commandline options. + /// + /// The executor takes ownership of \p Options. + StandaloneToolExecutor( + CommonOptionsParser Options, + std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()); + + StringRef getExecutorName() const override { return ExecutorName; } + + using ToolExecutor::execute; + + llvm::Error + execute(llvm::ArrayRef< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions) override; + + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { + Tool.setDiagnosticConsumer(DiagConsumer); + } + + ExecutionContext *getExecutionContext() override { return &Context; }; + + ToolResults *getToolResults() override { return &Results; } + + llvm::ArrayRef<std::string> getSourcePaths() const { + return Tool.getSourcePaths(); + } + + void mapVirtualFile(StringRef FilePath, StringRef Content) override { + Tool.mapVirtualFile(FilePath, Content); + } + + /// \brief Returns the file manager used in the tool. + /// + /// The file manager is shared between all translation units. + FileManager &getFiles() { return Tool.getFiles(); } + +private: + // Used to store the parser when the executor is initialized with parser. + llvm::Optional<CommonOptionsParser> OptionsParser; + // FIXME: The standalone executor is currently just a wrapper of `ClangTool`. + // Merge `ClangTool` implementation into the this. + ClangTool Tool; + ExecutionContext Context; + InMemoryToolResults Results; + ArgumentsAdjuster ArgsAdjuster; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h b/contrib/llvm/tools/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h new file mode 100644 index 0000000000000..11ba89546e9ea --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h @@ -0,0 +1,24 @@ +//===--- ToolExecutorPluginRegistry.h - -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H +#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H + +#include "clang/Tooling/Execution.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +typedef llvm::Registry<ToolExecutorPlugin> ToolExecutorPluginRegistry; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h index 6f9bc9e1a1504..e64be07d9ab44 100644 --- a/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h +++ b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h @@ -31,12 +31,12 @@ #define LLVM_CLANG_TOOLING_TOOLING_H #include "clang/AST/ASTConsumer.h" -#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Util.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -337,7 +337,9 @@ class ClangTool { /// The file manager is shared between all translation units. FileManager &getFiles() { return *Files; } - private: + llvm::ArrayRef<std::string> getSourcePaths() const { return SourcePaths; } + +private: const CompilationDatabase &Compilations; std::vector<std::string> SourcePaths; std::shared_ptr<PCHContainerOperations> PCHContainerOps; diff --git a/contrib/llvm/tools/clang/include/clang/module.modulemap b/contrib/llvm/tools/clang/include/clang/module.modulemap index d850bd552e1fd..4097ad2dc7164 100644 --- a/contrib/llvm/tools/clang/include/clang/module.modulemap +++ b/contrib/llvm/tools/clang/include/clang/module.modulemap @@ -49,6 +49,7 @@ module Clang_Basic { textual header "Basic/OperatorKinds.def" textual header "Basic/Sanitizers.def" textual header "Basic/TokenKinds.def" + textual header "Basic/X86Target.def" module * { export * } } @@ -69,9 +70,9 @@ module Clang_Diagnostics { module Frontend { header "Frontend/FrontendDiagnostic.h" export * } module Lex { header "Lex/LexDiagnostic.h" export * } module Parse { header "Parse/ParseDiagnostic.h" export * } - // FIXME: This breaks the build of Clang_Sema, for unknown reasons. - //module Sema { header "Sema/SemaDiagnostic.h" export * } + module Sema { header "Sema/SemaDiagnostic.h" export * } module Serialization { header "Serialization/SerializationDiagnostic.h" export * } + module Refactoring { header "Tooling/Refactoring/RefactoringDiagnostic.h" export * } } module Clang_Driver { @@ -90,7 +91,6 @@ module Clang_Frontend { requires cplusplus umbrella "Frontend" - textual header "Frontend/CodeGenOptions.def" textual header "Frontend/LangStandards.def" module * { export * } @@ -99,11 +99,20 @@ module Clang_Frontend { exclude header "Frontend/PCHContainerOperations.h" } +// Used in clangBasic +module Clang_Frontend_CodeGenOptions { + requires cplusplus + header "Frontend/CodeGenOptions.h" + textual header "Frontend/CodeGenOptions.def" + export * +} + module Clang_FrontendTool { requires cplusplus umbrella "FrontendTool" module * { export * } } module Clang_Index { requires cplusplus umbrella "Index" module * { export * } } module Clang_Lex { requires cplusplus umbrella "Lex" module * { export * } } module Clang_Parse { requires cplusplus umbrella "Parse" module * { export * } } -module Clang_Rewrite { requires cplusplus umbrella "Rewrite" module * { export * } } +module Clang_Rewrite { requires cplusplus umbrella "Rewrite/Core" module * { export * } } +module Clang_RewriteFrontend { requires cplusplus umbrella "Rewrite/Frontend" module * { export * } } module Clang_Sema { requires cplusplus umbrella "Sema" module * { export * } } module Clang_Serialization { requires cplusplus umbrella "Serialization" module * { export * } } @@ -139,3 +148,8 @@ module Clang_Tooling { // matchers (and thus the AST), which clang-format should not have. exclude header "Tooling/RefactoringCallbacks.h" } + +module Clang_ToolingCore { + requires cplusplus + umbrella "Tooling/Core" module * { export * } +} diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index c60373c5a90a4..dd96148edb272 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -1,4 +1,4 @@ -//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===// +//===- ASTContext.cpp - Context to hold long-lived AST nodes --------------===// // // The LLVM Compiler Infrastructure // @@ -13,33 +13,83 @@ #include "clang/AST/ASTContext.h" #include "CXXABI.h" +#include "clang/AST/APValue.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" +#include "clang/AST/AttrIterator.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Comment.h" -#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" #include "clang/AST/MangleNumberingContext.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/RawCommentList.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" #include "clang/AST/VTableBuilder.h" +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/SanitizerBlacklist.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/XRayLists.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Capacity.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdlib> #include <map> +#include <memory> +#include <string> +#include <tuple> +#include <utility> using namespace clang; @@ -57,7 +107,7 @@ unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; enum FloatingRank { - HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank + Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { @@ -256,11 +306,10 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return *Comment; } -namespace { /// If we have a 'templated' declaration for a template, adjust 'D' to /// refer to the actual template. /// If we have an implicit instantiation, adjust 'D' to refer to template. -const Decl *adjustDeclToTemplate(const Decl *D) { +static const Decl *adjustDeclToTemplate(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Is this function declaration part of a function template? if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) @@ -327,7 +376,6 @@ const Decl *adjustDeclToTemplate(const Decl *D) { // FIXME: Adjust alias templates? return D; } -} // anonymous namespace const RawComment *ASTContext::getRawCommentForAnyRedecl( const Decl *D, @@ -697,8 +745,8 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { llvm_unreachable("Invalid CXXABI type!"); } -static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, - const LangOptions &LOpts) { +static const LangASMap *getAddressSpaceMap(const TargetInfo &T, + const LangOptions &LOpts) { if (LOpts.FakeAddressSpaceMap) { // The fake address space map must have a distinct entry for each // language-specific address space. @@ -707,6 +755,7 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, 1, // opencl_global 3, // opencl_local 2, // opencl_constant + 0, // opencl_private 4, // opencl_generic 5, // cuda_device 6, // cuda_constant @@ -736,25 +785,12 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, Builtin::Context &builtins) : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), - SubstTemplateTemplateParmPacks(this_()), - GlobalNestedNameSpecifier(nullptr), Int128Decl(nullptr), - UInt128Decl(nullptr), BuiltinVaListDecl(nullptr), - BuiltinMSVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), - ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr), - CFConstantStringTagDecl(nullptr), CFConstantStringTypeDecl(nullptr), - ObjCInstanceTypeDecl(nullptr), FILEDecl(nullptr), jmp_bufDecl(nullptr), - sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), - BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), - cudaConfigureCallDecl(nullptr), FirstLocalImport(), LastLocalImport(), - ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr), - TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts), + SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, SM)), - AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), - BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr), - Listener(nullptr), Comments(SM), CommentsLoaded(false), + BuiltinInfo(builtins), DeclarationNames(*this), Comments(SM), CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(nullptr, 0) { TUDecl = TranslationUnitDecl::Create(*this); } @@ -1093,6 +1129,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, // GNU extension, __float128 for IEEE quadruple precision InitBuiltinType(Float128Ty, BuiltinType::Float128); + // C11 extension ISO/IEC TS 18661-3 + InitBuiltinType(Float16Ty, BuiltinType::Float16); + // GNU extension, 128-bit integers. InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); @@ -1182,7 +1221,14 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, ObjCSuperType = QualType(); // void * type - VoidPtrTy = getPointerType(VoidTy); + if (LangOpts.OpenCLVersion >= 200) { + auto Q = VoidTy.getQualifiers(); + Q.setAddressSpace(LangAS::opencl_generic); + VoidPtrTy = getPointerType(getCanonicalType( + getQualifiedType(VoidTy.getUnqualifiedType(), Q))); + } else { + VoidPtrTy = getPointerType(VoidTy); + } // nullptr type (C++0x 2.14.7) InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); @@ -1209,7 +1255,7 @@ AttrVec& ASTContext::getDeclAttrs(const Decl *D) { } /// \brief Erase the attributes corresponding to the given declaration. -void ASTContext::eraseDeclAttrs(const Decl *D) { +void ASTContext::eraseDeclAttrs(const Decl *D) { llvm::DenseMap<const Decl*, AttrVec*>::iterator Pos = DeclAttrs.find(D); if (Pos != DeclAttrs.end()) { Pos->second->~AttrVec(); @@ -1332,35 +1378,27 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { - llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos = - OverriddenMethods.find(Method->getCanonicalDecl()); - if (Pos == OverriddenMethods.end()) - return nullptr; - return Pos->second.begin(); + return overridden_methods(Method).begin(); } ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { - llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos = - OverriddenMethods.find(Method->getCanonicalDecl()); - if (Pos == OverriddenMethods.end()) - return nullptr; - return Pos->second.end(); + return overridden_methods(Method).end(); } unsigned ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { - llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos = - OverriddenMethods.find(Method->getCanonicalDecl()); - if (Pos == OverriddenMethods.end()) - return 0; - return Pos->second.size(); + auto Range = overridden_methods(Method); + return Range.end() - Range.begin(); } ASTContext::overridden_method_range ASTContext::overridden_methods(const CXXMethodDecl *Method) const { - return overridden_method_range(overridden_methods_begin(Method), - overridden_methods_end(Method)); + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos = + OverriddenMethods.find(Method->getCanonicalDecl()); + if (Pos == OverriddenMethods.end()) + return overridden_method_range(nullptr, nullptr); + return overridden_method_range(Pos->second.begin(), Pos->second.end()); } void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, @@ -1413,7 +1451,9 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: llvm_unreachable("Not a floating point type!"); - case BuiltinType::Half: return Target->getHalfFormat(); + case BuiltinType::Float16: + case BuiltinType::Half: + return Target->getHalfFormat(); case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); @@ -1450,7 +1490,6 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { // else about the declaration and its type. if (UseAlignAttrOnly) { // do nothing - } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType *RT = T->getAs<ReferenceType>()) { @@ -1624,6 +1663,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { uint64_t Width = 0; unsigned Align = 8; bool AlignIsRequired = false; + unsigned AS = 0; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1690,7 +1730,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = 0; Align = 8; break; - case BuiltinType::Bool: Width = Target->getBoolWidth(); Align = Target->getBoolAlign(); @@ -1740,6 +1779,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = 128; Align = 128; // int128_t is 128-bit aligned on all targets. break; + case BuiltinType::Float16: case BuiltinType::Half: Width = Target->getHalfWidth(); Align = Target->getHalfAlign(); @@ -1770,60 +1810,48 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; - case BuiltinType::OCLSampler: { - auto AS = getTargetAddressSpace(LangAS::opencl_constant); - Width = Target->getPointerWidth(AS); - Align = Target->getPointerAlign(AS); - break; - } + case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: - // Currently these types are pointers to opaque types. - Width = Target->getPointerWidth(0); - Align = Target->getPointerAlign(0); - break; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" - { - auto AS = getTargetAddressSpace(Target->getOpenCLImageAddrSpace()); - Width = Target->getPointerWidth(AS); - Align = Target->getPointerAlign(AS); - } + AS = getTargetAddressSpace( + Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T))); + Width = Target->getPointerWidth(AS); + Align = Target->getPointerAlign(AS); + break; } break; case Type::ObjCObjectPointer: Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; - case Type::BlockPointer: { - unsigned AS = getTargetAddressSpace( - cast<BlockPointerType>(T)->getPointeeType()); + case Type::BlockPointer: + AS = getTargetAddressSpace(cast<BlockPointerType>(T)->getPointeeType()); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; - } case Type::LValueReference: - case Type::RValueReference: { + case Type::RValueReference: // alignof and sizeof should never enter this code path here, so we go // the pointer route. - unsigned AS = getTargetAddressSpace( - cast<ReferenceType>(T)->getPointeeType()); + AS = getTargetAddressSpace(cast<ReferenceType>(T)->getPointeeType()); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; - } - case Type::Pointer: { - unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); + case Type::Pointer: + AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; - } case Type::MemberPointer: { const MemberPointerType *MPT = cast<MemberPointerType>(T); - std::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT); + CXXABI::MemberPointerInfo MPI = ABI->getMemberPointerInfo(MPT); + Width = MPI.Width; + Align = MPI.Align; break; } case Type::Complex: { @@ -1938,11 +1966,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } break; - case Type::Pipe: { + case Type::Pipe: Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global)); Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global)); - } - + break; } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); @@ -2055,7 +2082,6 @@ CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const { /// super class and then collects all ivars, including those synthesized for /// current class. This routine is used for implementation of current class /// when all ivars, declared and synthesized are known. -/// void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const { @@ -2107,6 +2133,171 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } } +static bool unionHasUniqueObjectRepresentations(const ASTContext &Context, + const RecordDecl *RD) { + assert(RD->isUnion() && "Must be union type"); + CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl()); + + for (const auto *Field : RD->fields()) { + if (!Context.hasUniqueObjectRepresentations(Field->getType())) + return false; + CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType()); + if (FieldSize != UnionSize) + return false; + } + return true; +} + +bool isStructEmpty(QualType Ty) { + const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl(); + + if (!RD->field_empty()) + return false; + + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) + return ClassDecl->isEmpty(); + + return true; +} + +static llvm::Optional<int64_t> +structHasUniqueObjectRepresentations(const ASTContext &Context, + const RecordDecl *RD) { + assert(!RD->isUnion() && "Must be struct/class type"); + const auto &Layout = Context.getASTRecordLayout(RD); + + int64_t CurOffsetInBits = 0; + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) { + if (ClassDecl->isDynamicClass()) + return llvm::None; + + SmallVector<std::pair<QualType, int64_t>, 4> Bases; + for (const auto Base : ClassDecl->bases()) { + // Empty types can be inherited from, and non-empty types can potentially + // have tail padding, so just make sure there isn't an error. + if (!isStructEmpty(Base.getType())) { + llvm::Optional<int64_t> Size = structHasUniqueObjectRepresentations( + Context, Base.getType()->getAs<RecordType>()->getDecl()); + if (!Size) + return llvm::None; + Bases.emplace_back(Base.getType(), Size.getValue()); + } + } + + std::sort( + Bases.begin(), Bases.end(), [&](const std::pair<QualType, int64_t> &L, + const std::pair<QualType, int64_t> &R) { + return Layout.getBaseClassOffset(L.first->getAsCXXRecordDecl()) < + Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl()); + }); + + for (const auto Base : Bases) { + int64_t BaseOffset = Context.toBits( + Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl())); + int64_t BaseSize = Base.second; + if (BaseOffset != CurOffsetInBits) + return llvm::None; + CurOffsetInBits = BaseOffset + BaseSize; + } + } + + for (const auto *Field : RD->fields()) { + if (!Field->getType()->isReferenceType() && + !Context.hasUniqueObjectRepresentations(Field->getType())) + return llvm::None; + + int64_t FieldSizeInBits = + Context.toBits(Context.getTypeSizeInChars(Field->getType())); + if (Field->isBitField()) { + int64_t BitfieldSize = Field->getBitWidthValue(Context); + + if (BitfieldSize > FieldSizeInBits) + return llvm::None; + FieldSizeInBits = BitfieldSize; + } + + int64_t FieldOffsetInBits = Context.getFieldOffset(Field); + + if (FieldOffsetInBits != CurOffsetInBits) + return llvm::None; + + CurOffsetInBits = FieldSizeInBits + FieldOffsetInBits; + } + + return CurOffsetInBits; +} + +bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const { + // C++17 [meta.unary.prop]: + // The predicate condition for a template specialization + // has_unique_object_representations<T> shall be + // satisfied if and only if: + // (9.1) - T is trivially copyable, and + // (9.2) - any two objects of type T with the same value have the same + // object representation, where two objects + // of array or non-union class type are considered to have the same value + // if their respective sequences of + // direct subobjects have the same values, and two objects of union type + // are considered to have the same + // value if they have the same active member and the corresponding members + // have the same value. + // The set of scalar types for which this condition holds is + // implementation-defined. [ Note: If a type has padding + // bits, the condition does not hold; otherwise, the condition holds true + // for unsigned integral types. -- end note ] + assert(!Ty.isNull() && "Null QualType sent to unique object rep check"); + + // Arrays are unique only if their element type is unique. + if (Ty->isArrayType()) + return hasUniqueObjectRepresentations(getBaseElementType(Ty)); + + // (9.1) - T is trivially copyable... + if (!Ty.isTriviallyCopyableType(*this)) + return false; + + // All integrals and enums are unique. + if (Ty->isIntegralOrEnumerationType()) + return true; + + // All other pointers are unique. + if (Ty->isPointerType()) + return true; + + if (Ty->isMemberPointerType()) { + const MemberPointerType *MPT = Ty->getAs<MemberPointerType>(); + return !ABI->getMemberPointerInfo(MPT).HasPadding; + } + + if (Ty->isRecordType()) { + const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl(); + + if (Record->isInvalidDecl()) + return false; + + if (Record->isUnion()) + return unionHasUniqueObjectRepresentations(*this, Record); + + Optional<int64_t> StructSize = + structHasUniqueObjectRepresentations(*this, Record); + + return StructSize && + StructSize.getValue() == static_cast<int64_t>(getTypeSize(Ty)); + } + + // FIXME: More cases to handle here (list by rsmith): + // vectors (careful about, eg, vector of 3 foo) + // _Complex int and friends + // _Atomic T + // Obj-C block pointers + // Obj-C object pointers + // and perhaps OpenCL's various builtin types (pipe, sampler_t, event_t, + // clk_event_t, queue_t, reserve_id_t) + // There're also Obj-C class types and the Obj-C selector type, but I think it + // makes sense for those to return false here. + + return false; +} + unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { unsigned count = 0; // Count ivars declared in class extension. @@ -2139,7 +2330,8 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) { return false; } -/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. +/// \brief Get the implementation of ObjCInterfaceDecl, or nullptr if none +/// exists. ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator I = ObjCImpls.find(D); @@ -2147,7 +2339,9 @@ ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) return cast<ObjCImplementationDecl>(I->second); return nullptr; } -/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. + +/// \brief Get the implementation of ObjCCategoryDecl, or nullptr if none +/// exists. ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator I = ObjCImpls.find(D); @@ -2162,6 +2356,7 @@ void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD, assert(IFaceD && ImplD && "Passed null params"); ObjCImpls[IFaceD] = ImplD; } + /// \brief Set the implementation of ObjCCategoryDecl. void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCCategoryImplDecl *ImplD) { @@ -2195,7 +2390,7 @@ const ObjCInterfaceDecl *ASTContext::getObjContainingInterface( return nullptr; } -/// \brief Get the copy initialization expression of VarDecl,or NULL if +/// \brief Get the copy initialization expression of VarDecl, or nullptr if /// none exists. Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) { assert(VD && "Passed null params"); @@ -2280,8 +2475,8 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const { return QualType(eq, fastQuals); } -QualType -ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const { +QualType ASTContext::getAddrSpaceQualType(QualType T, + LangAS AddressSpace) const { QualType CanT = getCanonicalType(T); if (CanT.getAddressSpace() == AddressSpace) return T; @@ -2300,6 +2495,27 @@ ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const { return getExtQualType(TypeNode, Quals); } +QualType ASTContext::removeAddrSpaceQualType(QualType T) const { + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If the qualifier doesn't have an address space just return it. + if (!Quals.hasAddressSpace()) + return T; + + Quals.removeAddressSpace(); + + // Removal of the address space can mean there are no longer any + // non-fast qualifiers, so creating an ExtQualType isn't possible (asserts) + // or required. + if (Quals.hasNonFastQualifiers()) + return getExtQualType(TypeNode, Quals); + else + return QualType(TypeNode, Quals.getFastQualifiers()); +} + QualType ASTContext::getObjCGCQualType(QualType T, Qualifiers::GC GCAttr) const { QualType CanT = getCanonicalType(T); @@ -2393,7 +2609,7 @@ static QualType getFunctionTypeWithExceptionSpec( bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) { return hasSameType(T, U) || - (getLangOpts().CPlusPlus1z && + (getLangOpts().CPlusPlus17 && hasSameType(getFunctionTypeWithExceptionSpec(*this, T, EST_None), getFunctionTypeWithExceptionSpec(*this, U, EST_None))); } @@ -2750,6 +2966,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::Vector: case Type::ExtVector: case Type::DependentSizedExtVector: + case Type::DependentAddressSpace: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: @@ -3098,6 +3315,41 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } +QualType ASTContext::getDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttrLoc) const { + assert(AddrSpaceExpr->isInstantiationDependent()); + + QualType canonPointeeType = getCanonicalType(PointeeType); + + void *insertPos = nullptr; + llvm::FoldingSetNodeID ID; + DependentAddressSpaceType::Profile(ID, *this, canonPointeeType, + AddrSpaceExpr); + + DependentAddressSpaceType *canonTy = + DependentAddressSpaceTypes.FindNodeOrInsertPos(ID, insertPos); + + if (!canonTy) { + canonTy = new (*this, TypeAlignment) + DependentAddressSpaceType(*this, canonPointeeType, + QualType(), AddrSpaceExpr, AttrLoc); + DependentAddressSpaceTypes.InsertNode(canonTy, insertPos); + Types.push_back(canonTy); + } + + if (canonPointeeType == PointeeType && + canonTy->getAddrSpaceExpr() == AddrSpaceExpr) + return QualType(canonTy, 0); + + DependentAddressSpaceType *sugaredType + = new (*this, TypeAlignment) + DependentAddressSpaceType(*this, PointeeType, QualType(canonTy, 0), + AddrSpaceExpr, AttrLoc); + Types.push_back(sugaredType); + return QualType(sugaredType, 0); +} + /// \brief Determine whether \p T is canonical as the result type of a function. static bool isCanonicalResultType(QualType T) { return T.isCanonical() && @@ -3106,7 +3358,6 @@ static bool isCanonicalResultType(QualType T) { } /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. -/// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { @@ -3222,7 +3473,7 @@ QualType ASTContext::getFunctionTypeInternal( Unique = true; } - bool NoexceptInType = getLangOpts().CPlusPlus1z; + bool NoexceptInType = getLangOpts().CPlusPlus17; bool IsCanonicalExceptionSpec = isCanonicalExceptionSpecification(EPI.ExceptionSpec, NoexceptInType); @@ -3358,7 +3609,7 @@ QualType ASTContext::getPipeType(QualType T, bool ReadOnly) const { llvm::FoldingSetNodeID ID; PipeType::Profile(ID, T, ReadOnly); - void *InsertPos = 0; + void *InsertPos = nullptr; if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); @@ -3986,7 +4237,7 @@ SortAndUniqueProtocols(SmallVectorImpl<ObjCProtocolDecl *> &Protocols) { QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { - return getObjCObjectType(BaseType, { }, + return getObjCObjectType(BaseType, {}, llvm::makeArrayRef(Protocols, NumProtocols), /*isKindOf=*/false); } @@ -4123,13 +4374,13 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, // FIXME: Check for protocols to which the class type is already // known to conform. - return getObjCObjectType(type, { }, protocols, false); + return getObjCObjectType(type, {}, protocols, false); } // id<protocol-list> if (type->isObjCIdType()) { const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); - type = getObjCObjectType(ObjCBuiltinIdTy, { }, protocols, + type = getObjCObjectType(ObjCBuiltinIdTy, {}, protocols, objPtr->isKindOfType()); return getObjCObjectPointerType(type); } @@ -4137,7 +4388,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, // Class<protocol-list> if (type->isObjCClassType()) { const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); - type = getObjCObjectType(ObjCBuiltinClassTy, { }, protocols, + type = getObjCObjectType(ObjCBuiltinClassTy, {}, protocols, objPtr->isKindOfType()); return getObjCObjectPointerType(type); } @@ -4512,7 +4763,7 @@ QualType ASTContext::getAutoRRefDeductType() const { /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { - assert (Decl); + assert(Decl); // FIXME: What is the design on getTagDeclType when it requires casting // away const? mutable? return getTypeDeclType(const_cast<TagDecl*>(Decl)); @@ -4569,6 +4820,13 @@ QualType ASTContext::getPointerDiffType() const { return getFromTargetType(Target->getPtrDiffType(0)); } +/// \brief Return the unique unsigned counterpart of "ptrdiff_t" +/// integer type. The standard (C11 7.21.6.1p7) refers to this type +/// in the definition of %tu format specifier. +QualType ASTContext::getUnsignedPointerDiffType() const { + return getFromTargetType(Target->getUnsignedPtrDiffType(0)); +} + /// \brief Return the unique type for "pid_t" defined in /// <sys/types.h>. We need this to compute the correct type for vfork(). QualType ASTContext::getProcessIDType() const { @@ -5051,6 +5309,7 @@ static FloatingRank getFloatingRank(QualType T) { assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type"); switch (T->getAs<BuiltinType>()->getKind()) { default: llvm_unreachable("getFloatingRank(): not a floating type"); + case BuiltinType::Float16: return Float16Rank; case BuiltinType::Half: return HalfRank; case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; @@ -5068,6 +5327,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, FloatingRank EltRank = getFloatingRank(Size); if (Domain->isComplexType()) { switch (EltRank) { + case Float16Rank: case HalfRank: llvm_unreachable("Complex half is not supported"); case FloatRank: return FloatComplexTy; case DoubleRank: return DoubleComplexTy; @@ -5078,6 +5338,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, assert(Domain->isRealFloatingType() && "Unknown domain!"); switch (EltRank) { + case Float16Rank: return HalfTy; case HalfRank: return HalfTy; case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; @@ -5455,6 +5716,46 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { return getTagDeclType(BlockDescriptorExtendedType); } +TargetInfo::OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { + auto BT = dyn_cast<BuiltinType>(T); + + if (!BT) { + if (isa<PipeType>(T)) + return TargetInfo::OCLTK_Pipe; + + return TargetInfo::OCLTK_Default; + } + + switch (BT->getKind()) { +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: \ + return TargetInfo::OCLTK_Image; +#include "clang/Basic/OpenCLImageTypes.def" + + case BuiltinType::OCLClkEvent: + return TargetInfo::OCLTK_ClkEvent; + + case BuiltinType::OCLEvent: + return TargetInfo::OCLTK_Event; + + case BuiltinType::OCLQueue: + return TargetInfo::OCLTK_Queue; + + case BuiltinType::OCLReserveID: + return TargetInfo::OCLTK_ReserveID; + + case BuiltinType::OCLSampler: + return TargetInfo::OCLTK_Sampler; + + default: + return TargetInfo::OCLTK_Default; + } +} + +LangAS ASTContext::getOpenCLTypeAddrSpace(const Type *T) const { + return Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T)); +} + /// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty" /// requires copy/dispose. Note that this must match the logic /// in buildByrefHelpers. @@ -5497,7 +5798,6 @@ bool ASTContext::BlockRequiresCopying(QualType Ty, bool ASTContext::getByrefLifetime(QualType Ty, Qualifiers::ObjCLifetime &LifeTime, bool &HasByrefExtendedLayout) const { - if (!getLangOpts().ObjC1 || getLangOpts().getGC() != LangOptions::NonGC) return false; @@ -5565,14 +5865,14 @@ ASTContext::getInlineVariableDefinitionKind(const VarDecl *VD) const { // In almost all cases, it's a weak definition. auto *First = VD->getFirstDecl(); - if (!First->isConstexpr() || First->isInlineSpecified() || - !VD->isStaticDataMember()) + if (First->isInlineSpecified() || !First->isStaticDataMember()) return InlineVariableDefinitionKind::Weak; // If there's a file-context declaration in this translation unit, it's a // non-discardable definition. for (auto *D : VD->redecls()) - if (D->getLexicalDeclContext()->isFileContext()) + if (D->getLexicalDeclContext()->isFileContext() && + !D->isInlineSpecified() && (D->isConstexpr() || First->isConstexpr())) return InlineVariableDefinitionKind::Strong; // If we've not seen one yet, we don't know. @@ -5602,7 +5902,6 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! - SourceLocation Loc; CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); CharUnits ParmOffset = PtrSize; for (auto PI : Decl->parameters()) { @@ -5610,7 +5909,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { CharUnits sz = getObjCEncodingTypeSize(PType); if (sz.isZero()) continue; - assert (sz.isPositive() && "BlockExpr - Incomplete param type"); + assert(sz.isPositive() && "BlockExpr - Incomplete param type"); ParmOffset += sz; } // Size of the argument frame @@ -5710,7 +6009,6 @@ std::string ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! - SourceLocation Loc; CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); // The first two arguments (self and _cmd) are pointers; account for // their size. @@ -5722,8 +6020,8 @@ std::string ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, if (sz.isZero()) continue; - assert (sz.isPositive() && - "getObjCEncodingForMethodDecl - Incomplete param type"); + assert(sz.isPositive() && + "getObjCEncodingForMethodDecl - Incomplete param type"); ParmOffset += sz; } S += charUnitsToString(ParmOffset); @@ -5870,7 +6168,6 @@ ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, /// Another legacy compatibility encoding: 32-bit longs are encoded as /// 'l' or 'L' , but not always. For typedefs, we need to use /// 'i' or 'I' instead if encoding a struct field, or a pointer! -/// void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { if (isa<TypedefType>(PointeeTy.getTypePtr())) { if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) { @@ -5935,6 +6232,7 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C, case BuiltinType::LongDouble: return 'D'; case BuiltinType::NullPtr: return '*'; // like char* + case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Half: // FIXME: potentially need @encodes for these! @@ -6176,9 +6474,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); llvm::raw_string_ostream OS(S); - TemplateSpecializationType::PrintTemplateArgumentList(OS, - TemplateArgs.asArray(), - (*this).getPrintingPolicy()); + printTemplateArgumentList(OS, TemplateArgs.asArray(), + getPrintingPolicy()); } } else { S += '?'; @@ -6370,10 +6667,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Vector: case Type::ExtVector: // Until we have a coherent encoding of these three types, issue warning. - { if (NotEncodedT) - *NotEncodedT = T; - return; - } + if (NotEncodedT) + *NotEncodedT = T; + return; // We could see an undeduced auto type here during error recovery. // Just ignore it. @@ -6557,7 +6853,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, TypedefDecl *ASTContext::getObjCIdDecl() const { if (!ObjCIdDecl) { - QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { }); + QualType T = getObjCObjectType(ObjCBuiltinIdTy, {}, {}); T = getObjCObjectPointerType(T); ObjCIdDecl = buildImplicitTypedef(T, "id"); } @@ -6574,7 +6870,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const { TypedefDecl *ASTContext::getObjCClassDecl() const { if (!ObjCClassDecl) { - QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { }); + QualType T = getObjCObjectType(ObjCBuiltinClassTy, {}, {}); T = getObjCObjectPointerType(T); ObjCClassDecl = buildImplicitTypedef(T, "Class"); } @@ -7236,7 +7532,7 @@ bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, QualType rhs) { const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); - assert ((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible"); + assert((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible"); for (auto *lhsProto : lhsQID->quals()) { bool match = false; @@ -7374,7 +7670,6 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, /// canAssignObjCInterfaces - Return true if the two interface types are /// compatible for assignment from RHS to LHS. This handles validation of any /// protocol qualifiers on the LHS or RHS. -/// bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { const ObjCObjectType* LHS = LHSOPT->getObjectType(); @@ -7480,7 +7775,6 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( static int compareObjCProtocolsByName(ObjCProtocolDecl * const *lhs, ObjCProtocolDecl * const *rhs) { return (*lhs)->getName().compare((*rhs)->getName()); - } /// getIntersectionOfProtocols - This routine finds the intersection of set @@ -7649,7 +7943,7 @@ QualType ASTContext::areCommonBaseCompatible( } else if (LHS->isSpecialized() != RHS->isSpecialized()) { // If only one has type arguments, the result will not have type // arguments. - LHSTypeArgs = { }; + LHSTypeArgs = {}; anyChanges = true; } @@ -7700,7 +7994,7 @@ QualType ASTContext::areCommonBaseCompatible( } else if (LHS->isSpecialized() != RHS->isSpecialized()) { // If only one has type arguments, the result will not have type // arguments. - RHSTypeArgs = { }; + RHSTypeArgs = {}; anyChanges = true; } @@ -7962,9 +8256,17 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->getTypeQuals() != rproto->getTypeQuals()) return QualType(); - if (!doFunctionTypesMatchOnExtParameterInfos(rproto, lproto)) + SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos; + bool canUseLeft, canUseRight; + if (!mergeExtParameterInfo(lproto, rproto, canUseLeft, canUseRight, + newParamInfos)) return QualType(); + if (!canUseLeft) + allLTypes = false; + if (!canUseRight) + allRTypes = false; + // Check parameter type compatibility SmallVector<QualType, 10> types; for (unsigned i = 0, n = lproto->getNumParams(); i < n; i++) { @@ -7995,6 +8297,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo(); EPI.ExtInfo = einfo; + EPI.ExtParameterInfos = + newParamInfos.empty() ? nullptr : newParamInfos.data(); return getFunctionType(retType, types, EPI); } @@ -8328,7 +8632,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return QualType(); } - case Type::ObjCObjectPointer: { + case Type::ObjCObjectPointer: if (OfBlockPointer) { if (canAssignObjCInterfacesInBlockPointer( LHS->getAs<ObjCObjectPointerType>(), @@ -8342,38 +8646,59 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return LHS; return QualType(); - } case Type::Pipe: - { assert(LHS != RHS && "Equivalent pipe types should have already been handled!"); return QualType(); } - } llvm_unreachable("Invalid Type::Class!"); } -bool ASTContext::doFunctionTypesMatchOnExtParameterInfos( - const FunctionProtoType *firstFnType, - const FunctionProtoType *secondFnType) { +bool ASTContext::mergeExtParameterInfo( + const FunctionProtoType *FirstFnType, const FunctionProtoType *SecondFnType, + bool &CanUseFirst, bool &CanUseSecond, + SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos) { + assert(NewParamInfos.empty() && "param info list not empty"); + CanUseFirst = CanUseSecond = true; + bool FirstHasInfo = FirstFnType->hasExtParameterInfos(); + bool SecondHasInfo = SecondFnType->hasExtParameterInfos(); + // Fast path: if the first type doesn't have ext parameter infos, - // we match if and only if they second type also doesn't have them. - if (!firstFnType->hasExtParameterInfos()) - return !secondFnType->hasExtParameterInfos(); + // we match if and only if the second type also doesn't have them. + if (!FirstHasInfo && !SecondHasInfo) + return true; - // Otherwise, we can only match if the second type has them. - if (!secondFnType->hasExtParameterInfos()) - return false; + bool NeedParamInfo = false; + size_t E = FirstHasInfo ? FirstFnType->getExtParameterInfos().size() + : SecondFnType->getExtParameterInfos().size(); - auto firstEPI = firstFnType->getExtParameterInfos(); - auto secondEPI = secondFnType->getExtParameterInfos(); - assert(firstEPI.size() == secondEPI.size()); + for (size_t I = 0; I < E; ++I) { + FunctionProtoType::ExtParameterInfo FirstParam, SecondParam; + if (FirstHasInfo) + FirstParam = FirstFnType->getExtParameterInfo(I); + if (SecondHasInfo) + SecondParam = SecondFnType->getExtParameterInfo(I); - for (size_t i = 0, n = firstEPI.size(); i != n; ++i) { - if (firstEPI[i] != secondEPI[i]) + // Cannot merge unless everything except the noescape flag matches. + if (FirstParam.withIsNoEscape(false) != SecondParam.withIsNoEscape(false)) return false; + + bool FirstNoEscape = FirstParam.isNoEscape(); + bool SecondNoEscape = SecondParam.isNoEscape(); + bool IsNoEscape = FirstNoEscape && SecondNoEscape; + NewParamInfos.push_back(FirstParam.withIsNoEscape(IsNoEscape)); + if (NewParamInfos.back().getOpaqueValue()) + NeedParamInfo = true; + if (FirstNoEscape != IsNoEscape) + CanUseFirst = false; + if (SecondNoEscape != IsNoEscape) + CanUseSecond = false; } + + if (!NeedParamInfo) + NewParamInfos.clear(); + return true; } @@ -8502,7 +8827,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { } } -ASTMutationListener::~ASTMutationListener() { } +ASTMutationListener::~ASTMutationListener() = default; void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {} @@ -8554,7 +8879,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; - case 'N': { + case 'N': // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); @@ -8564,7 +8889,6 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, if (Context.getTargetInfo().getLongWidth() == 32) ++HowLong; break; - } case 'W': // This modifier represents int64 type. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); @@ -8719,10 +9043,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Type = Context.getComplexType(ElementType); break; } - case 'Y' : { + case 'Y': Type = Context.getPointerDiffType(); break; - } case 'P': Type = Context.getFILEType(); if (Type.isNull()) { @@ -8767,8 +9090,8 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, char *End; unsigned AddrSpace = strtoul(Str, &End, 10); if (End != Str && AddrSpace != 0) { - Type = Context.getAddrSpaceQualType( - Type, AddrSpace + LangAS::FirstTargetAddressSpace); + Type = Context.getAddrSpaceQualType(Type, + getLangASFromTargetAS(AddrSpace)); Str = End; } if (c == '*') @@ -8860,6 +9183,12 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, if (!FD->isExternallyVisible()) return GVA_Internal; + // Non-user-provided functions get emitted as weak definitions with every + // use, no matter whether they've been explicitly instantiated etc. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) + if (!MD->isUserProvided()) + return GVA_DiscardableODR; + GVALinkage External; switch (FD->getTemplateSpecializationKind()) { case TSK_Undeclared: @@ -8912,7 +9241,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, } static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, - GVALinkage L, const Decl *D) { + const Decl *D, GVALinkage L) { // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx // dllexport/dllimport on inline functions. if (D->hasAttr<DLLImportAttr>()) { @@ -8931,25 +9260,37 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, return L; } -GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { - auto L = adjustGVALinkageForAttributes( - *this, basicGVALinkageForFunction(*this, FD), FD); - auto EK = ExternalASTSource::EK_ReplyHazy; - if (auto *Ext = getExternalSource()) - EK = Ext->hasExternalDefinitions(FD); - switch (EK) { +/// Adjust the GVALinkage for a declaration based on what an external AST source +/// knows about whether there can be other definitions of this declaration. +static GVALinkage +adjustGVALinkageForExternalDefinitionKind(const ASTContext &Ctx, const Decl *D, + GVALinkage L) { + ExternalASTSource *Source = Ctx.getExternalSource(); + if (!Source) + return L; + + switch (Source->hasExternalDefinitions(D)) { case ExternalASTSource::EK_Never: + // Other translation units rely on us to provide the definition. if (L == GVA_DiscardableODR) return GVA_StrongODR; break; + case ExternalASTSource::EK_Always: return GVA_AvailableExternally; + case ExternalASTSource::EK_ReplyHazy: break; } return L; } +GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { + return adjustGVALinkageForExternalDefinitionKind(*this, FD, + adjustGVALinkageForAttributes(*this, FD, + basicGVALinkageForFunction(*this, FD))); +} + static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, const VarDecl *VD) { if (!VD->isExternallyVisible()) @@ -9028,8 +9369,9 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { - return adjustGVALinkageForAttributes( - *this, basicGVALinkageForVariable(*this, VD), VD); + return adjustGVALinkageForExternalDefinitionKind(*this, VD, + adjustGVALinkageForAttributes(*this, VD, + basicGVALinkageForVariable(*this, VD))); } bool ASTContext::DeclMustBeEmitted(const Decl *D) { @@ -9112,9 +9454,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; // Variables that can be needed in other TUs are required. - if (!isDiscardableGVALinkage(GetGVALinkageForVariable(VD))) + auto Linkage = GetGVALinkageForVariable(VD); + if (!isDiscardableGVALinkage(Linkage)) return true; + // We never need to emit a variable that is available in another TU. + if (Linkage == GVA_AvailableExternally) + return false; + // Variables that have destruction with side-effects are required. if (VD->getType().isDestructedType()) return true; @@ -9148,7 +9495,7 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, case LangOptions::DCC_CDecl: return CC_C; case LangOptions::DCC_FastCall: - if (getTargetInfo().hasFeature("sse2")) + if (getTargetInfo().hasFeature("sse2") && !IsVariadic) return CC_X86FastCall; break; case LangOptions::DCC_StdCall: @@ -9160,6 +9507,11 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, if (!IsVariadic) return CC_X86VectorCall; break; + case LangOptions::DCC_RegCall: + // __regcall cannot be applied to variadic functions. + if (!IsVariadic) + return CC_X86RegCall; + break; } return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown); } @@ -9196,7 +9548,7 @@ MangleContext *ASTContext::createMangleContext() { llvm_unreachable("Unsupported ABI"); } -CXXABI::~CXXABI() {} +CXXABI::~CXXABI() = default; size_t ASTContext::getSideTableAllocatedMemory() const { return ASTRecordLayouts.getMemorySize() + @@ -9359,9 +9711,7 @@ bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits); } -namespace { - -ast_type_traits::DynTypedNode getSingleDynTypedNodeFromParentMap( +static ast_type_traits::DynTypedNode getSingleDynTypedNodeFromParentMap( ASTContext::ParentMapPointers::mapped_type U) { if (const auto *D = U.dyn_cast<const Decl *>()) return ast_type_traits::DynTypedNode::create(*D); @@ -9370,6 +9720,8 @@ ast_type_traits::DynTypedNode getSingleDynTypedNodeFromParentMap( return *U.get<ast_type_traits::DynTypedNode *>(); } +namespace { + /// Template specializations to abstract away from pointers and TypeLocs. /// @{ template <typename T> @@ -9410,7 +9762,9 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { } private: - typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase; + friend class RecursiveASTVisitor<ParentMapASTVisitor>; + + using VisitorBase = RecursiveASTVisitor<ParentMapASTVisitor>; ParentMapASTVisitor(ASTContext::ParentMapPointers *Parents, ASTContext::ParentMapOtherNodes *OtherParents) @@ -9419,6 +9773,7 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return true; } @@ -9508,11 +9863,9 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { ASTContext::ParentMapPointers *Parents; ASTContext::ParentMapOtherNodes *OtherParents; llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack; - - friend class RecursiveASTVisitor<ParentMapASTVisitor>; }; -} // anonymous namespace +} // namespace template <typename NodeTy, typename MapTy> static ASTContext::DynTypedNodeList getDynNodeFromMap(const NodeTy &Node, @@ -9568,25 +9921,25 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, if (!hasSameType(DeclVar->getType(), ImplVar->getType())) return false; } + return (MethodDecl->isVariadic() == MethodImpl->isVariadic()); - } uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const { - unsigned AS; + LangAS AS; if (QT->getUnqualifiedDesugaredType()->isNullPtrType()) - AS = 0; + AS = LangAS::Default; else AS = QT->getPointeeType().getAddressSpace(); return getTargetInfo().getNullPointerValue(AS); } -unsigned ASTContext::getTargetAddressSpace(unsigned AS) const { - if (AS >= LangAS::FirstTargetAddressSpace) - return AS - LangAS::FirstTargetAddressSpace; +unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { + if (isTargetAddressSpace(AS)) + return toTargetAddressSpace(AS); else - return (*AddrSpaceMap)[AS]; + return (*AddrSpaceMap)[(unsigned)AS]; } // Explicitly instantiate this in case a Redeclarable<T> is used from a TU that diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp index 92ed7da94d8e8..157b29fd84b6b 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp @@ -537,6 +537,7 @@ namespace { void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(const CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); + void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); void VisitCXXNewExpr(const CXXNewExpr *Node); @@ -1184,7 +1185,7 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { I != E; ++I) dumpCXXCtorInitializer(*I); - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { if (MD->size_overridden_methods() != 0) { auto dumpOverride = [=](const CXXMethodDecl *D) { @@ -1194,16 +1195,18 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { }; dumpChild([=] { - auto FirstOverrideItr = MD->begin_overridden_methods(); + auto Overrides = MD->overridden_methods(); OS << "Overrides: [ "; - dumpOverride(*FirstOverrideItr); + dumpOverride(*Overrides.begin()); for (const auto *Override : - llvm::make_range(FirstOverrideItr + 1, - MD->end_overridden_methods())) + llvm::make_range(Overrides.begin() + 1, Overrides.end())) { + OS << ", "; dumpOverride(Override); + } OS << " ]"; }); } + } if (D->doesThisDeclarationHaveABody()) dumpStmt(D->getBody()); @@ -1313,6 +1316,16 @@ void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { dumpStmt(D->getCombiner()); if (auto *Initializer = D->getInitializer()) { OS << " initializer"; + switch (D->getInitializerKind()) { + case OMPDeclareReductionDecl::DirectInit: + OS << " omp_priv = "; + break; + case OMPDeclareReductionDecl::CopyInit: + OS << " omp_priv ()"; + break; + case OMPDeclareReductionDecl::CallInit: + break; + } dumpStmt(Initializer); } } @@ -1362,6 +1375,128 @@ void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { if (!D->isCompleteDefinition()) return; + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "DefinitionData"; + } +#define FLAG(fn, name) if (D->fn()) OS << " " #name; + FLAG(isParsingBaseSpecifiers, parsing_base_specifiers); + + FLAG(isGenericLambda, generic); + FLAG(isLambda, lambda); + + FLAG(canPassInRegisters, pass_in_registers); + FLAG(isEmpty, empty); + FLAG(isAggregate, aggregate); + FLAG(isStandardLayout, standard_layout); + FLAG(isTriviallyCopyable, trivially_copyable); + FLAG(isPOD, pod); + FLAG(isTrivial, trivial); + FLAG(isPolymorphic, polymorphic); + FLAG(isAbstract, abstract); + FLAG(isLiteral, literal); + + FLAG(hasUserDeclaredConstructor, has_user_declared_ctor); + FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor); + FLAG(hasMutableFields, has_mutable_fields); + FLAG(hasVariantMembers, has_variant_members); + FLAG(allowConstDefaultInit, can_const_default_init); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "DefaultConstructor"; + } + FLAG(hasDefaultConstructor, exists); + FLAG(hasTrivialDefaultConstructor, trivial); + FLAG(hasNonTrivialDefaultConstructor, non_trivial); + FLAG(hasUserProvidedDefaultConstructor, user_provided); + FLAG(hasConstexprDefaultConstructor, constexpr); + FLAG(needsImplicitDefaultConstructor, needs_implicit); + FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr); + }); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "CopyConstructor"; + } + FLAG(hasSimpleCopyConstructor, simple); + FLAG(hasTrivialCopyConstructor, trivial); + FLAG(hasNonTrivialCopyConstructor, non_trivial); + FLAG(hasUserDeclaredCopyConstructor, user_declared); + FLAG(hasCopyConstructorWithConstParam, has_const_param); + FLAG(needsImplicitCopyConstructor, needs_implicit); + FLAG(needsOverloadResolutionForCopyConstructor, + needs_overload_resolution); + if (!D->needsOverloadResolutionForCopyConstructor()) + FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted); + FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param); + }); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "MoveConstructor"; + } + FLAG(hasMoveConstructor, exists); + FLAG(hasSimpleMoveConstructor, simple); + FLAG(hasTrivialMoveConstructor, trivial); + FLAG(hasNonTrivialMoveConstructor, non_trivial); + FLAG(hasUserDeclaredMoveConstructor, user_declared); + FLAG(needsImplicitMoveConstructor, needs_implicit); + FLAG(needsOverloadResolutionForMoveConstructor, + needs_overload_resolution); + if (!D->needsOverloadResolutionForMoveConstructor()) + FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted); + }); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "CopyAssignment"; + } + FLAG(hasTrivialCopyAssignment, trivial); + FLAG(hasNonTrivialCopyAssignment, non_trivial); + FLAG(hasCopyAssignmentWithConstParam, has_const_param); + FLAG(hasUserDeclaredCopyAssignment, user_declared); + FLAG(needsImplicitCopyAssignment, needs_implicit); + FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution); + FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param); + }); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "MoveAssignment"; + } + FLAG(hasMoveAssignment, exists); + FLAG(hasSimpleMoveAssignment, simple); + FLAG(hasTrivialMoveAssignment, trivial); + FLAG(hasNonTrivialMoveAssignment, non_trivial); + FLAG(hasUserDeclaredMoveAssignment, user_declared); + FLAG(needsImplicitMoveAssignment, needs_implicit); + FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution); + }); + + dumpChild([=] { + { + ColorScope Color(*this, DeclKindNameColor); + OS << "Destructor"; + } + FLAG(hasSimpleDestructor, simple); + FLAG(hasIrrelevantDestructor, irrelevant); + FLAG(hasTrivialDestructor, trivial); + FLAG(hasNonTrivialDestructor, non_trivial); + FLAG(hasUserDeclaredDestructor, user_declared); + FLAG(needsImplicitDestructor, needs_implicit); + FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution); + if (!D->needsOverloadResolutionForDestructor()) + FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted); + }); + }); + for (const auto &I : D->bases()) { dumpChild([=] { if (I.isVirtual()) @@ -2166,12 +2301,24 @@ void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) { << " <" << Node->getCastKindName() << ">"; } +void ASTDumper::VisitCXXUnresolvedConstructExpr( + const CXXUnresolvedConstructExpr *Node) { + VisitExpr(Node); + dumpType(Node->getTypeAsWritten()); + if (Node->isListInitialization()) + OS << " list"; +} + void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) { VisitExpr(Node); CXXConstructorDecl *Ctor = Node->getConstructor(); dumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; + if (Node->isListInitialization()) + OS << " list"; + if (Node->isStdInitListInitialization()) + OS << " std::initializer_list"; if (Node->requiresZeroInitialization()) OS << " zeroing"; } diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index 2c0bb11cc4bc3..84b0d7ecff93f 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -58,7 +58,7 @@ namespace clang { QualType VisitExtVectorType(const ExtVectorType *T); QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T); QualType VisitFunctionProtoType(const FunctionProtoType *T); - // FIXME: UnresolvedUsingType + QualType VisitUnresolvedUsingType(const UnresolvedUsingType *T); QualType VisitParenType(const ParenType *T); QualType VisitTypedefType(const TypedefType *T); QualType VisitTypeOfExprType(const TypeOfExprType *T); @@ -77,6 +77,7 @@ namespace clang { QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T); QualType VisitElaboratedType(const ElaboratedType *T); // FIXME: DependentNameType + QualType VisitPackExpansionType(const PackExpansionType *T); // FIXME: DependentTemplateSpecializationType QualType VisitObjCInterfaceType(const ObjCInterfaceType *T); QualType VisitObjCObjectType(const ObjCObjectType *T); @@ -128,27 +129,35 @@ namespace clang { TemplateParameterList *ImportTemplateParameterList( TemplateParameterList *Params); TemplateArgument ImportTemplateArgument(const TemplateArgument &From); - TemplateArgumentLoc ImportTemplateArgumentLoc( - const TemplateArgumentLoc &TALoc, bool &Error); + Optional<TemplateArgumentLoc> ImportTemplateArgumentLoc( + const TemplateArgumentLoc &TALoc); bool ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl<TemplateArgument> &ToArgs); + template <typename InContainerTy> + bool ImportTemplateArgumentListInfo(const InContainerTy &Container, + TemplateArgumentListInfo &ToTAInfo); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); + bool IsStructuralMatch(FunctionTemplateDecl *From, + FunctionTemplateDecl *To); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); + Decl *VisitEmptyDecl(EmptyDecl *D); Decl *VisitAccessSpecDecl(AccessSpecDecl *D); Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias); Decl *VisitTypedefDecl(TypedefDecl *D); Decl *VisitTypeAliasDecl(TypeAliasDecl *D); + Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); Decl *VisitLabelDecl(LabelDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitRecordDecl(RecordDecl *D); @@ -170,6 +179,12 @@ namespace clang { Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); + Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); @@ -185,6 +200,7 @@ namespace clang { ClassTemplateSpecializationDecl *D); Decl *VisitVarTemplateDecl(VarTemplateDecl *D); Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); // Importing statements DeclGroupRef ImportDeclGroup(DeclGroupRef DG); @@ -265,13 +281,16 @@ namespace clang { Expr *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); Expr *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *CE); Expr *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); + Expr *VisitPackExpansionExpr(PackExpansionExpr *E); Expr *VisitCXXNewExpr(CXXNewExpr *CE); Expr *VisitCXXDeleteExpr(CXXDeleteExpr *E); Expr *VisitCXXConstructExpr(CXXConstructExpr *E); Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E); + Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); Expr *VisitExprWithCleanups(ExprWithCleanups *EWC); Expr *VisitCXXThisExpr(CXXThisExpr *E); Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); + Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); Expr *VisitMemberExpr(MemberExpr *E); Expr *VisitCallExpr(CallExpr *E); Expr *VisitInitListExpr(InitListExpr *E); @@ -280,6 +299,7 @@ namespace clang { Expr *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E); Expr *VisitCXXNamedCastExpr(CXXNamedCastExpr *E); Expr *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E); + Expr *VisitTypeTraitExpr(TypeTraitExpr *E); template<typename IIter, typename OIter> @@ -566,6 +586,22 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI); } +QualType ASTNodeImporter::VisitUnresolvedUsingType( + const UnresolvedUsingType *T) { + UnresolvedUsingTypenameDecl *ToD = cast_or_null<UnresolvedUsingTypenameDecl>( + Importer.Import(T->getDecl())); + if (!ToD) + return QualType(); + + UnresolvedUsingTypenameDecl *ToPrevD = + cast_or_null<UnresolvedUsingTypenameDecl>( + Importer.Import(T->getDecl()->getPreviousDecl())); + if (!ToPrevD && T->getDecl()->getPreviousDecl()) + return QualType(); + + return Importer.getToContext().getTypeDeclType(ToD, ToPrevD); +} + QualType ASTNodeImporter::VisitParenType(const ParenType *T) { QualType ToInnerType = Importer.Import(T->getInnerType()); if (ToInnerType.isNull()) @@ -767,6 +803,15 @@ QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { ToQualifier, ToNamedType); } +QualType ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) { + QualType Pattern = Importer.Import(T->getPattern()); + if (Pattern.isNull()) + return QualType(); + + return Importer.getToContext().getPackExpansionType(Pattern, + T->getNumExpansions()); +} + QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); @@ -1171,9 +1216,8 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { llvm_unreachable("Invalid template argument kind"); } -TemplateArgumentLoc ASTNodeImporter::ImportTemplateArgumentLoc( - const TemplateArgumentLoc &TALoc, bool &Error) { - Error = false; +Optional<TemplateArgumentLoc> +ASTNodeImporter::ImportTemplateArgumentLoc(const TemplateArgumentLoc &TALoc) { TemplateArgument Arg = ImportTemplateArgument(TALoc.getArgument()); TemplateArgumentLocInfo FromInfo = TALoc.getLocInfo(); TemplateArgumentLocInfo ToInfo; @@ -1181,12 +1225,12 @@ TemplateArgumentLoc ASTNodeImporter::ImportTemplateArgumentLoc( Expr *E = Importer.Import(FromInfo.getAsExpr()); ToInfo = TemplateArgumentLocInfo(E); if (!E) - Error = true; + return None; } else if (Arg.getKind() == TemplateArgument::Type) { if (TypeSourceInfo *TSI = Importer.Import(FromInfo.getAsTypeSourceInfo())) ToInfo = TemplateArgumentLocInfo(TSI); else - Error = true; + return None; } else { ToInfo = TemplateArgumentLocInfo( Importer.Import(FromInfo.getTemplateQualifierLoc()), @@ -1210,6 +1254,18 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, return false; } +template <typename InContainerTy> +bool ASTNodeImporter::ImportTemplateArgumentListInfo( + const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { + for (const auto &FromLoc : Container) { + if (auto ToLoc = ImportTemplateArgumentLoc(FromLoc)) + ToTAInfo.addArgument(*ToLoc); + else + return true; + } + return false; +} + bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { // Eliminate a potential failure point where we attempt to re-import @@ -1243,6 +1299,14 @@ bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum); } +bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, + FunctionTemplateDecl *To) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), false, false); + return Ctx.IsStructurallyEquivalent(From, To); +} + bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC) { @@ -1276,6 +1340,29 @@ Decl *ASTNodeImporter::VisitDecl(Decl *D) { return nullptr; } +Decl *ASTNodeImporter::VisitEmptyDecl(EmptyDecl *D) { + // Import the context of this declaration. + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return nullptr; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return nullptr; + } + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + EmptyDecl *ToD = EmptyDecl::Create(Importer.getToContext(), DC, Loc); + ToD->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToD); + LexicalDC->addDeclInternal(ToD); + return ToD; +} + Decl *ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { TranslationUnitDecl *ToD = Importer.getToContext().getTranslationUnitDecl(); @@ -1410,6 +1497,44 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { return ToNamespace; } +Decl *ASTNodeImporter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + // Import the major distinguishing characteristics of this namespace. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *LookupD; + if (ImportDeclParts(D, DC, LexicalDC, Name, LookupD, Loc)) + return nullptr; + if (LookupD) + return LookupD; + + // NOTE: No conflict resolution is done for namespace aliases now. + + NamespaceDecl *TargetDecl = cast_or_null<NamespaceDecl>( + Importer.Import(D->getNamespace())); + if (!TargetDecl) + return nullptr; + + IdentifierInfo *ToII = Importer.Import(D->getIdentifier()); + if (!ToII) + return nullptr; + + NestedNameSpecifierLoc ToQLoc = Importer.Import(D->getQualifierLoc()); + if (D->getQualifierLoc() && !ToQLoc) + return nullptr; + + NamespaceAliasDecl *ToD = NamespaceAliasDecl::Create( + Importer.getToContext(), DC, Importer.Import(D->getNamespaceLoc()), + Importer.Import(D->getAliasLoc()), ToII, ToQLoc, + Importer.Import(D->getTargetNameLoc()), TargetDecl); + + ToD->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToD); + LexicalDC->addDeclInternal(ToD); + + return ToD; +} + Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { // Import the major distinguishing characteristics of this typedef. DeclContext *DC, *LexicalDC; @@ -1487,6 +1612,63 @@ Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) { return VisitTypedefNameDecl(D, /*IsAlias=*/true); } +Decl *ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + // Import the major distinguishing characteristics of this typedef. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + // If this typedef is not in block scope, determine whether we've + // seen a typedef with the same name (that we can merge with) or any + // other entity by that name (which name lookup could conflict with). + if (!DC->isFunctionOrMethod()) { + SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + continue; + if (auto *FoundAlias = + dyn_cast<TypeAliasTemplateDecl>(FoundDecls[I])) + return Importer.Imported(D, FoundAlias); + ConflictingDecls.push_back(FoundDecls[I]); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return nullptr; + } + } + + TemplateParameterList *Params = ImportTemplateParameterList( + D->getTemplateParameters()); + if (!Params) + return nullptr; + + NamedDecl *TemplDecl = cast_or_null<NamedDecl>( + Importer.Import(D->getTemplatedDecl())); + if (!TemplDecl) + return nullptr; + + TypeAliasTemplateDecl *ToAlias = TypeAliasTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, Params, TemplDecl); + + ToAlias->setAccess(D->getAccess()); + ToAlias->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToAlias); + LexicalDC->addDeclInternal(ToAlias); + return ToD; +} + Decl *ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { // Import the major distinguishing characteristics of this label. DeclContext *DC, *LexicalDC; @@ -1752,6 +1934,31 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } D2 = D2CXX; D2->setAccess(D->getAccess()); + + Importer.Imported(D, D2); + + if (ClassTemplateDecl *FromDescribed = + DCXX->getDescribedClassTemplate()) { + ClassTemplateDecl *ToDescribed = cast_or_null<ClassTemplateDecl>( + Importer.Import(FromDescribed)); + if (!ToDescribed) + return nullptr; + D2CXX->setDescribedClassTemplate(ToDescribed); + + } else if (MemberSpecializationInfo *MemberInfo = + DCXX->getMemberSpecializationInfo()) { + TemplateSpecializationKind SK = + MemberInfo->getTemplateSpecializationKind(); + CXXRecordDecl *FromInst = DCXX->getInstantiatedFromMemberClass(); + CXXRecordDecl *ToInst = + cast_or_null<CXXRecordDecl>(Importer.Import(FromInst)); + if (FromInst && !ToInst) + return nullptr; + D2CXX->setInstantiationOfMemberClass(ToInst, SK); + D2CXX->getMemberSpecializationInfo()->setPointOfInstantiation( + Importer.Import(MemberInfo->getPointOfInstantiation())); + } + } else { D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc, Name.getAsIdentifierInfo()); @@ -1846,6 +2053,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ToD) return ToD; + const FunctionDecl *FoundWithoutBody = nullptr; + // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. if (!LexicalDC->isFunctionOrMethod()) { @@ -1863,6 +2072,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { // FIXME: Actually try to merge the body and other attributes. + const FunctionDecl *FromBodyDecl = nullptr; + D->hasBody(FromBodyDecl); + if (D == FromBodyDecl && !FoundFunction->hasBody()) { + // This function is needed to merge completely. + FoundWithoutBody = FoundFunction; + break; + } return Importer.Imported(D, FoundFunction); } @@ -2013,6 +2229,12 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } ToFunction->setParams(Parameters); + if (FoundWithoutBody) { + auto *Recent = const_cast<FunctionDecl *>( + FoundWithoutBody->getMostRecentDecl()); + ToFunction->setPreviousDecl(Recent); + } + if (usedDifferentExceptionSpec) { // Update FunctionProtoType::ExtProtoInfo. QualType T = Importer.Import(D->getType()); @@ -2876,6 +3098,178 @@ Decl *ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { return ToLinkageSpec; } +Decl *ASTNodeImporter::VisitUsingDecl(UsingDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + DeclarationNameInfo NameInfo(Name, + Importer.Import(D->getNameInfo().getLoc())); + ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + + UsingDecl *ToUsing = UsingDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getUsingLoc()), + Importer.Import(D->getQualifierLoc()), + NameInfo, D->hasTypename()); + ToUsing->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToUsing); + Importer.Imported(D, ToUsing); + + if (NamedDecl *FromPattern = + Importer.getFromContext().getInstantiatedFromUsingDecl(D)) { + if (NamedDecl *ToPattern = + dyn_cast_or_null<NamedDecl>(Importer.Import(FromPattern))) + Importer.getToContext().setInstantiatedFromUsingDecl(ToUsing, ToPattern); + else + return nullptr; + } + + for (UsingShadowDecl *FromShadow : D->shadows()) { + if (UsingShadowDecl *ToShadow = + dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromShadow))) + ToUsing->addShadowDecl(ToShadow); + else + // FIXME: We return a nullptr here but the definition is already created + // and available with lookups. How to fix this?.. + return nullptr; + } + return ToUsing; +} + +Decl *ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + UsingDecl *ToUsing = dyn_cast_or_null<UsingDecl>( + Importer.Import(D->getUsingDecl())); + if (!ToUsing) + return nullptr; + + NamedDecl *ToTarget = dyn_cast_or_null<NamedDecl>( + Importer.Import(D->getTargetDecl())); + if (!ToTarget) + return nullptr; + + UsingShadowDecl *ToShadow = UsingShadowDecl::Create( + Importer.getToContext(), DC, Loc, ToUsing, ToTarget); + + ToShadow->setLexicalDeclContext(LexicalDC); + ToShadow->setAccess(D->getAccess()); + Importer.Imported(D, ToShadow); + + if (UsingShadowDecl *FromPattern = + Importer.getFromContext().getInstantiatedFromUsingShadowDecl(D)) { + if (UsingShadowDecl *ToPattern = + dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromPattern))) + Importer.getToContext().setInstantiatedFromUsingShadowDecl(ToShadow, + ToPattern); + else + // FIXME: We return a nullptr here but the definition is already created + // and available with lookups. How to fix this?.. + return nullptr; + } + + LexicalDC->addDeclInternal(ToShadow); + + return ToShadow; +} + + +Decl *ASTNodeImporter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + DeclContext *ToComAncestor = Importer.ImportContext(D->getCommonAncestor()); + if (!ToComAncestor) + return nullptr; + + NamespaceDecl *ToNominated = cast_or_null<NamespaceDecl>( + Importer.Import(D->getNominatedNamespace())); + if (!ToNominated) + return nullptr; + + UsingDirectiveDecl *ToUsingDir = UsingDirectiveDecl::Create( + Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), + Importer.Import(D->getNamespaceKeyLocation()), + Importer.Import(D->getQualifierLoc()), + Importer.Import(D->getIdentLocation()), ToNominated, ToComAncestor); + ToUsingDir->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToUsingDir); + Importer.Imported(D, ToUsingDir); + + return ToUsingDir; +} + +Decl *ASTNodeImporter::VisitUnresolvedUsingValueDecl( + UnresolvedUsingValueDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + DeclarationNameInfo NameInfo(Name, Importer.Import(D->getNameInfo().getLoc())); + ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + + UnresolvedUsingValueDecl *ToUsingValue = UnresolvedUsingValueDecl::Create( + Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), + Importer.Import(D->getQualifierLoc()), NameInfo, + Importer.Import(D->getEllipsisLoc())); + + Importer.Imported(D, ToUsingValue); + ToUsingValue->setAccess(D->getAccess()); + ToUsingValue->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToUsingValue); + + return ToUsingValue; +} + +Decl *ASTNodeImporter::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + if (ToD) + return ToD; + + UnresolvedUsingTypenameDecl *ToUsing = UnresolvedUsingTypenameDecl::Create( + Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), + Importer.Import(D->getTypenameLoc()), + Importer.Import(D->getQualifierLoc()), Loc, Name, + Importer.Import(D->getEllipsisLoc())); + + Importer.Imported(D, ToUsing); + ToUsing->setAccess(D->getAccess()); + ToUsing->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToUsing); + + return ToUsing; +} + + bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) { @@ -3453,7 +3847,6 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl *DTemplated = D->getTemplatedDecl(); // Create the declaration that is being templated. - // Create the declaration that is being templated. CXXRecordDecl *D2Templated = cast_or_null<CXXRecordDecl>( Importer.Import(DTemplated)); if (!D2Templated) @@ -3560,11 +3953,10 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( TemplateArgumentListInfo ToTAInfo; auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) { - bool Error = false; - auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I], Error); - if (Error) + if (auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I])) + ToTAInfo.addArgument(*ToLoc); + else return nullptr; - ToTAInfo.addArgument(ToLoc); } QualType CanonInjType = Importer.Import( @@ -3832,6 +4224,64 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( return D2; } +Decl *ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD; + + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return nullptr; + + if (ToD) + return ToD; + + // Try to find a function in our own ("to") context with the same name, same + // type, and in the same context as the function we're importing. + if (!LexicalDC->isFunctionOrMethod()) { + unsigned IDNS = Decl::IDNS_Ordinary; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + continue; + + if (FunctionTemplateDecl *FoundFunction = + dyn_cast<FunctionTemplateDecl>(FoundDecls[I])) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { + if (IsStructuralMatch(D, FoundFunction)) { + Importer.Imported(D, FoundFunction); + // FIXME: Actually try to merge the body and other attributes. + return FoundFunction; + } + } + } + } + } + + TemplateParameterList *Params = + ImportTemplateParameterList(D->getTemplateParameters()); + if (!Params) + return nullptr; + + FunctionDecl *TemplatedFD = + cast_or_null<FunctionDecl>(Importer.Import(D->getTemplatedDecl())); + if (!TemplatedFD) + return nullptr; + + FunctionTemplateDecl *ToFunc = FunctionTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, Params, TemplatedFD); + + TemplatedFD->setDescribedFunctionTemplate(ToFunc); + ToFunc->setAccess(D->getAccess()); + ToFunc->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToFunc); + + LexicalDC->addDeclInternal(ToFunc); + return ToFunc; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- @@ -3968,12 +4418,16 @@ Stmt *ASTNodeImporter::VisitCaseStmt(CaseStmt *S) { Expr *ToRHS = Importer.Import(S->getRHS()); if (!ToRHS && S->getRHS()) return nullptr; + Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); + if (!ToSubStmt && S->getSubStmt()) + return nullptr; SourceLocation ToCaseLoc = Importer.Import(S->getCaseLoc()); SourceLocation ToEllipsisLoc = Importer.Import(S->getEllipsisLoc()); SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); - return new (Importer.getToContext()) CaseStmt(ToLHS, ToRHS, - ToCaseLoc, ToEllipsisLoc, - ToColonLoc); + CaseStmt *ToStmt = new (Importer.getToContext()) + CaseStmt(ToLHS, ToRHS, ToCaseLoc, ToEllipsisLoc, ToColonLoc); + ToStmt->setSubStmt(ToSubStmt); + return ToStmt; } Stmt *ASTNodeImporter::VisitDefaultStmt(DefaultStmt *S) { @@ -4443,11 +4897,10 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { for (const auto &FromLoc : E->template_arguments()) { - bool Error = false; - TemplateArgumentLoc ToTALoc = ImportTemplateArgumentLoc(FromLoc, Error); - if (Error) + if (auto ToTALoc = ImportTemplateArgumentLoc(FromLoc)) + ToTAInfo.addArgument(*ToTALoc); + else return nullptr; - ToTAInfo.addArgument(ToTALoc); } ResInfo = &ToTAInfo; } @@ -5161,6 +5614,20 @@ ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { return ToMTE; } +Expr *ASTNodeImporter::VisitPackExpansionExpr(PackExpansionExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *Pattern = Importer.Import(E->getPattern()); + if (!Pattern) + return nullptr; + + return new (Importer.getToContext()) PackExpansionExpr( + T, Pattern, Importer.Import(E->getEllipsisLoc()), + E->getNumExpansions()); +} + Expr *ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *CE) { QualType T = Importer.Import(CE->getType()); if (T.isNull()) @@ -5344,6 +5811,80 @@ Expr *ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { E->getObjectKind()); } +Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr( + CXXPseudoDestructorExpr *E) { + + Expr *BaseE = Importer.Import(E->getBase()); + if (!BaseE) + return nullptr; + + TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo()); + if (!ScopeInfo && E->getScopeTypeInfo()) + return nullptr; + + PseudoDestructorTypeStorage Storage; + if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { + IdentifierInfo *ToII = Importer.Import(FromII); + if (!ToII) + return nullptr; + Storage = PseudoDestructorTypeStorage( + ToII, Importer.Import(E->getDestroyedTypeLoc())); + } else { + TypeSourceInfo *TI = Importer.Import(E->getDestroyedTypeInfo()); + if (!TI) + return nullptr; + Storage = PseudoDestructorTypeStorage(TI); + } + + return new (Importer.getToContext()) CXXPseudoDestructorExpr( + Importer.getToContext(), BaseE, E->isArrow(), + Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getQualifierLoc()), + ScopeInfo, Importer.Import(E->getColonColonLoc()), + Importer.Import(E->getTildeLoc()), Storage); +} + +Expr *ASTNodeImporter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + Expr *Base = nullptr; + if (!E->isImplicitAccess()) { + Base = Importer.Import(E->getBase()); + if (!Base) + return nullptr; + } + + QualType BaseType = Importer.Import(E->getBaseType()); + if (BaseType.isNull()) + return nullptr; + + TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()), + Importer.Import(E->getRAngleLoc())); + TemplateArgumentListInfo *ResInfo = nullptr; + if (E->hasExplicitTemplateArgs()) { + if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + return nullptr; + ResInfo = &ToTAInfo; + } + + DeclarationName Name = Importer.Import(E->getMember()); + if (!E->getMember().isEmpty() && Name.isEmpty()) + return nullptr; + + DeclarationNameInfo MemberNameInfo(Name, Importer.Import(E->getMemberLoc())); + // Import additional name location/type info. + ImportDeclarationNameLoc(E->getMemberNameInfo(), MemberNameInfo); + auto ToFQ = Importer.Import(E->getFirstQualifierFoundInScope()); + if (!ToFQ && E->getFirstQualifierFoundInScope()) + return nullptr; + + return CXXDependentScopeMemberExpr::Create( + Importer.getToContext(), Base, BaseType, E->isArrow(), + Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getQualifierLoc()), + Importer.Import(E->getTemplateKeywordLoc()), + cast_or_null<NamedDecl>(ToFQ), MemberNameInfo, ResInfo); +} + Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -5510,6 +6051,26 @@ Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr( Replacement); } +Expr *ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) { + QualType ToType = Importer.Import(E->getType()); + if (ToType.isNull()) + return nullptr; + + SmallVector<TypeSourceInfo *, 4> ToArgs(E->getNumArgs()); + if (ImportContainerChecked(E->getArgs(), ToArgs)) + return nullptr; + + // According to Sema::BuildTypeTrait(), if E is value-dependent, + // Value is always false. + bool ToValue = false; + if (!E->isValueDependent()) + ToValue = E->getValue(); + + return TypeTraitExpr::Create( + Importer.getToContext(), ToType, Importer.Import(E->getLocStart()), + E->getTrait(), ToArgs, Importer.Import(E->getLocEnd()), ToValue); +} + void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod) { for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) diff --git a/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp index ea7faab767edf..0df8e5653f3b5 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -365,6 +365,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *DepAddressSpace1 = + cast<DependentAddressSpaceType>(T1); + const DependentAddressSpaceType *DepAddressSpace2 = + cast<DependentAddressSpaceType>(T2); + if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(), + DepAddressSpace2->getAddrSpaceExpr())) + return false; + if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(), + DepAddressSpace2->getPointeeType())) + return false; + + break; + } + case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *Vec1 = cast<DependentSizedExtVectorType>(T1); diff --git a/contrib/llvm/tools/clang/lib/AST/CXXABI.h b/contrib/llvm/tools/clang/lib/AST/CXXABI.h index 924ef00e8147a..06295b58178bf 100644 --- a/contrib/llvm/tools/clang/lib/AST/CXXABI.h +++ b/contrib/llvm/tools/clang/lib/AST/CXXABI.h @@ -31,9 +31,16 @@ class CXXABI { public: virtual ~CXXABI(); - /// Returns the width and alignment of a member pointer in bits. - virtual std::pair<uint64_t, unsigned> - getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0; + struct MemberPointerInfo { + uint64_t Width; + unsigned Align; + bool HasPadding; + }; + + /// Returns the width and alignment of a member pointer in bits, as well as + /// whether it has padding. + virtual MemberPointerInfo + getMemberPointerInfo(const MemberPointerType *MPT) const = 0; /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; diff --git a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp index fc4d8b137337f..24e96ba38015c 100644 --- a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp +++ b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp @@ -1,4 +1,4 @@ -//===------ CXXInheritance.cpp - C++ Inheritance ----------------*- C++ -*-===// +//===- CXXInheritance.cpp - C++ Inheritance -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,27 @@ // This file provides routines that help analyzing C++ inheritance hierarchies. // //===----------------------------------------------------------------------===// + #include "clang/AST/CXXInheritance.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include <algorithm> +#include <utility> +#include <cassert> +#include <vector> using namespace clang; @@ -26,7 +40,7 @@ void CXXBasePaths::ComputeDeclsFound() { assert(NumDeclsFound == 0 && !DeclsFound && "Already computed the set of declarations"); - llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls; + llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8>> Decls; for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path) Decls.insert(Path->Decls.front()); @@ -419,8 +433,8 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path, DeclarationName Name) { - const unsigned IDNS = clang::Decl::IDNS_Ordinary | clang::Decl::IDNS_Tag | - clang::Decl::IDNS_Member; + const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | + Decl::IDNS_Member; for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); Path.Decls = Path.Decls.slice(1)) { @@ -550,26 +564,27 @@ void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) { } } - namespace { - class FinalOverriderCollector { - /// \brief The number of subobjects of a given class type that - /// occur within the class hierarchy. - llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount; - /// \brief Overriders for each virtual base subobject. - llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders; +class FinalOverriderCollector { + /// \brief The number of subobjects of a given class type that + /// occur within the class hierarchy. + llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount; - CXXFinalOverriderMap FinalOverriders; + /// \brief Overriders for each virtual base subobject. + llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders; - public: - ~FinalOverriderCollector(); + CXXFinalOverriderMap FinalOverriders; - void Collect(const CXXRecordDecl *RD, bool VirtualBase, - const CXXRecordDecl *InVirtualSubobject, - CXXFinalOverriderMap &Overriders); - }; -} +public: + ~FinalOverriderCollector(); + + void Collect(const CXXRecordDecl *RD, bool VirtualBase, + const CXXRecordDecl *InVirtualSubobject, + CXXFinalOverriderMap &Overriders); +}; + +} // namespace void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, bool VirtualBase, @@ -635,9 +650,11 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, continue; CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); + using OverriddenMethodsRange = + llvm::iterator_range<CXXMethodDecl::method_iterator>; + OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods(); - if (CanonM->begin_overridden_methods() - == CanonM->end_overridden_methods()) { + if (OverriddenMethods.begin() == OverriddenMethods.end()) { // This is a new virtual function that does not override any // other virtual function. Add it to the map of virtual // functions for which we are tracking overridders. @@ -656,11 +673,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, // overrider. To do so, we dig down to the original virtual // functions using data recursion and update all of the methods it // overrides. - typedef llvm::iterator_range<CXXMethodDecl::method_iterator> - OverriddenMethods; - SmallVector<OverriddenMethods, 4> Stack; - Stack.push_back(llvm::make_range(CanonM->begin_overridden_methods(), - CanonM->end_overridden_methods())); + SmallVector<OverriddenMethodsRange, 4> Stack(1, OverriddenMethods); while (!Stack.empty()) { for (const CXXMethodDecl *OM : Stack.pop_back_val()) { const CXXMethodDecl *CanonOM = OM->getCanonicalDecl(); @@ -678,14 +691,13 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); - if (CanonOM->begin_overridden_methods() - == CanonOM->end_overridden_methods()) + auto OverriddenMethods = CanonOM->overridden_methods(); + if (OverriddenMethods.begin() == OverriddenMethods.end()) continue; // Continue recursion to the methods that this virtual method // overrides. - Stack.push_back(llvm::make_range(CanonOM->begin_overridden_methods(), - CanonOM->end_overridden_methods())); + Stack.push_back(OverriddenMethods); } } diff --git a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp index 403454d3ab7e6..6c2019e1a72b6 100644 --- a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp +++ b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp @@ -813,7 +813,7 @@ bool Sema::isAnyFunctionDecl() { } bool Sema::isFunctionOrMethodVariadic() { - if (!isAnyFunctionDecl() && !isObjCMethodDecl() && !isFunctionTemplateDecl()) + if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl) return false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) @@ -824,6 +824,14 @@ bool Sema::isFunctionOrMethodVariadic() { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) return MD->isVariadic(); + if (const TypedefNameDecl *TD = + dyn_cast<TypedefNameDecl>(ThisDeclInfo->CurrentDecl)) { + QualType Type = TD->getUnderlyingType(); + if (Type->isFunctionPointerType() || Type->isBlockPointerType()) + Type = Type->getPointeeType(); + if (const auto *FT = Type->getAs<FunctionProtoType>()) + return FT->isVariadic(); + } return false; } diff --git a/contrib/llvm/tools/clang/lib/AST/DataCollection.cpp b/contrib/llvm/tools/clang/lib/AST/DataCollection.cpp new file mode 100644 index 0000000000000..c2ecabe8e6f8a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DataCollection.cpp @@ -0,0 +1,50 @@ +//===-- DataCollection.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DataCollection.h" + +#include "clang/Lex/Lexer.h" + +namespace clang { +namespace data_collection { + +/// Prints the macro name that contains the given SourceLocation into the given +/// raw_string_ostream. +static void printMacroName(llvm::raw_string_ostream &MacroStack, + ASTContext &Context, SourceLocation Loc) { + MacroStack << Lexer::getImmediateMacroName(Loc, Context.getSourceManager(), + Context.getLangOpts()); + + // Add an empty space at the end as a padding to prevent + // that macro names concatenate to the names of other macros. + MacroStack << " "; +} + +/// Returns a string that represents all macro expansions that expanded into the +/// given SourceLocation. +/// +/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations +/// A and B are expanded from the same macros in the same order. +std::string getMacroStack(SourceLocation Loc, ASTContext &Context) { + std::string MacroStack; + llvm::raw_string_ostream MacroStackStream(MacroStack); + SourceManager &SM = Context.getSourceManager(); + + // Iterate over all macros that expanded into the given SourceLocation. + while (Loc.isMacroID()) { + // Add the macro name to the stream. + printMacroName(MacroStackStream, Context, Loc); + Loc = SM.getImmediateMacroCallerLoc(Loc); + } + MacroStackStream.flush(); + return MacroStack; +} + +} // end namespace data_collection +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp index 573a98efe980b..2f51ec31a7bdc 100644 --- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Decl.cpp @@ -1,4 +1,4 @@ -//===--- Decl.cpp - Declaration AST Node Implementation -------------------===// +//===- Decl.cpp - Declaration AST Node Implementation ---------------------===// // // The LLVM Compiler Infrastructure // @@ -12,27 +12,62 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Decl.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" -#include "clang/AST/Attr.h" +#include "clang/AST/CanonicalType.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Redeclarable.h" #include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Linkage.h" #include "clang/Basic/Module.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SanitizerBlacklist.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Visibility.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <memory> +#include <string> +#include <tuple> +#include <type_traits> using namespace clang; @@ -47,7 +82,7 @@ bool Decl::isOutOfLine() const { TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx) : Decl(TranslationUnit, nullptr, SourceLocation()), - DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {} + DeclContext(TranslationUnit), Ctx(ctx) {} //===----------------------------------------------------------------------===// // NamedDecl Implementation @@ -99,63 +134,25 @@ TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx) // and 'matcher' is a type only matters when looking for attributes // and settings from the immediate context. -const unsigned IgnoreExplicitVisibilityBit = 2; -const unsigned IgnoreAllVisibilityBit = 4; - -/// Kinds of LV computation. The linkage side of the computation is -/// always the same, but different things can change how visibility is -/// computed. -enum LVComputationKind { - /// Do an LV computation for, ultimately, a type. - /// Visibility may be restricted by type visibility settings and - /// the visibility of template arguments. - LVForType = NamedDecl::VisibilityForType, - - /// Do an LV computation for, ultimately, a non-type declaration. - /// Visibility may be restricted by value visibility settings and - /// the visibility of template arguments. - LVForValue = NamedDecl::VisibilityForValue, - - /// Do an LV computation for, ultimately, a type that already has - /// some sort of explicit visibility. Visibility may only be - /// restricted by the visibility of template arguments. - LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit), - - /// Do an LV computation for, ultimately, a non-type declaration - /// that already has some sort of explicit visibility. Visibility - /// may only be restricted by the visibility of template arguments. - LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), - - /// Do an LV computation when we only care about the linkage. - LVForLinkageOnly = - LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit -}; - /// Does this computation kind permit us to consider additional /// visibility settings from attributes and the like? static bool hasExplicitVisibilityAlready(LVComputationKind computation) { - return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0); + return computation.IgnoreExplicitVisibility; } /// Given an LVComputationKind, return one of the same type/value sort /// that records that it already has explicit visibility. static LVComputationKind -withExplicitVisibilityAlready(LVComputationKind oldKind) { - LVComputationKind newKind = - static_cast<LVComputationKind>(unsigned(oldKind) | - IgnoreExplicitVisibilityBit); - assert(oldKind != LVForType || newKind == LVForExplicitType); - assert(oldKind != LVForValue || newKind == LVForExplicitValue); - assert(oldKind != LVForExplicitType || newKind == LVForExplicitType); - assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue); - return newKind; +withExplicitVisibilityAlready(LVComputationKind Kind) { + Kind.IgnoreExplicitVisibility = true; + return Kind; } static Optional<Visibility> getExplicitVisibility(const NamedDecl *D, LVComputationKind kind) { - assert(!hasExplicitVisibilityAlready(kind) && + assert(!kind.IgnoreExplicitVisibility && "asking for explicit visibility when we shouldn't be"); - return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind); + return D->getExplicitVisibility(kind.getExplicitVisibilityKind()); } /// Is the given declaration a "type" or a "value" for the purposes of @@ -216,30 +213,21 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D, return getVisibilityFromAttr(A); } - // If we're on Mac OS X, an 'availability' for Mac OS X attribute - // implies visibility(default). - if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) { - for (const auto *A : D->specific_attrs<AvailabilityAttr>()) - if (A->getPlatform()->getName().equals("macos")) - return DefaultVisibility; - } - return None; } -static LinkageInfo -getLVForType(const Type &T, LVComputationKind computation) { - if (computation == LVForLinkageOnly) +LinkageInfo LinkageComputer::getLVForType(const Type &T, + LVComputationKind computation) { + if (computation.IgnoreAllVisibility) return LinkageInfo(T.getLinkage(), DefaultVisibility, true); - return T.getLinkageAndVisibility(); + return getTypeLinkageAndVisibility(&T); } /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. For visibility purposes, template /// parameters are part of the signature of a template. -static LinkageInfo -getLVForTemplateParameterList(const TemplateParameterList *Params, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForTemplateParameterList( + const TemplateParameterList *Params, LVComputationKind computation) { LinkageInfo LV; for (const NamedDecl *P : *Params) { // Template type parameters are the most common and never @@ -264,7 +252,7 @@ getLVForTemplateParameterList(const TemplateParameterList *Params, for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) { QualType type = NTTP->getExpansionType(i); if (!type->isDependentType()) - LV.merge(type->getLinkageAndVisibility()); + LV.merge(getTypeLinkageAndVisibility(type)); } continue; } @@ -291,10 +279,6 @@ getLVForTemplateParameterList(const TemplateParameterList *Params, return LV; } -/// getLVForDecl - Get the linkage and visibility for the given declaration. -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation); - static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { const Decl *Ret = nullptr; const DeclContext *DC = D->getDeclContext(); @@ -311,8 +295,9 @@ static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { /// /// Note that we don't take an LVComputationKind because we always /// want to honor the visibility of template arguments in the same way. -static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, + LVComputationKind computation) { LinkageInfo LV; for (const TemplateArgument &Arg : Args) { @@ -334,7 +319,7 @@ static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, continue; case TemplateArgument::NullPtr: - LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility()); + LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType())); continue; case TemplateArgument::Template: @@ -354,9 +339,9 @@ static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, return LV; } -static LinkageInfo -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation) { return getLVForTemplateArgumentList(TArgs.asArray(), computation); } @@ -379,10 +364,10 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, /// LVForValue. /// /// \param[out] LV the computation to use for the parent -static void -mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *specInfo, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV( + LinkageInfo &LV, const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); @@ -402,21 +387,11 @@ mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, /// that would match the given rules? static bool hasDirectVisibilityAttribute(const NamedDecl *D, LVComputationKind computation) { - switch (computation) { - case LVForType: - case LVForExplicitType: - if (D->hasAttr<TypeVisibilityAttr>()) - return true; - // fallthrough - case LVForValue: - case LVForExplicitValue: - if (D->hasAttr<VisibilityAttr>()) - return true; - return false; - case LVForLinkageOnly: + if (computation.IgnoreAllVisibility) return false; - } - llvm_unreachable("bad visibility computation kind"); + + return (computation.isTypeVisibility() && D->hasAttr<TypeVisibilityAttr>()) || + D->hasAttr<VisibilityAttr>(); } /// Should we consider visibility associated with the template @@ -457,9 +432,9 @@ static bool shouldConsiderTemplateVisibility( /// Merge in template-related linkage and visibility for the given /// class template specialization. -static void mergeTemplateLV(LinkageInfo &LV, - const ClassTemplateSpecializationDecl *spec, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV( + LinkageInfo &LV, const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore @@ -509,9 +484,9 @@ static bool shouldConsiderTemplateVisibility( /// Merge in template-related linkage and visibility for the given /// variable template specialization. As usual, follow class template /// specialization logic up to initialization. -static void mergeTemplateLV(LinkageInfo &LV, - const VarTemplateSpecializationDecl *spec, - LVComputationKind computation) { +void LinkageComputer::mergeTemplateLV(LinkageInfo &LV, + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore @@ -574,6 +549,7 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { } static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { + // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: case Decl::ModuleOwnershipKind::ModulePrivate: @@ -605,14 +581,17 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { // declaration has module linkage. if (auto *M = D->getOwningModule()) if (M->Kind == Module::ModuleInterfaceUnit) - if (!isExportedFromModuleIntefaceUnit(D)) + if (!isExportedFromModuleIntefaceUnit( + cast<NamedDecl>(D->getCanonicalDecl()))) return LinkageInfo(ModuleLinkage, DefaultVisibility, false); return LinkageInfo::external(); } -static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -652,7 +631,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, PrevVar = PrevVar->getPreviousDecl()) { if (PrevVar->getStorageClass() == SC_PrivateExtern && Var->getStorageClass() == SC_None) - return PrevVar->getLinkageAndVisibility(); + return getDeclLinkageAndVisibility(PrevVar); // Explicitly declared static. if (PrevVar->getStorageClass() == SC_Static) return getInternalLinkageFor(Var); @@ -669,23 +648,23 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); assert(VD && "Expected a VarDecl in this IndirectFieldDecl!"); - return getLVForNamespaceScopeDecl(VD, computation); + return getLVForNamespaceScopeDecl(VD, computation, IgnoreVarTypeLinkage); } assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); if (D->isInAnonymousNamespace()) { const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); - // FIXME: In C++11 onwards, anonymous namespaces should give decls - // within them (including those inside extern "C" contexts) internal - // linkage, not unique external linkage: + // FIXME: The check for extern "C" here is not justified by the standard + // wording, but we retain it from the pre-DR1113 model to avoid breaking + // code. // // C++11 [basic.link]p4: // An unnamed namespace or a namespace declared directly or indirectly // within an unnamed namespace has internal linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(D); } // Set up the defaults. @@ -694,7 +673,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // If the declaration of an identifier for an object has file // scope and no storage-class specifier, its linkage is // external. - LinkageInfo LV; + LinkageInfo LV = getExternalLinkageFor(D); if (!hasExplicitVisibilityAlready(computation)) { if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) { @@ -717,13 +696,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Add in global settings if the above didn't give us direct visibility. if (!LV.isVisibilityExplicit()) { // Use global type/value visibility as appropriate. - Visibility globalVisibility; - if (computation == LVForValue) { - globalVisibility = Context.getLangOpts().getValueVisibilityMode(); - } else { - assert(computation == LVForType); - globalVisibility = Context.getLangOpts().getTypeVisibilityMode(); - } + Visibility globalVisibility = + computation.isValueVisibility() + ? Context.getLangOpts().getValueVisibilityMode() + : Context.getLangOpts().getTypeVisibilityMode(); LV.mergeVisibility(globalVisibility, /*explicit*/ false); // If we're paying attention to global visibility, apply @@ -761,10 +737,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) && + !IgnoreVarTypeLinkage) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); - if (TypeLV.getLinkage() != ExternalLinkage && - TypeLV.getLinkage() != ModuleLinkage) + if (!isExternallyVisible(TypeLV.getLinkage())) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); @@ -802,19 +778,13 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // unique-external linkage, it's not legally usable from outside // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. - if (Context.getLangOpts().CPlusPlus && - !Function->isInExternCContext()) { - // Only look at the type-as-written. If this function has an auto-deduced - // return type, we can't compute the linkage of that type because it could - // require looking at the linkage of this function, and we don't need this - // for correctness because the type is not part of the function's - // signature. - // FIXME: This is a hack. We should be able to solve this circularity and - // the one in getLVForClassMember for Functions some other way. + if (Context.getLangOpts().CPlusPlus && !Function->isInExternCContext()) { + // Only look at the type-as-written. Otherwise, deducing the return type + // of a function could change its linkage. QualType TypeAsWritten = Function->getType(); if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); - if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + if (!isExternallyVisible(TypeAsWritten->getLinkage())) return LinkageInfo::uniqueExternal(); } @@ -883,16 +853,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return LinkageInfo::none(); } - // If we ended up with non-external linkage, visibility should + // If we ended up with non-externally-visible linkage, visibility should // always be default. - if (LV.getLinkage() != ExternalLinkage) + if (!isExternallyVisible(LV.getLinkage())) return LinkageInfo(LV.getLinkage(), DefaultVisibility, false); return LV; } -static LinkageInfo getLVForClassMember(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo +LinkageComputer::getLVForClassMember(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { // Only certain class members have linkage. Note that fields don't // really have linkage, but it's convenient to say they do for the // purposes of calculating linkage of pointer-to-data-member @@ -935,12 +907,11 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LinkageInfo classLV = getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation); - // If the class already has unique-external linkage, we can't improve. - if (classLV.getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); - + // The member has the same linkage as the class. If that's not externally + // visible, we don't need to compute anything about the linkage. + // FIXME: If we're only computing linkage, can we bail out here? if (!isExternallyVisible(classLV.getLinkage())) - return LinkageInfo::none(); + return classLV; // Otherwise, don't merge in classLV yet, because in certain cases @@ -950,22 +921,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, const NamedDecl *explicitSpecSuppressor = nullptr; if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - // If the type of the function uses a type with unique-external - // linkage, it's not legally usable from outside this translation unit. - // But only look at the type-as-written. If this function has an - // auto-deduced return type, we can't compute the linkage of that type - // because it could require looking at the linkage of this function, and we - // don't need this for correctness because the type is not part of the - // function's signature. - // FIXME: This is a hack. We should be able to solve this circularity and - // the one in getLVForNamespaceScopeDecl for Functions some other way. - { - QualType TypeAsWritten = MD->getType(); - if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) - TypeAsWritten = TSI->getType(); - if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); - } + // Only look at the type-as-written. Otherwise, deducing the return type + // of a function could change its linkage. + QualType TypeAsWritten = MD->getType(); + if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (!isExternallyVisible(TypeAsWritten->getLinkage())) + return LinkageInfo::uniqueExternal(); + // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec @@ -1002,10 +965,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, // Modify the variable's linkage by its type, but ignore the // type's visibility unless it's a definition. - LinkageInfo typeLV = getLVForType(*VD->getType(), computation); - if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) - LV.mergeVisibility(typeLV); - LV.mergeExternalVisibility(typeLV); + if (!IgnoreVarTypeLinkage) { + LinkageInfo typeLV = getLVForType(*VD->getType(), computation); + // FIXME: If the type's linkage is not externally visible, we can + // give this static data member UniqueExternalLinkage. + if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) + LV.mergeVisibility(typeLV); + LV.mergeExternalVisibility(typeLV); + } if (isExplicitMemberSpecialization(VD)) { explicitSpecSuppressor = VD; @@ -1047,17 +1014,16 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, return LV; } -void NamedDecl::anchor() { } - -static LinkageInfo computeLVForDecl(const NamedDecl *D, - LVComputationKind computation); +void NamedDecl::anchor() {} bool NamedDecl::isLinkageValid() const { if (!hasCachedLinkage()) return true; - return computeLVForDecl(this, LVForLinkageOnly).getLinkage() == - getCachedLinkage(); + Linkage L = LinkageComputer{} + .computeLVForDecl(this, LVComputationKind::forLinkageOnly()) + .getLinkage(); + return L == getCachedLinkage(); } ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { @@ -1076,13 +1042,13 @@ ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { Linkage NamedDecl::getLinkageInternal() const { // We don't care about visibility here, so ask for the cheapest // possible visibility analysis. - return getLVForDecl(this, LVForLinkageOnly).getLinkage(); + return LinkageComputer{} + .getLVForDecl(this, LVComputationKind::forLinkageOnly()) + .getLinkage(); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { - LVComputationKind computation = - (usesTypeVisibility(this) ? LVForType : LVForValue); - return getLVForDecl(this, computation); + return LinkageComputer{}.getDeclLinkageAndVisibility(this); } static Optional<Visibility> @@ -1160,30 +1126,46 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { return getExplicitVisibilityAux(this, kind, false); } -static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC, + Decl *ContextDecl, + LVComputationKind computation) { // This lambda has its linkage/visibility determined by its owner. - if (ContextDecl) { - if (isa<ParmVarDecl>(ContextDecl)) - DC = ContextDecl->getDeclContext()->getRedeclContext(); - else - return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); - } + const NamedDecl *Owner; + if (!ContextDecl) + Owner = dyn_cast<NamedDecl>(DC); + else if (isa<ParmVarDecl>(ContextDecl)) + Owner = + dyn_cast<NamedDecl>(ContextDecl->getDeclContext()->getRedeclContext()); + else + Owner = cast<NamedDecl>(ContextDecl); - if (const auto *ND = dyn_cast<NamedDecl>(DC)) - return getLVForDecl(ND, computation); + if (!Owner) + return LinkageInfo::none(); - // FIXME: We have a closure at TU scope with no context declaration. This - // should probably have no linkage. - return LinkageInfo::external(); + // If the owner has a deduced type, we need to skip querying the linkage and + // visibility of that type, because it might involve this closure type. The + // only effect of this is that we might give a lambda VisibleNoLinkage rather + // than NoLinkage when we don't strictly need to, which is benign. + auto *VD = dyn_cast<VarDecl>(Owner); + LinkageInfo OwnerLV = + VD && VD->getType()->getContainedDeducedType() + ? computeLVForDecl(Owner, computation, /*IgnoreVarTypeLinkage*/true) + : getLVForDecl(Owner, computation); + + // A lambda never formally has linkage. But if the owner is externally + // visible, then the lambda is too. We apply the same rules to blocks. + if (!isExternallyVisible(OwnerLV.getLinkage())) + return LinkageInfo::none(); + return LinkageInfo(VisibleNoLinkage, OwnerLV.getVisibility(), + OwnerLV.isVisibilityExplicit()); } -static LinkageInfo getLVForLocalDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, + LVComputationKind computation) { if (const auto *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && !Function->isInExternCContext()) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(Function); // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) @@ -1206,7 +1188,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, if (const auto *Var = dyn_cast<VarDecl>(D)) { if (Var->hasExternalStorage()) { if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) - return LinkageInfo::uniqueExternal(); + return getInternalLinkageFor(Var); LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) @@ -1272,8 +1254,9 @@ getOutermostEnclosingLambda(const CXXRecordDecl *Record) { return Ret; } -static LinkageInfo computeLVForDecl(const NamedDecl *D, - LVComputationKind computation) { +LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) return getInternalLinkageFor(D); @@ -1361,7 +1344,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, // Handle linkage for namespace-scope names. if (D->getDeclContext()->getRedeclContext()->isFileContext()) - return getLVForNamespaceScopeDecl(D, computation); + return getLVForNamespaceScopeDecl(D, computation, IgnoreVarTypeLinkage); // C++ [basic.link]p5: // In addition, a member function, static data member, a named @@ -1371,7 +1354,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, // purposes (7.1.3), has external linkage if the name of the class // has external linkage. if (D->getDeclContext()->isRecord()) - return getLVForClassMember(D, computation); + return getLVForClassMember(D, computation, IgnoreVarTypeLinkage); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -1392,56 +1375,93 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, return LinkageInfo::none(); } -namespace clang { -class LinkageComputer { -public: - static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { - // Internal_linkage attribute overrides other considerations. - if (D->hasAttr<InternalLinkageAttr>()) - return getInternalLinkageFor(D); +/// getLVForDecl - Get the linkage and visibility for the given declaration. +LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + // Internal_linkage attribute overrides other considerations. + if (D->hasAttr<InternalLinkageAttr>()) + return getInternalLinkageFor(D); + + if (computation.IgnoreAllVisibility && D->hasCachedLinkage()) + return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); - if (computation == LVForLinkageOnly && D->hasCachedLinkage()) - return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); + if (llvm::Optional<LinkageInfo> LI = lookup(D, computation)) + return *LI; - LinkageInfo LV = computeLVForDecl(D, computation); - if (D->hasCachedLinkage()) - assert(D->getCachedLinkage() == LV.getLinkage()); + LinkageInfo LV = computeLVForDecl(D, computation); + if (D->hasCachedLinkage()) + assert(D->getCachedLinkage() == LV.getLinkage()); - D->setCachedLinkage(LV.getLinkage()); + D->setCachedLinkage(LV.getLinkage()); + cache(D, computation, LV); #ifndef NDEBUG - // In C (because of gnu inline) and in c++ with microsoft extensions an - // static can follow an extern, so we can have two decls with different - // linkages. - const LangOptions &Opts = D->getASTContext().getLangOpts(); - if (!Opts.CPlusPlus || Opts.MicrosoftExt) - return LV; + // In C (because of gnu inline) and in c++ with microsoft extensions an + // static can follow an extern, so we can have two decls with different + // linkages. + const LangOptions &Opts = D->getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return LV; - // We have just computed the linkage for this decl. By induction we know - // that all other computed linkages match, check that the one we just - // computed also does. - NamedDecl *Old = nullptr; - for (auto I : D->redecls()) { - auto *T = cast<NamedDecl>(I); - if (T == D) - continue; - if (!T->isInvalidDecl() && T->hasCachedLinkage()) { - Old = T; - break; - } + // We have just computed the linkage for this decl. By induction we know + // that all other computed linkages match, check that the one we just + // computed also does. + NamedDecl *Old = nullptr; + for (auto I : D->redecls()) { + auto *T = cast<NamedDecl>(I); + if (T == D) + continue; + if (!T->isInvalidDecl() && T->hasCachedLinkage()) { + Old = T; + break; } - assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); + } + assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); #endif - return LV; - } -}; + return LV; +} + +LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) { + return getLVForDecl(D, + LVComputationKind(usesTypeVisibility(D) + ? NamedDecl::VisibilityForType + : NamedDecl::VisibilityForValue)); } -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { - return clang::LinkageComputer::getLVForDecl(D, computation); +Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { + Module *M = getOwningModule(); + if (!M) + return nullptr; + + switch (M->Kind) { + case Module::ModuleMapModule: + // Module map modules have no special linkage semantics. + return nullptr; + + case Module::ModuleInterfaceUnit: + return M; + + case Module::GlobalModuleFragment: { + // External linkage declarations in the global module have no owning module + // for linkage purposes. But internal linkage declarations in the global + // module fragment of a particular module are owned by that module for + // linkage purposes. + if (IgnoreLinkage) + return nullptr; + bool InternalLinkage; + if (auto *ND = dyn_cast<NamedDecl>(this)) + InternalLinkage = !ND->hasExternalFormalLinkage(); + else { + auto *NSD = dyn_cast<NamespaceDecl>(this); + InternalLinkage = (NSD && NSD->isAnonymousNamespace()) || + isInAnonymousNamespace(); + } + return InternalLinkage ? M->Parent : nullptr; + } + } + + llvm_unreachable("unknown module kind"); } void NamedDecl::printName(raw_ostream &os) const { @@ -1473,7 +1493,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, return; } - typedef SmallVector<const DeclContext *, 8> ContextsTy; + using ContextsTy = SmallVector<const DeclContext *, 8>; ContextsTy Contexts; // Collect contexts. @@ -1482,12 +1502,11 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, Ctx = Ctx->getParent(); } - for (const DeclContext *DC : reverse(Contexts)) { + for (const DeclContext *DC : llvm::reverse(Contexts)) { if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { OS << Spec->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, TemplateArgs.asArray(), P); + printTemplateArgumentList(OS, TemplateArgs.asArray(), P); } else if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) { if (P.SuppressUnwrittenScope && (ND->isAnonymousNamespace() || ND->isInline())) @@ -1612,14 +1631,6 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const { cast<UnresolvedUsingValueDecl>(OldD)->getQualifier()); } - // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. - // They can be replaced if they nominate the same namespace. - // FIXME: Is this true even if they have different module visibility? - if (auto *UD = dyn_cast<UsingDirectiveDecl>(this)) - return UD->getNominatedNamespace()->getOriginalNamespace() == - cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace() - ->getOriginalNamespace(); - if (isRedeclarable(getKind())) { if (getCanonicalDecl() != OldD->getCanonicalDecl()) return false; @@ -1754,11 +1765,9 @@ SourceLocation DeclaratorDecl::getOuterLocStart() const { return getTemplateOrInnerLocStart(this); } -namespace { - // Helper function: returns true if QT is or contains a type // having a postfix component. -bool typeIsPostfix(clang::QualType QT) { +static bool typeIsPostfix(QualType QT) { while (true) { const Type* T = QT.getTypePtr(); switch (T->getTypeClass()) { @@ -1792,8 +1801,6 @@ bool typeIsPostfix(clang::QualType QT) { } } -} // namespace - SourceRange DeclaratorDecl::getSourceRange() const { SourceLocation RangeEnd = getLocation(); if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { @@ -1843,7 +1850,7 @@ VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - redeclarable_base(C), Init() { + redeclarable_base(C) { static_assert(sizeof(VarDeclBitfields) <= sizeof(unsigned), "VarDeclBitfields too large!"); static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned), @@ -1967,6 +1974,9 @@ VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); } VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(ASTContext &C) const { + if (isThisDeclarationADemotedDefinition()) + return DeclarationOnly; + // C++ [basic.def]p2: // A declaration is a definition unless [...] it contains the 'extern' // specifier or a linkage-specification and neither an initializer [...], @@ -1980,9 +1990,6 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const { // // FIXME: How do you declare (but not define) a partial specialization of // a static data member template outside the containing class? - if (isThisDeclarationADemotedDefinition()) - return DeclarationOnly; - if (isStaticDataMember()) { if (isOutOfLine() && !(getCanonicalDecl()->isInline() && @@ -2022,9 +2029,12 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const { // A variable template specialization (other than a static data member // template or an explicit specialization) is a declaration until we // instantiate its initializer. - if (isa<VarTemplateSpecializationDecl>(this) && - getTemplateSpecializationKind() != TSK_ExplicitSpecialization) - return DeclarationOnly; + if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(this)) { + if (VTSD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(VTSD) && + !VTSD->IsCompleteDefinition) + return DeclarationOnly; + } if (hasExternalStorage()) return DeclarationOnly; @@ -2408,15 +2418,21 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, dyn_cast<VarTemplateSpecializationDecl>(this)) { Spec->setSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - Spec->getPointOfInstantiation().isInvalid()) + Spec->getPointOfInstantiation().isInvalid()) { Spec->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) + MSI->getPointOfInstantiation().isInvalid()) { MSI->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } } @@ -2548,8 +2564,7 @@ void FunctionDecl::getNameForDiagnostic( NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); if (TemplateArgs) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, TemplateArgs->asArray(), Policy); + printTemplateArgumentList(OS, TemplateArgs->asArray(), Policy); } bool FunctionDecl::isVariadic() const { @@ -2747,6 +2762,20 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const return Params == FPT->getNumParams(); } +bool FunctionDecl::isDestroyingOperatorDelete() const { + // C++ P0722: + // Within a class C, a single object deallocation function with signature + // (T, std::destroying_delete_t, <more params>) + // is a destroying operator delete. + if (!isa<CXXMethodDecl>(this) || getOverloadedOperator() != OO_Delete || + getNumParams() < 2) + return false; + + auto *RD = getParamDecl(1)->getType()->getAsCXXRecordDecl(); + return RD && RD->isInStdNamespace() && RD->getIdentifier() && + RD->getIdentifier()->isStr("destroying_delete_t"); +} + LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getDeclLanguageLinkage(*this); } @@ -2871,7 +2900,6 @@ unsigned FunctionDecl::getBuiltinID() const { return BuiltinID; } - /// getNumParams - Return the number of parameters this function must have /// based on its FunctionType. This is the length of the ParamInfo array /// after it has been created. @@ -3057,7 +3085,8 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const { const Attr *FunctionDecl::getUnusedResultAttr() const { QualType RetType = getReturnType(); if (RetType->isRecordType()) { - if (const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl()) { + if (const auto *Ret = + dyn_cast_or_null<RecordDecl>(RetType->getAsTagDecl())) { if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>()) return R; } @@ -3382,7 +3411,6 @@ DependentFunctionTemplateSpecializationInfo:: DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, const TemplateArgumentListInfo &TArgs) : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { - NumTemplates = Ts.size(); NumArgs = TArgs.size(); @@ -3420,15 +3448,21 @@ FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, FTSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->getPointOfInstantiation().isInvalid()) { FTSInfo->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } else if (MemberSpecializationInfo *MSInfo = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) { MSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && - MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->getPointOfInstantiation().isInvalid()) { MSInfo->setPointOfInstantiation(PointOfInstantiation); + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->InstantiationRequested(this); + } } else llvm_unreachable("Function cannot have a template specialization kind"); } @@ -3598,8 +3632,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const { unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { assert(isBitField() && "not a bitfield"); - auto *BitWidth = static_cast<Expr *>(InitStorage.getPointer()); - return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); + return getBitWidth()->EvaluateKnownConstInt(Ctx).getZExtValue(); } unsigned FieldDecl::getFieldIndex() const { @@ -3610,7 +3643,8 @@ unsigned FieldDecl::getFieldIndex() const { if (CachedFieldIndex) return CachedFieldIndex - 1; unsigned Index = 0; - const RecordDecl *RD = getParent(); + const RecordDecl *RD = getParent()->getDefinition(); + assert(RD && "requested index for field of struct with no definition"); for (auto *Field : RD->fields()) { Field->getCanonicalDecl()->CachedFieldIndex = Index + 1; @@ -3622,25 +3656,18 @@ unsigned FieldDecl::getFieldIndex() const { } SourceRange FieldDecl::getSourceRange() const { - switch (InitStorage.getInt()) { - // All three of these cases store an optional Expr*. - case ISK_BitWidthOrNothing: - case ISK_InClassCopyInit: - case ISK_InClassListInit: - if (const auto *E = static_cast<const Expr *>(InitStorage.getPointer())) - return SourceRange(getInnerLocStart(), E->getLocEnd()); - // FALLTHROUGH - - case ISK_CapturedVLAType: - return DeclaratorDecl::getSourceRange(); - } - llvm_unreachable("bad init storage kind"); + const Expr *FinalExpr = getInClassInitializer(); + if (!FinalExpr) + FinalExpr = getBitWidth(); + if (FinalExpr) + return SourceRange(getInnerLocStart(), FinalExpr->getLocEnd()); + return DeclaratorDecl::getSourceRange(); } void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) { assert((getParent()->isLambda() || getParent()->isCapturedRecord()) && "capturing type in non-lambda or captured record."); - assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + assert(InitStorage.getInt() == ISK_NoInit && InitStorage.getPointer() == nullptr && "bit width, initializer or captured type already set"); InitStorage.setPointerAndInt(const_cast<VariableArrayType *>(VLAType), @@ -3753,7 +3780,7 @@ void TagDecl::setTemplateParameterListsInfo( // EnumDecl Implementation //===----------------------------------------------------------------------===// -void EnumDecl::anchor() { } +void EnumDecl::anchor() {} EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -3862,12 +3889,10 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl *PrevDecl) - : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc) { - HasFlexibleArrayMember = false; - AnonymousStructOrUnion = false; - HasObjectMember = false; - HasVolatileMember = false; - LoadedFieldsFromExternalStorage = false; + : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc), + HasFlexibleArrayMember(false), AnonymousStructOrUnion(false), + HasObjectMember(false), HasVolatileMember(false), + LoadedFieldsFromExternalStorage(false) { assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } @@ -3958,9 +3983,9 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const { ASTContext &Context = getASTContext(); - if (!Context.getLangOpts().Sanitize.hasOneOf( - SanitizerKind::Address | SanitizerKind::KernelAddress) || - !Context.getLangOpts().SanitizeAddressFieldPadding) + const SanitizerMask EnabledAsanMask = Context.getLangOpts().Sanitize.Mask & + (SanitizerKind::Address | SanitizerKind::KernelAddress); + if (!EnabledAsanMask || !Context.getLangOpts().SanitizeAddressFieldPadding) return false; const auto &Blacklist = Context.getSanitizerBlacklist(); const auto *CXXRD = dyn_cast<CXXRecordDecl>(this); @@ -3978,9 +4003,11 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const { ReasonToReject = 4; // has trivial destructor. else if (CXXRD->isStandardLayout()) ReasonToReject = 5; // is standard layout. - else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding")) + else if (Blacklist.isBlacklistedLocation(EnabledAsanMask, getLocation(), + "field-padding")) ReasonToReject = 6; // is in a blacklisted file. - else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(), + else if (Blacklist.isBlacklistedType(EnabledAsanMask, + getQualifiedNameAsString(), "field-padding")) ReasonToReject = 7; // is blacklisted. @@ -4014,7 +4041,6 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const { return nullptr; } - //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// @@ -4060,13 +4086,13 @@ SourceRange BlockDecl::getSourceRange() const { // Other Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// -void TranslationUnitDecl::anchor() { } +void TranslationUnitDecl::anchor() {} TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C); } -void PragmaCommentDecl::anchor() { } +void PragmaCommentDecl::anchor() {} PragmaCommentDecl *PragmaCommentDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, @@ -4088,7 +4114,7 @@ PragmaCommentDecl *PragmaCommentDecl::CreateDeserialized(ASTContext &C, PragmaCommentDecl(nullptr, SourceLocation(), PCK_Unknown); } -void PragmaDetectMismatchDecl::anchor() { } +void PragmaDetectMismatchDecl::anchor() {} PragmaDetectMismatchDecl * PragmaDetectMismatchDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, @@ -4113,14 +4139,14 @@ PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, unsigned ID, PragmaDetectMismatchDecl(nullptr, SourceLocation(), 0); } -void ExternCContextDecl::anchor() { } +void ExternCContextDecl::anchor() {} ExternCContextDecl *ExternCContextDecl::Create(const ASTContext &C, TranslationUnitDecl *DC) { return new (C, DC) ExternCContextDecl(DC); } -void LabelDecl::anchor() { } +void LabelDecl::anchor() {} LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II) { @@ -4146,7 +4172,7 @@ void LabelDecl::setMSAsmLabel(StringRef Name) { MSAsmName = Buffer; } -void ValueDecl::anchor() { } +void ValueDecl::anchor() {} bool ValueDecl::isWeak() const { for (const auto *I : attrs()) @@ -4156,7 +4182,7 @@ bool ValueDecl::isWeak() const { return isWeakImported(); } -void ImplicitParamDecl::anchor() { } +void ImplicitParamDecl::anchor() {} ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, @@ -4239,7 +4265,7 @@ EnumConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) { QualType(), nullptr, llvm::APSInt()); } -void IndirectFieldDecl::anchor() { } +void IndirectFieldDecl::anchor() {} IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, @@ -4273,7 +4299,7 @@ SourceRange EnumConstantDecl::getSourceRange() const { return SourceRange(getLocation(), End); } -void TypeDecl::anchor() { } +void TypeDecl::anchor() {} TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -4281,7 +4307,7 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } -void TypedefNameDecl::anchor() { } +void TypedefNameDecl::anchor() {} TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>()) { @@ -4355,7 +4381,7 @@ SourceRange TypeAliasDecl::getSourceRange() const { return SourceRange(getLocStart(), RangeEnd); } -void FileScopeAsmDecl::anchor() { } +void FileScopeAsmDecl::anchor() {} FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, StringLiteral *Str, @@ -4398,9 +4424,7 @@ static unsigned getNumModuleIdentifiers(Module *Mod) { ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef<SourceLocation> IdentifierLocs) - : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, true), - NextLocalImport() -{ + : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, true) { assert(getNumModuleIdentifiers(Imported) == IdentifierLocs.size()); auto *StoredLocs = getTrailingObjects<SourceLocation>(); std::uninitialized_copy(IdentifierLocs.begin(), IdentifierLocs.end(), @@ -4409,9 +4433,7 @@ ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc, ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc) - : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, false), - NextLocalImport() -{ + : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, false) { *getTrailingObjects<SourceLocation>() = EndLoc; } diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index cd2c83a02f599..29ce7ae034b5c 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -1,4 +1,4 @@ -//===--- DeclBase.cpp - Declaration AST Node Implementation ---------------===// +//===- DeclBase.cpp - Declaration AST Node Implementation -----------------===// // // The LLVM Compiler Infrastructure // @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Attr.h" +#include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" @@ -25,11 +26,30 @@ #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" -#include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> +#include <tuple> +#include <utility> + using namespace clang; //===----------------------------------------------------------------------===// @@ -74,8 +94,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra) { assert(!Parent || &Parent->getParentASTContext() == &Ctx); // With local visibility enabled, we track the owning module even for local - // declarations. - if (Ctx.getLangOpts().trackLocalOwningModule()) { + // declarations. We create the TU decl early and may not yet know what the + // LangOpts are, so conservatively allocate the storage. + if (Ctx.getLangOpts().trackLocalOwningModule() || !Parent) { // Ensure required alignment of the resulting object by adding extra // padding at the start if required. size_t ExtraAlign = @@ -229,7 +250,6 @@ const DeclContext *Decl::getParentFunctionOrMethod() const { return nullptr; } - //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// @@ -259,7 +279,7 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const { //===----------------------------------------------------------------------===// // Out-of-line virtual method providing a home for Decl. -Decl::~Decl() { } +Decl::~Decl() = default; void Decl::setDeclContext(DeclContext *DC) { DeclCtx = DC; @@ -314,12 +334,11 @@ bool Decl::isLexicallyWithinFunctionOrMethod() const { } bool Decl::isInAnonymousNamespace() const { - const DeclContext *DC = getDeclContext(); - do { + for (const DeclContext *DC = getDeclContext(); DC; DC = DC->getParent()) { if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) if (ND->isAnonymousNamespace()) return true; - } while ((DC = DC->getParent())); + } return false; } @@ -680,7 +699,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConversion: case EnumConstant: case Var: - case Binding: case ImplicitParam: case ParmVar: case ObjCMethod: @@ -692,10 +710,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case IndirectField: return IDNS_Ordinary | IDNS_Member; + case Binding: case NonTypeTemplateParm: - // Non-type template parameters are not found by lookups that ignore - // non-types, but they are found by redeclaration lookups for tag types, - // so we include them in the tag namespace. + case VarTemplate: + // These (C++-only) declarations are found by redeclaration lookup for + // tag types, so we include them in the tag namespace. return IDNS_Ordinary | IDNS_Tag; case ObjCCompatibleAlias: @@ -704,7 +723,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Typedef: case TypeAlias: - case TypeAliasTemplate: case TemplateTypeParm: case ObjCTypeParam: return IDNS_Ordinary | IDNS_Type; @@ -740,11 +758,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: - case VarTemplate: return IDNS_Ordinary; case ClassTemplate: case TemplateTemplateParm: + case TypeAliasTemplate: return IDNS_Ordinary | IDNS_Tag | IDNS_Type; case OMPDeclareReduction: @@ -914,7 +932,6 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { return Ty->getAs<FunctionType>(); } - /// Starting at a given context (a Decl or DeclContext), look for a /// code context that is not a closure (a lambda, block, etc.). template <class T> static Decl *getNonClosureContext(T *D) { @@ -967,7 +984,7 @@ bool DeclContext::classof(const Decl *D) { } } -DeclContext::~DeclContext() { } +DeclContext::~DeclContext() = default; /// \brief Find the parent context of this context that will be /// used for unqualified name lookup. @@ -1058,15 +1075,14 @@ static bool isLinkageSpecContext(const DeclContext *DC, } bool DeclContext::isExternCContext() const { - return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); + return isLinkageSpecContext(this, LinkageSpecDecl::lang_c); } const LinkageSpecDecl *DeclContext::getExternCContext() const { const DeclContext *DC = this; while (DC->getDeclKind() != Decl::TranslationUnit) { if (DC->getDeclKind() == Decl::LinkageSpec && - cast<LinkageSpecDecl>(DC)->getLanguage() == - clang::LinkageSpecDecl::lang_c) + cast<LinkageSpecDecl>(DC)->getLanguage() == LinkageSpecDecl::lang_c) return cast<LinkageSpecDecl>(DC); DC = DC->getLexicalParent(); } @@ -1074,7 +1090,7 @@ const LinkageSpecDecl *DeclContext::getExternCContext() const { } bool DeclContext::isExternCXXContext() const { - return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); + return isLinkageSpecContext(this, LinkageSpecDecl::lang_cxx); } bool DeclContext::Encloses(const DeclContext *DC) const { @@ -1109,13 +1125,11 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::ObjCInterface: if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) return Def; - return this; case Decl::ObjCProtocol: if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) return Def; - return this; case Decl::ObjCCategory: diff --git a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp index 5782b7b56c963..41f2449a9d6a0 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp @@ -1,4 +1,4 @@ -//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// +//===- DeclCXX.cpp - C++ Declaration AST Node Implementation --------------===// // // The LLVM Compiler Infrastructure // @@ -10,26 +10,51 @@ // This file implements the C++ related Decl classes. // //===----------------------------------------------------------------------===// + #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/ODRHash.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" -#include "llvm/ADT/STLExtras.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> + using namespace clang; //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// -void AccessSpecDecl::anchor() { } +void AccessSpecDecl::anchor() {} AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) AccessSpecDecl(EmptyShell()); @@ -76,9 +101,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false), - IsParsingBaseSpecifiers(false), HasODRHash(false), ODRHash(0), - NumBases(0), NumVBases(0), Bases(), VBases(), Definition(D), - FirstFriend() {} + IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {} CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { return Bases.get(Definition->getASTContext().getExternalSource()); @@ -94,13 +117,12 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, CXXRecordDecl *PrevDecl) : RecordDecl(K, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl), DefinitionData(PrevDecl ? PrevDecl->DefinitionData - : nullptr), - TemplateOrInstantiation() {} + : nullptr) {} CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl* PrevDecl, + CXXRecordDecl *PrevDecl, bool DelayTypeCreation) { CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); @@ -148,7 +170,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, C.Deallocate(data().getBases()); if (NumBases) { - if (!C.getLangOpts().CPlusPlus1z) { + if (!C.getLangOpts().CPlusPlus17) { // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. data().Aggregate = false; @@ -403,7 +425,6 @@ unsigned CXXRecordDecl::getODRHash() const { return DefinitionData->ODRHash; } - void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // C++11 [class.copy]p11: // A defaulted copy/move constructor for a class X is defined as @@ -1470,6 +1491,66 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const { return false; } +static bool isDeclContextInNamespace(const DeclContext *DC) { + while (!DC->isTranslationUnit()) { + if (DC->isNamespace()) + return true; + DC = DC->getParent(); + } + return false; +} + +bool CXXRecordDecl::isInterfaceLike() const { + assert(hasDefinition() && "checking for interface-like without a definition"); + // All __interfaces are inheritently interface-like. + if (isInterface()) + return true; + + // Interface-like types cannot have a user declared constructor, destructor, + // friends, VBases, conversion functions, or fields. Additionally, lambdas + // cannot be interface types. + if (isLambda() || hasUserDeclaredConstructor() || + hasUserDeclaredDestructor() || !field_empty() || hasFriends() || + getNumVBases() > 0 || conversion_end() - conversion_begin() > 0) + return false; + + // No interface-like type can have a method with a definition. + for (const auto *const Method : methods()) + if (Method->isDefined() && !Method->isImplicit()) + return false; + + // Check "Special" types. + const auto *Uuid = getAttr<UuidAttr>(); + // MS SDK declares IUnknown/IDispatch both in the root of a TU, or in an + // extern C++ block directly in the TU. These are only valid if in one + // of these two situations. + if (Uuid && isStruct() && !getDeclContext()->isExternCContext() && + !isDeclContextInNamespace(getDeclContext()) && + ((getName() == "IUnknown" && + Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") || + (getName() == "IDispatch" && + Uuid->getGuid() == "00020400-0000-0000-C000-000000000046"))) { + if (getNumBases() > 0) + return false; + return true; + } + + // FIXME: Any access specifiers is supposed to make this no longer interface + // like. + + // If this isn't a 'special' type, it must have a single interface-like base. + if (getNumBases() != 1) + return false; + + const auto BaseSpec = *bases_begin(); + if (BaseSpec.isVirtual() || BaseSpec.getAccessSpecifier() != AS_public) + return false; + const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl(); + if (Base->isInterface() || !Base->isInterfaceLike()) + return false; + return true; +} + void CXXRecordDecl::completeDefinition() { completeDefinition(nullptr); } @@ -1530,7 +1611,7 @@ bool CXXRecordDecl::mayBeAbstract() const { return false; } -void CXXDeductionGuideDecl::anchor() { } +void CXXDeductionGuideDecl::anchor() {} CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create( ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit, @@ -1547,7 +1628,7 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, nullptr, SourceLocation()); } -void CXXMethodDecl::anchor() { } +void CXXMethodDecl::anchor() {} bool CXXMethodDecl::isStatic() const { const CXXMethodDecl *MD = getCanonicalDecl(); @@ -1561,9 +1642,7 @@ bool CXXMethodDecl::isStatic() const { static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { - for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), - E = DerivedMD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *MD = *I; + for (const CXXMethodDecl *MD : DerivedMD->overridden_methods()) { if (MD->getCanonicalDecl() == BaseMD->getCanonicalDecl()) return true; if (recursivelyOverrides(MD, BaseMD)) @@ -1728,6 +1807,14 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; unsigned UsualParams = 1; + // C++ P0722: + // A destroying operator delete is a usual deallocation function if + // removing the std::destroying_delete_t parameter and changing the + // first parameter type from T* to void* results in the signature of + // a usual deallocation function. + if (isDestroyingOperatorDelete()) + ++UsualParams; + // C++ <=14 [basic.stc.dynamic.deallocation]p2: // [...] If class T does not declare such an operator delete but does // declare a member deallocation function named operator delete with @@ -1886,43 +1973,34 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, SourceLocation L, Expr *Init, SourceLocation R, SourceLocation EllipsisLoc) - : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), - LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual), - IsWritten(false), SourceOrder(0) -{ -} + : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual), + IsWritten(false), SourceOrder(0) {} CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R) - : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), - LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), - IsWritten(false), SourceOrder(0) -{ -} + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), + IsWritten(false), SourceOrder(0) {} CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R) - : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), - LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), - IsWritten(false), SourceOrder(0) -{ -} + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), + IsWritten(false), SourceOrder(0) {} CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, SourceLocation L, Expr *Init, SourceLocation R) - : Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init), - LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false), - IsWritten(false), SourceOrder(0) -{ -} + : Initializee(TInfo), Init(Init), LParenLoc(L), RParenLoc(R), + IsDelegating(true), IsVirtual(false), IsWritten(false), SourceOrder(0) {} TypeLoc CXXCtorInitializer::getBaseClassLoc() const { if (isBaseInitializer()) @@ -1962,7 +2040,7 @@ SourceRange CXXCtorInitializer::getSourceRange() const { return SourceRange(getSourceLocation(), getRParenLoc()); } -void CXXConstructorDecl::anchor() { } +void CXXConstructorDecl::anchor() {} CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID, @@ -2105,7 +2183,7 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { return true; } -void CXXDestructorDecl::anchor() { } +void CXXDestructorDecl::anchor() {} CXXDestructorDecl * CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -2127,16 +2205,17 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, isInline, isImplicitlyDeclared); } -void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) { +void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) { auto *First = cast<CXXDestructorDecl>(getFirstDecl()); if (OD && !First->OperatorDelete) { First->OperatorDelete = OD; + First->OperatorDeleteThisArg = ThisArg; if (auto *L = getASTMutationListener()) - L->ResolvedOperatorDelete(First, OD); + L->ResolvedOperatorDelete(First, OD, ThisArg); } } -void CXXConversionDecl::anchor() { } +void CXXConversionDecl::anchor() {} CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -2166,7 +2245,7 @@ bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { getConversionType()->isBlockPointerType(); } -void LinkageSpecDecl::anchor() { } +void LinkageSpecDecl::anchor() {} LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, DeclContext *DC, @@ -2183,7 +2262,7 @@ LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, SourceLocation(), lang_c, false); } -void UsingDirectiveDecl::anchor() { } +void UsingDirectiveDecl::anchor() {} UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -2217,7 +2296,7 @@ NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl) : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), - redeclarable_base(C), LocStart(StartLoc), RBraceLoc(), + redeclarable_base(C), LocStart(StartLoc), AnonOrFirstNamespaceAndInline(nullptr, Inline) { setPreviousDecl(PrevDecl); @@ -2257,21 +2336,25 @@ bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); } NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() { return getNextRedeclaration(); } + NamespaceDecl *NamespaceDecl::getPreviousDeclImpl() { return getPreviousDecl(); } + NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() { return getMostRecentDecl(); } -void NamespaceAliasDecl::anchor() { } +void NamespaceAliasDecl::anchor() {} NamespaceAliasDecl *NamespaceAliasDecl::getNextRedeclarationImpl() { return getNextRedeclaration(); } + NamespaceAliasDecl *NamespaceAliasDecl::getPreviousDeclImpl() { return getPreviousDecl(); } + NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() { return getMostRecentDecl(); } @@ -2298,7 +2381,7 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SourceLocation(), nullptr); } -void UsingShadowDecl::anchor() { } +void UsingShadowDecl::anchor() {} UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, @@ -2313,7 +2396,7 @@ UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, EmptyShell Empty) : NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), - redeclarable_base(C), Underlying(), UsingOrNextShadow() {} + redeclarable_base(C) {} UsingShadowDecl * UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -2328,7 +2411,7 @@ UsingDecl *UsingShadowDecl::getUsingDecl() const { return cast<UsingDecl>(Shadow->UsingOrNextShadow); } -void ConstructorUsingShadowDecl::anchor() { } +void ConstructorUsingShadowDecl::anchor() {} ConstructorUsingShadowDecl * ConstructorUsingShadowDecl::Create(ASTContext &C, DeclContext *DC, @@ -2347,7 +2430,7 @@ CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { return getUsingDecl()->getQualifier()->getAsRecordDecl(); } -void UsingDecl::anchor() { } +void UsingDecl::anchor() {} void UsingDecl::addShadowDecl(UsingShadowDecl *S) { assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && @@ -2399,7 +2482,7 @@ SourceRange UsingDecl::getSourceRange() const { return SourceRange(Begin, getNameInfo().getEndLoc()); } -void UsingPackDecl::anchor() { } +void UsingPackDecl::anchor() {} UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC, NamedDecl *InstantiatedFrom, @@ -2419,7 +2502,7 @@ UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, unsigned ID, return Result; } -void UnresolvedUsingValueDecl::anchor() { } +void UnresolvedUsingValueDecl::anchor() {} UnresolvedUsingValueDecl * UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, @@ -2447,7 +2530,7 @@ SourceRange UnresolvedUsingValueDecl::getSourceRange() const { return SourceRange(Begin, getNameInfo().getEndLoc()); } -void UnresolvedUsingTypenameDecl::anchor() { } +void UnresolvedUsingTypenameDecl::anchor() {} UnresolvedUsingTypenameDecl * UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, @@ -2469,7 +2552,7 @@ UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SourceLocation(), nullptr, SourceLocation()); } -void StaticAssertDecl::anchor() { } +void StaticAssertDecl::anchor() {} StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StaticAssertLoc, diff --git a/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp b/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp index 121403b07e575..461bf36858b74 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp @@ -1,4 +1,4 @@ -//===--- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation --===// +//===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===// // // The LLVM Compiler Infrastructure // @@ -12,12 +12,20 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstddef> + using namespace clang; -void FriendDecl::anchor() { } +void FriendDecl::anchor() {} FriendDecl *FriendDecl::getNextFriendSlowCase() { return cast_or_null<FriendDecl>( @@ -28,9 +36,9 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend, SourceLocation FriendL, - ArrayRef<TemplateParameterList*> FriendTypeTPLists) { + ArrayRef<TemplateParameterList *> FriendTypeTPLists) { #ifndef NDEBUG - if (Friend.is<NamedDecl*>()) { + if (Friend.is<NamedDecl *>()) { NamedDecl *D = Friend.get<NamedDecl*>(); assert(isa<FunctionDecl>(D) || isa<CXXRecordDecl>(D) || @@ -42,7 +50,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, assert(D->getFriendObjectKind() || (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); // These template parameters are for friend types only. - assert(FriendTypeTPLists.size() == 0); + assert(FriendTypeTPLists.empty()); } #endif diff --git a/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp b/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp index 2f95e1f1c345f..f74ef9bbb8391 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp @@ -1,4 +1,4 @@ -//===--- DeclGroup.cpp - Classes for representing groups of Decls -*- C++ -*-==// +//===- DeclGroup.cpp - Classes for representing groups of Decls -----------===// // // The LLVM Compiler Infrastructure // @@ -13,7 +13,9 @@ #include "clang/AST/DeclGroup.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" +#include <cassert> +#include <memory> + using namespace clang; DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { diff --git a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp index d8bdb6369e947..f95d5def47acc 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp @@ -1,4 +1,4 @@ -//===--- DeclObjC.cpp - ObjC Declaration AST Node Implementation ----------===// +//===- DeclObjC.cpp - ObjC Declaration AST Node Implementation ------------===// // // The LLVM Compiler Infrastructure // @@ -15,9 +15,27 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/Stmt.h" -#include "llvm/ADT/STLExtras.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <utility> + using namespace clang; //===----------------------------------------------------------------------===// @@ -28,7 +46,6 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { List = nullptr; if (Elts == 0) return; // Setting to an empty list is a noop. - List = new (Ctx) void*[Elts]; NumElts = Elts; memcpy(List, InList, sizeof(void*)*Elts); @@ -48,7 +65,7 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, // ObjCInterfaceDecl //===----------------------------------------------------------------------===// -void ObjCContainerDecl::anchor() { } +void ObjCContainerDecl::anchor() {} /// getIvarDecl - This method looks up an ivar in this ContextDecl. /// @@ -82,7 +99,6 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, // - (int) class_method; // + (float) class_method; // @end - // lookup_result R = lookup(Sel); for (lookup_iterator Meth = R.begin(), MethEnd = R.end(); Meth != MethEnd; ++Meth) { @@ -280,7 +296,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( return nullptr; } -void ObjCInterfaceDecl::anchor() { } +void ObjCInterfaceDecl::anchor() {} ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { // If this particular declaration has a type parameter list, return it. @@ -341,7 +357,6 @@ SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols /// (direct or indirect) used by the primary class. -/// ObjCPropertyDecl * ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( IdentifierInfo *PropertyId, @@ -409,8 +424,7 @@ const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const { void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, - ASTContext &C) -{ + ASTContext &C) { if (data().ExternallyCompleted) LoadExternalDefinition(); @@ -488,7 +502,7 @@ bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const { return true; case DefinitionData::IDI_NotInherited: return false; - case DefinitionData::IDI_Unknown: { + case DefinitionData::IDI_Unknown: // If the class introduced initializers we conservatively assume that we // don't know if any of them is a designated initializer to avoid possible // misleading warnings. @@ -510,7 +524,6 @@ bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const { return data().InheritedDesignatedInitializers == DefinitionData::IDI_Inherited; } - } llvm_unreachable("unexpected InheritedDesignatedInitializers value"); } @@ -902,7 +915,6 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), isInstanceMethod())) return MD; - } else if (ObjCCategoryImplDecl *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) @@ -1312,7 +1324,8 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { if (!CheckOverrides) return nullptr; - typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy; + using OverridesTy = SmallVector<const ObjCMethodDecl *, 8>; + OverridesTy Overrides; getOverriddenMethods(Overrides); for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end(); @@ -1328,7 +1341,7 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { // ObjCTypeParamDecl //===----------------------------------------------------------------------===// -void ObjCTypeParamDecl::anchor() { } +void ObjCTypeParamDecl::anchor() {} ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, ObjCTypeParamVariance variance, @@ -1373,14 +1386,12 @@ SourceRange ObjCTypeParamDecl::getSourceRange() const { ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc, ArrayRef<ObjCTypeParamDecl *> typeParams, SourceLocation rAngleLoc) - : NumParams(typeParams.size()) -{ + : NumParams(typeParams.size()) { Brackets.Begin = lAngleLoc.getRawEncoding(); Brackets.End = rAngleLoc.getRawEncoding(); std::copy(typeParams.begin(), typeParams.end(), begin()); } - ObjCTypeParamList *ObjCTypeParamList::create( ASTContext &ctx, SourceLocation lAngleLoc, @@ -1438,8 +1449,7 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *PrevDecl, bool IsInternal) : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc), - redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr), - Data() { + redeclarable_base(C) { setPreviousDecl(PrevDecl); // Copy the 'data' pointer over. @@ -1518,19 +1528,22 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { } namespace { - struct SynthesizeIvarChunk { - uint64_t Size; - ObjCIvarDecl *Ivar; - SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar) + +struct SynthesizeIvarChunk { + uint64_t Size; + ObjCIvarDecl *Ivar; + + SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar) : Size(size), Ivar(ivar) {} - }; +}; - bool operator<(const SynthesizeIvarChunk & LHS, - const SynthesizeIvarChunk &RHS) { - return LHS.Size < RHS.Size; - } +bool operator<(const SynthesizeIvarChunk & LHS, + const SynthesizeIvarChunk &RHS) { + return LHS.Size < RHS.Size; } +} // namespace + /// all_declared_ivar_begin - return first ivar declared in this class, /// its extensions and its implementation. Lazily build the list on first /// access. @@ -1694,7 +1707,7 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, // ObjCIvarDecl //===----------------------------------------------------------------------===// -void ObjCIvarDecl::anchor() { } +void ObjCIvarDecl::anchor() {} ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, @@ -1771,7 +1784,7 @@ QualType ObjCIvarDecl::getUsageType(QualType objectType) const { // ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// -void ObjCAtDefsFieldDecl::anchor() { } +void ObjCAtDefsFieldDecl::anchor() {} ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, @@ -1791,14 +1804,14 @@ ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C, // ObjCProtocolDecl //===----------------------------------------------------------------------===// -void ObjCProtocolDecl::anchor() { } +void ObjCProtocolDecl::anchor() {} ObjCProtocolDecl::ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, SourceLocation nameLoc, SourceLocation atStartLoc, ObjCProtocolDecl *PrevDecl) : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), - redeclarable_base(C), Data() { + redeclarable_base(C) { setPreviousDecl(PrevDecl); if (PrevDecl) Data = PrevDecl->Data; @@ -1874,7 +1887,6 @@ void ObjCProtocolDecl::startDefinition() { void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM, PropertyDeclOrder &PO) const { - if (const ObjCProtocolDecl *PDecl = getDefinition()) { for (auto *Prop : PDecl->properties()) { // Insert into PM if not there already. @@ -1921,7 +1933,7 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const { // ObjCCategoryDecl //===----------------------------------------------------------------------===// -void ObjCCategoryDecl::anchor() { } +void ObjCCategoryDecl::anchor() {} ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, @@ -1930,11 +1942,9 @@ ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) - : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), - ClassInterface(IDecl), TypeParamList(nullptr), - NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc), - IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) -{ + : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), + ClassInterface(IDecl), CategoryNameLoc(CategoryNameLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { setTypeParamList(typeParamList); } @@ -1994,7 +2004,7 @@ void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { // ObjCCategoryImplDecl //===----------------------------------------------------------------------===// -void ObjCCategoryImplDecl::anchor() { } +void ObjCCategoryImplDecl::anchor() {} ObjCCategoryImplDecl * ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, @@ -2023,8 +2033,7 @@ ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { return nullptr; } - -void ObjCImplDecl::anchor() { } +void ObjCImplDecl::anchor() {} void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { // FIXME: The context should be correct before we get here. @@ -2052,7 +2061,6 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of /// properties implemented in this \@implementation block and returns /// the implemented property that uses it. -/// ObjCPropertyImplDecl *ObjCImplDecl:: FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const { for (auto *PID : property_impls()) @@ -2065,7 +2073,6 @@ FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const { /// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl /// added to the list of those properties \@synthesized/\@dynamic in this /// category \@implementation block. -/// ObjCPropertyImplDecl *ObjCImplDecl:: FindPropertyImplDecl(IdentifierInfo *Id, ObjCPropertyQueryKind QueryKind) const { @@ -2103,7 +2110,7 @@ raw_ostream &clang::operator<<(raw_ostream &OS, // ObjCImplementationDecl //===----------------------------------------------------------------------===// -void ObjCImplementationDecl::anchor() { } +void ObjCImplementationDecl::anchor() {} ObjCImplementationDecl * ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, @@ -2155,7 +2162,7 @@ raw_ostream &clang::operator<<(raw_ostream &OS, // ObjCCompatibleAliasDecl //===----------------------------------------------------------------------===// -void ObjCCompatibleAliasDecl::anchor() { } +void ObjCCompatibleAliasDecl::anchor() {} ObjCCompatibleAliasDecl * ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, @@ -2175,7 +2182,7 @@ ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { // ObjCPropertyDecl //===----------------------------------------------------------------------===// -void ObjCPropertyDecl::anchor() { } +void ObjCPropertyDecl::anchor() {} ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, diff --git a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp index 6eeba88e40336..b792c5920a553 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp @@ -28,6 +28,7 @@ namespace { class DeclPrinter : public DeclVisitor<DeclPrinter> { raw_ostream &Out; PrintingPolicy Policy; + const ASTContext &Context; unsigned Indentation; bool PrintInstantiation; @@ -36,6 +37,8 @@ namespace { void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls); void Print(AccessSpecifier AS); + void PrintConstructorInitializers(CXXConstructorDecl *CDecl, + std::string &Proto); /// Print an Objective-C method type in parentheses. /// @@ -48,9 +51,10 @@ namespace { public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, - unsigned Indentation = 0, bool PrintInstantiation = false) - : Out(Out), Policy(Policy), Indentation(Indentation), - PrintInstantiation(PrintInstantiation) { } + const ASTContext &Context, unsigned Indentation = 0, + bool PrintInstantiation = false) + : Out(Out), Policy(Policy), Context(Context), Indentation(Indentation), + PrintInstantiation(PrintInstantiation) {} void VisitDeclContext(DeclContext *DC, bool Indent = true); @@ -115,7 +119,8 @@ void Decl::print(raw_ostream &Out, unsigned Indentation, void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation, bool PrintInstantiation) const { - DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation); + DeclPrinter Printer(Out, Policy, getASTContext(), Indentation, + PrintInstantiation); Printer.Visit(const_cast<Decl*>(this)); } @@ -192,7 +197,7 @@ LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const { DC = DC->getParent(); ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); - DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), 0); + DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), Ctx, 0); Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); } @@ -271,6 +276,71 @@ void DeclPrinter::Print(AccessSpecifier AS) { } } +void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl, + std::string &Proto) { + bool HasInitializerList = false; + for (const auto *BMInitializer : CDecl->inits()) { + if (BMInitializer->isInClassMemberInitializer()) + continue; + + if (!HasInitializerList) { + Proto += " : "; + Out << Proto; + Proto.clear(); + HasInitializerList = true; + } else + Out << ", "; + + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); + Out << *FD; + } else { + Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy); + } + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = nullptr; + Expr **Args = nullptr; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct = + dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, nullptr, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + assert(Args[I] != nullptr && "Expected non-null Expr"); + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, nullptr, Policy, Indentation); + } + } + } + Out << ")"; + if (BMInitializer->isPackExpansion()) + Out << "..."; + } +} + //---------------------------------------------------------------------------- // Common C declarations //---------------------------------------------------------------------------- @@ -467,7 +537,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { prettyPrintAttributes(D); if (Expr *Init = D->getInitExpr()) { Out << " = "; - Init->printPretty(Out, nullptr, Policy, Indentation); + Init->printPretty(Out, nullptr, Policy, Indentation, &Context); } } @@ -510,18 +580,24 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; std::string Proto; - if (!Policy.SuppressScope) { - if (const NestedNameSpecifier *NS = D->getQualifier()) { - llvm::raw_string_ostream OS(Proto); - NS->print(OS, Policy); + + if (Policy.FullyQualifiedName) { + Proto += D->getQualifiedNameAsString(); + } else { + if (!Policy.SuppressScope) { + if (const NestedNameSpecifier *NS = D->getQualifier()) { + llvm::raw_string_ostream OS(Proto); + NS->print(OS, Policy); + } } + Proto += D->getNameInfo().getAsString(); } - Proto += D->getNameInfo().getAsString(); + if (GuideDecl) Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString(); if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) { llvm::raw_string_ostream POut(Proto); - DeclPrinter TArgPrinter(POut, SubPolicy, Indentation); + DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation); TArgPrinter.printTemplateArguments(*TArgs); } @@ -539,7 +615,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += "("; if (FT) { llvm::raw_string_ostream POut(Proto); - DeclPrinter ParamPrinter(POut, SubPolicy, Indentation); + DeclPrinter ParamPrinter(POut, SubPolicy, Context, Indentation); for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { if (i) POut << ", "; ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); @@ -605,67 +681,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } if (CDecl) { - bool HasInitializerList = false; - for (const auto *BMInitializer : CDecl->inits()) { - if (BMInitializer->isInClassMemberInitializer()) - continue; - - if (!HasInitializerList) { - Proto += " : "; - Out << Proto; - Proto.clear(); - HasInitializerList = true; - } else - Out << ", "; - - if (BMInitializer->isAnyMemberInitializer()) { - FieldDecl *FD = BMInitializer->getAnyMember(); - Out << *FD; - } else { - Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy); - } - - Out << "("; - if (!BMInitializer->getInit()) { - // Nothing to print - } else { - Expr *Init = BMInitializer->getInit(); - if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) - Init = Tmp->getSubExpr(); - - Init = Init->IgnoreParens(); - - Expr *SimpleInit = nullptr; - Expr **Args = nullptr; - unsigned NumArgs = 0; - if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); - } else if (CXXConstructExpr *Construct - = dyn_cast<CXXConstructExpr>(Init)) { - Args = Construct->getArgs(); - NumArgs = Construct->getNumArgs(); - } else - SimpleInit = Init; - - if (SimpleInit) - SimpleInit->printPretty(Out, nullptr, Policy, Indentation); - else { - for (unsigned I = 0; I != NumArgs; ++I) { - assert(Args[I] != nullptr && "Expected non-null Expr"); - if (isa<CXXDefaultArgExpr>(Args[I])) - break; - - if (I) - Out << ", "; - Args[I]->printPretty(Out, nullptr, Policy, Indentation); - } - } - } - Out << ")"; - if (BMInitializer->isPackExpansion()) - Out << "..."; - } + if (!Policy.TerseOutput) + PrintConstructorInitializers(CDecl, Proto); } else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) { if (FT && FT->hasTrailingReturn()) { if (!GuideDecl) @@ -695,7 +712,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { // This is a K&R function definition, so we need to print the // parameters. Out << '\n'; - DeclPrinter ParamPrinter(Out, SubPolicy, Indentation); + DeclPrinter ParamPrinter(Out, SubPolicy, Context, Indentation); Indentation += Policy.Indentation; for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { Indent(); @@ -709,7 +726,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->getBody()) D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation); } else { - if (isa<CXXConstructorDecl>(*D)) + if (!Policy.TerseOutput && isa<CXXConstructorDecl>(*D)) Out << " {}"; } } @@ -1541,7 +1558,19 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { Out << ")"; if (auto *Init = D->getInitializer()) { Out << " initializer("; + switch (D->getInitializerKind()) { + case OMPDeclareReductionDecl::DirectInit: + Out << "omp_priv("; + break; + case OMPDeclareReductionDecl::CopyInit: + Out << "omp_priv = "; + break; + case OMPDeclareReductionDecl::CallInit: + break; + } Init->printPretty(Out, nullptr, Policy, 0); + if (D->getInitializerKind() == OMPDeclareReductionDecl::DirectInit) + Out << ")"; Out << ")"; } } diff --git a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp index 00a6739478bd4..a7949b310cefc 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp @@ -1,4 +1,4 @@ -//===--- DeclTemplate.cpp - Template Declaration AST Node Implementation --===// +//===- DeclTemplate.cpp - Template Declaration AST Node Implementation ----===// // // The LLVM Compiler Infrastructure // @@ -15,13 +15,28 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" -#include "clang/Basic/IdentifierTable.h" -#include "llvm/ADT/STLExtras.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstdint> #include <memory> +#include <utility> + using namespace clang; //===----------------------------------------------------------------------===// @@ -33,9 +48,9 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, Expr *RequiresClause) - : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), - NumParams(Params.size()), ContainsUnexpandedParameterPack(false), - HasRequiresClause(static_cast<bool>(RequiresClause)) { + : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), + NumParams(Params.size()), ContainsUnexpandedParameterPack(false), + HasRequiresClause(static_cast<bool>(RequiresClause)) { for (unsigned Idx = 0; Idx < NumParams; ++Idx) { NamedDecl *P = Params[Idx]; begin()[Idx] = P; @@ -124,10 +139,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, } namespace clang { + void *allocateDefaultArgStorageChain(const ASTContext &C) { return new (C) char[sizeof(void*) * 2]; } -} + +} // namespace clang //===----------------------------------------------------------------------===// // RedeclarableTemplateDecl Implementation @@ -165,14 +182,28 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } +void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { + // Grab the most recent declaration to ensure we've loaded any lazy + // redeclarations of this template. + CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); + if (CommonBasePtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonBasePtr->LazySpecializations; + CommonBasePtr->LazySpecializations = nullptr; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + template<class EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * RedeclarableTemplateDecl::findSpecializationImpl( llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args, void *&InsertPos) { - typedef SpecEntryTraits<EntryType> SETraits; + using SETraits = SpecEntryTraits<EntryType>; + llvm::FoldingSetNodeID ID; - EntryType::Profile(ID,Args, getASTContext()); + EntryType::Profile(ID, Args, getASTContext()); EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } @@ -181,7 +212,8 @@ template<class Derived, class EntryType> void RedeclarableTemplateDecl::addSpecializationImpl( llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry, void *InsertPos) { - typedef SpecEntryTraits<EntryType> SETraits; + using SETraits = SpecEntryTraits<EntryType>; + if (InsertPos) { #ifndef NDEBUG void *CorrectInsertPos; @@ -232,18 +264,7 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const { } void FunctionTemplateDecl::LoadLazySpecializations() const { - // Grab the most recent declaration to ensure we've loaded any lazy - // redeclarations of this template. - // - // FIXME: Avoid walking the entire redeclaration chain here. - Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); - if (CommonPtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - uint32_t *Specs = CommonPtr->LazySpecializations; - CommonPtr->LazySpecializations = nullptr; - for (uint32_t I = 0, N = *Specs++; I != N; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); - } + loadLazySpecializationsImpl(); } llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> & @@ -311,18 +332,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, } void ClassTemplateDecl::LoadLazySpecializations() const { - // Grab the most recent declaration to ensure we've loaded any lazy - // redeclarations of this template. - // - // FIXME: Avoid walking the entire redeclaration chain here. - Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); - if (CommonPtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - uint32_t *Specs = CommonPtr->LazySpecializations; - CommonPtr->LazySpecializations = nullptr; - for (uint32_t I = 0, N = *Specs++; I != N; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); - } + loadLazySpecializationsImpl(); } llvm::FoldingSetVector<ClassTemplateSpecializationDecl> & @@ -562,7 +572,7 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { // TemplateTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// -void TemplateTemplateParmDecl::anchor() { } +void TemplateTemplateParmDecl::anchor() {} TemplateTemplateParmDecl::TemplateTemplateParmDecl( DeclContext *DC, SourceLocation L, unsigned D, unsigned P, @@ -665,11 +675,12 @@ FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD, // TemplateDecl Implementation //===----------------------------------------------------------------------===// -void TemplateDecl::anchor() { } +void TemplateDecl::anchor() {} //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// + ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, SourceLocation StartLoc, @@ -677,11 +688,9 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args, ClassTemplateSpecializationDecl *PrevDecl) - : CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc, - SpecializedTemplate->getIdentifier(), - PrevDecl), + : CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc, + SpecializedTemplate->getIdentifier(), PrevDecl), SpecializedTemplate(SpecializedTemplate), - ExplicitInfo(nullptr), TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)), SpecializationKind(TSK_Undeclared) { } @@ -690,7 +699,7 @@ ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C, Kind DK) : CXXRecordDecl(DK, TTK_Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr), - ExplicitInfo(nullptr), SpecializationKind(TSK_Undeclared) {} + SpecializationKind(TSK_Undeclared) {} ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, @@ -726,12 +735,10 @@ void ClassTemplateSpecializationDecl::getNameForDiagnostic( auto *PS = dyn_cast<ClassTemplatePartialSpecializationDecl>(this); if (const ASTTemplateArgumentListInfo *ArgsAsWritten = PS ? PS->getTemplateArgsAsWritten() : nullptr) { - TemplateSpecializationType::PrintTemplateArgumentList( - OS, ArgsAsWritten->arguments(), Policy); + printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy); } else { const TemplateArgumentList &TemplateArgs = getTemplateArgs(); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, TemplateArgs.asArray(), Policy); + printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy); } } @@ -762,7 +769,7 @@ ClassTemplateSpecializationDecl::getSourceRange() const { // An implicit instantiation of a class template partial specialization // uses ExplicitInfo to record the TypeAsWritten, but the source // locations should be retrieved from the instantiation pattern. - typedef ClassTemplatePartialSpecializationDecl CTPSDecl; + using CTPSDecl = ClassTemplatePartialSpecializationDecl; CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this)); CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember(); assert(inst_from != nullptr); @@ -785,7 +792,7 @@ ClassTemplateSpecializationDecl::getSourceRange() const { //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// -void ClassTemplatePartialSpecializationDecl::anchor() { } +void ClassTemplatePartialSpecializationDecl::anchor() {} ClassTemplatePartialSpecializationDecl:: ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, @@ -797,14 +804,12 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, ArrayRef<TemplateArgument> Args, const ASTTemplateArgumentListInfo *ArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl) - : ClassTemplateSpecializationDecl(Context, - ClassTemplatePartialSpecialization, - TK, DC, StartLoc, IdLoc, - SpecializedTemplate, - Args, PrevDecl), - TemplateParams(Params), ArgsAsWritten(ArgInfos), - InstantiatedFromMember(nullptr, false) -{ + : ClassTemplateSpecializationDecl(Context, + ClassTemplatePartialSpecialization, + TK, DC, StartLoc, IdLoc, + SpecializedTemplate, Args, PrevDecl), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + InstantiatedFromMember(nullptr, false) { AdoptTemplateParameterList(Params, this); } @@ -845,7 +850,7 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// -void FriendTemplateDecl::anchor() { } +void FriendTemplateDecl::anchor() {} FriendTemplateDecl * FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC, @@ -891,7 +896,7 @@ TypeAliasTemplateDecl::newCommon(ASTContext &C) const { // ClassScopeFunctionSpecializationDecl Implementation //===----------------------------------------------------------------------===// -void ClassScopeFunctionSpecializationDecl::anchor() { } +void ClassScopeFunctionSpecializationDecl::anchor() {} ClassScopeFunctionSpecializationDecl * ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, @@ -927,21 +932,8 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -// TODO: Unify across class, function and variable templates? -// May require moving this and Common to RedeclarableTemplateDecl. void VarTemplateDecl::LoadLazySpecializations() const { - // Grab the most recent declaration to ensure we've loaded any lazy - // redeclarations of this template. - // - // FIXME: Avoid walking the entire redeclaration chain here. - Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); - if (CommonPtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - uint32_t *Specs = CommonPtr->LazySpecializations; - CommonPtr->LazySpecializations = nullptr; - for (uint32_t I = 0, N = *Specs++; I != N; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); - } + loadLazySpecializationsImpl(); } llvm::FoldingSetVector<VarTemplateSpecializationDecl> & @@ -1020,21 +1012,22 @@ VarTemplateDecl::findPartialSpecInstantiatedFromMember( //===----------------------------------------------------------------------===// // VarTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// + VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( Kind DK, ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument> Args) : VarDecl(DK, Context, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T, TInfo, S), - SpecializedTemplate(SpecializedTemplate), ExplicitInfo(nullptr), + SpecializedTemplate(SpecializedTemplate), TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)), - SpecializationKind(TSK_Undeclared) {} + SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {} VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK, ASTContext &C) : VarDecl(DK, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None), - ExplicitInfo(nullptr), SpecializationKind(TSK_Undeclared) {} + SpecializationKind(TSK_Undeclared), IsCompleteDefinition(false) {} VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, @@ -1058,12 +1051,10 @@ void VarTemplateSpecializationDecl::getNameForDiagnostic( auto *PS = dyn_cast<VarTemplatePartialSpecializationDecl>(this); if (const ASTTemplateArgumentListInfo *ArgsAsWritten = PS ? PS->getTemplateArgsAsWritten() : nullptr) { - TemplateSpecializationType::PrintTemplateArgumentList( - OS, ArgsAsWritten->arguments(), Policy); + printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy); } else { const TemplateArgumentList &TemplateArgs = getTemplateArgs(); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, TemplateArgs.asArray(), Policy); + printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy); } } @@ -1085,6 +1076,7 @@ void VarTemplateSpecializationDecl::setTemplateArgsInfo( //===----------------------------------------------------------------------===// // VarTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// + void VarTemplatePartialSpecializationDecl::anchor() {} VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl( diff --git a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp index 1f8e26deda979..31bae93c3cb56 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp @@ -1,4 +1,4 @@ -//===-- DeclarationName.cpp - Declaration names implementation --*- C++ -*-===// +//===- DeclarationName.cpp - Declaration names implementation -------------===// // // The LLVM Compiler Infrastructure // @@ -11,20 +11,36 @@ // classes. // //===----------------------------------------------------------------------===// + #include "clang/AST/DeclarationName.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <string> + using namespace clang; namespace clang { + /// CXXSpecialName - Records the type associated with one of the /// "special" kinds of declaration names in C++, e.g., constructors, /// destructors, and conversion functions. @@ -89,6 +105,8 @@ public: } }; +} // namespace clang + static int compareInt(unsigned A, unsigned B) { return (A < B ? -1 : (A > B ? 1 : 0)); } @@ -197,10 +215,9 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { case DeclarationName::CXXConstructorName: return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy); - case DeclarationName::CXXDestructorName: { + case DeclarationName::CXXDestructorName: OS << '~'; return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy); - } case DeclarationName::CXXDeductionGuideName: OS << "<deduction guide for "; @@ -250,13 +267,15 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { llvm_unreachable("Unexpected declaration name kind"); } +namespace clang { + raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { LangOptions LO; N.print(OS, PrintingPolicy(LO)); return OS; } -} // end namespace clang +} // namespace clang DeclarationName::NameKind DeclarationName::getNameKind() const { switch (getStoredNameKind()) { diff --git a/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp index afc7fa8ea0949..55061aa462e5c 100644 --- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Expr.cpp @@ -1695,6 +1695,26 @@ CXXBaseSpecifier **CastExpr::path_buffer() { } } +const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, + QualType opType) { + auto RD = unionType->castAs<RecordType>()->getDecl(); + return getTargetFieldForToUnionCast(RD, opType); +} + +const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD, + QualType OpType) { + auto &Ctx = RD->getASTContext(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(), FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Ctx.hasSameUnqualifiedType(Field->getType(), OpType) && + !Field->isUnnamedBitfield()) { + return *Field; + } + } + return nullptr; +} + ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, @@ -1760,6 +1780,7 @@ BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { case OO_Amp: return BO_And; case OO_Pipe: return BO_Or; case OO_Equal: return BO_Assign; + case OO_Spaceship: return BO_Cmp; case OO_Less: return BO_LT; case OO_Greater: return BO_GT; case OO_PlusEqual: return BO_AddAssign; @@ -1791,6 +1812,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { OO_Star, OO_Slash, OO_Percent, OO_Plus, OO_Minus, OO_LessLess, OO_GreaterGreater, + OO_Spaceship, OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual, OO_EqualEqual, OO_ExclaimEqual, OO_Amp, @@ -1809,6 +1831,38 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } +bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx, + Opcode Opc, + Expr *LHS, Expr *RHS) { + if (Opc != BO_Add) + return false; + + // Check that we have one pointer and one integer operand. + Expr *PExp; + if (LHS->getType()->isPointerType()) { + if (!RHS->getType()->isIntegerType()) + return false; + PExp = LHS; + } else if (RHS->getType()->isPointerType()) { + if (!LHS->getType()->isIntegerType()) + return false; + PExp = RHS; + } else { + return false; + } + + // Check that the pointer is a nullptr. + if (!PExp->IgnoreParenCasts() + ->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) + return false; + + // Check that the pointee type is char-sized. + const PointerType *PTy = PExp->getType()->getAs<PointerType>(); + if (!PTy || !PTy->getPointeeType()->isCharType()) + return false; + + return true; +} InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, @@ -1899,6 +1953,17 @@ bool InitListExpr::isTransparent() const { getInit(0)->getType().getCanonicalType(); } +bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const { + assert(isSyntacticForm() && "only test syntactic form as zero initializer"); + + if (LangOpts.CPlusPlus || getNumInits() != 1) { + return false; + } + + const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0)); + return Lit && Lit->getValue() == 0; +} + SourceLocation InitListExpr::getLocStart() const { if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getLocStart(); @@ -2235,7 +2300,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr()->IgnoreParens()); if (!(DRE && isa<VarDecl>(DRE->getDecl()) && - cast<VarDecl>(DRE->getDecl())->hasLocalStorage())) { + cast<VarDecl>(DRE->getDecl())->hasLocalStorage()) && + !isa<CallExpr>(CE->getSubExpr()->IgnoreParens())) { return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } @@ -3230,20 +3296,20 @@ Expr::isNullPointerConstant(ASTContext &Ctx, // Check that it is a cast to void*. if (const PointerType *PT = CE->getType()->getAs<PointerType>()) { QualType Pointee = PT->getPointeeType(); - Qualifiers Q = Pointee.getQualifiers(); - // In OpenCL v2.0 generic address space acts as a placeholder - // and should be ignored. - bool IsASValid = true; - if (Ctx.getLangOpts().OpenCLVersion >= 200) { - if (Pointee.getAddressSpace() == LangAS::opencl_generic) - Q.removeAddressSpace(); - else - IsASValid = false; - } + // Only (void*)0 or equivalent are treated as nullptr. If pointee type + // has non-default address space it is not treated as nullptr. + // (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr + // since it cannot be assigned to a pointer to constant address space. + bool PointeeHasDefaultAS = + Pointee.getAddressSpace() == LangAS::Default || + (Ctx.getLangOpts().OpenCLVersion >= 200 && + Pointee.getAddressSpace() == LangAS::opencl_generic) || + (Ctx.getLangOpts().OpenCL && + Ctx.getLangOpts().OpenCLVersion < 200 && + Pointee.getAddressSpace() == LangAS::opencl_private); - if (IsASValid && !Q.hasQualifiers() && - Pointee->isVoidType() && // to void* - CE->getSubExpr()->getType()->isIntegerType()) // from int. + if (PointeeHasDefaultAS && Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } } @@ -3938,10 +4004,12 @@ AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { switch (Op) { case AO__c11_atomic_init: + case AO__opencl_atomic_init: case AO__c11_atomic_load: case AO__atomic_load_n: return 2; + case AO__opencl_atomic_load: case AO__c11_atomic_store: case AO__c11_atomic_exchange: case AO__atomic_load: @@ -3967,6 +4035,15 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__atomic_nand_fetch: return 3; + case AO__opencl_atomic_store: + case AO__opencl_atomic_exchange: + case AO__opencl_atomic_fetch_add: + case AO__opencl_atomic_fetch_sub: + case AO__opencl_atomic_fetch_and: + case AO__opencl_atomic_fetch_or: + case AO__opencl_atomic_fetch_xor: + case AO__opencl_atomic_fetch_min: + case AO__opencl_atomic_fetch_max: case AO__atomic_exchange: return 4; @@ -3974,6 +4051,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__c11_atomic_compare_exchange_weak: return 5; + case AO__opencl_atomic_compare_exchange_strong: + case AO__opencl_atomic_compare_exchange_weak: case AO__atomic_compare_exchange: case AO__atomic_compare_exchange_n: return 6; @@ -3981,6 +4060,13 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { llvm_unreachable("unknown atomic op"); } +QualType AtomicExpr::getValueType() const { + auto T = getPtr()->getType()->castAs<PointerType>()->getPointeeType(); + if (auto AT = T->getAs<AtomicType>()) + return AT->getValueType(); + return T; +} + QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) { unsigned ArraySectionCount = 0; while (auto *OASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParens())) { diff --git a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp index fe45b5e47f36d..262a1e3ff9d58 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp @@ -1,4 +1,4 @@ -//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===// +//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===// // // The LLVM Compiler Infrastructure // @@ -11,15 +11,33 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/IdentifierTable.h" -using namespace clang; +#include "clang/Basic/LLVM.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstddef> +#include <cstring> +#include <memory> +using namespace clang; //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements @@ -85,15 +103,14 @@ CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew, Expr *initializer, QualType ty, TypeSourceInfo *allocatedTypeInfo, SourceRange Range, SourceRange directInitRange) - : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, - ty->isDependentType(), ty->isDependentType(), - ty->isInstantiationDependentType(), - ty->containsUnexpandedParameterPack()), - SubExprs(nullptr), OperatorNew(operatorNew), OperatorDelete(operatorDelete), - AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens), - Range(Range), DirectInitRange(directInitRange), - GlobalNew(globalNew), PassAlignment(PassAlignment), - UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { + : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), + ty->isDependentType(), ty->isInstantiationDependentType(), + ty->containsUnexpandedParameterPack()), + OperatorNew(operatorNew), OperatorDelete(operatorDelete), + AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens), + Range(Range), DirectInitRange(directInitRange), GlobalNew(globalNew), + PassAlignment(PassAlignment), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { assert((initializer != nullptr || initializationStyle == NoInit) && "Only NoInit can have no initializer."); StoredInitializationStyle = initializer ? initializationStyle + 1 : 0; @@ -160,6 +177,22 @@ bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); + + // For a destroying operator delete, we may have implicitly converted the + // pointer type to the type of the parameter of the 'operator delete' + // function. + while (auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ICE->getCastKind() == CK_DerivedToBase || + ICE->getCastKind() == CK_UncheckedDerivedToBase || + ICE->getCastKind() == CK_NoOp) { + assert((ICE->getCastKind() == CK_NoOp || + getOperatorDelete()->isDestroyingOperatorDelete()) && + "only a destroying operator delete can have a converted arg"); + Arg = ICE->getSubExpr(); + } else + break; + } + // The type-to-delete may not be a pointer if it's a dependent type. const QualType ArgType = Arg->getType(); @@ -171,8 +204,7 @@ QualType CXXDeleteExpr::getDestroyedType() const { // CXXPseudoDestructorExpr PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) - : Type(Info) -{ + : Type(Info) { Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } @@ -209,7 +241,7 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context, Base(static_cast<Stmt *>(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), - DestroyedType(DestroyedType) { } + DestroyedType(DestroyedType) {} QualType CXXPseudoDestructorExpr::getDestroyedType() const { if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) @@ -235,8 +267,7 @@ UnresolvedLookupExpr::Create(const ASTContext &C, bool ADL, const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin, - UnresolvedSetIterator End) -{ + UnresolvedSetIterator End) { assert(Args || TemplateKWLoc.isValid()); unsigned num_args = Args ? Args->size() : 0; @@ -274,21 +305,20 @@ OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C, bool KnownDependent, bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack) - : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent, - KnownDependent, - (KnownInstantiationDependent || - NameInfo.isInstantiationDependent() || - (QualifierLoc && - QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())), - (KnownContainsUnexpandedParameterPack || - NameInfo.containsUnexpandedParameterPack() || - (QualifierLoc && - QualifierLoc.getNestedNameSpecifier() - ->containsUnexpandedParameterPack()))), - NameInfo(NameInfo), QualifierLoc(QualifierLoc), - Results(nullptr), NumResults(End - Begin), - HasTemplateKWAndArgsInfo(TemplateArgs != nullptr || - TemplateKWLoc.isValid()) { + : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent, + KnownDependent, + (KnownInstantiationDependent || + NameInfo.isInstantiationDependent() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())), + (KnownContainsUnexpandedParameterPack || + NameInfo.containsUnexpandedParameterPack() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()))), + NameInfo(NameInfo), QualifierLoc(QualifierLoc), NumResults(End - Begin), + HasTemplateKWAndArgsInfo(TemplateArgs != nullptr || + TemplateKWLoc.isValid()) { NumResults = End - Begin; if (NumResults) { // Determine whether this expression is type-dependent. @@ -493,7 +523,6 @@ CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { return nullptr; } - CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() const { Expr* ThisArg = getImplicitObjectArgument(); if (!ThisArg) @@ -505,7 +534,6 @@ CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() const { return ThisArg->getType()->getAsCXXRecordDecl(); } - //===----------------------------------------------------------------------===// // Named casts //===----------------------------------------------------------------------===// @@ -742,16 +770,12 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization) - : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type, - TSI->getTypeLoc().getBeginLoc(), - Cons, false, Args, - HadMultipleCandidates, - ListInitialization, - StdInitListInitialization, - ZeroInitialization, - CXXConstructExpr::CK_Complete, ParenOrBraceRange), - Type(TSI) { -} + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type, + TSI->getTypeLoc().getBeginLoc(), Cons, false, Args, + HadMultipleCandidates, ListInitialization, + StdInitListInitialization, ZeroInitialization, + CXXConstructExpr::CK_Complete, ParenOrBraceRange), + Type(TSI) {} SourceLocation CXXTemporaryObjectExpr::getLocStart() const { return Type->getTypeLoc().getBeginLoc(); @@ -794,18 +818,16 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange) - : Expr(SC, T, VK_RValue, OK_Ordinary, - T->isDependentType(), T->isDependentType(), - T->isInstantiationDependentType(), - T->containsUnexpandedParameterPack()), - Constructor(Ctor), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange), - NumArgs(Args.size()), - Elidable(Elidable), HadMultipleCandidates(HadMultipleCandidates), - ListInitialization(ListInitialization), - StdInitListInitialization(StdInitListInitialization), - ZeroInitialization(ZeroInitialization), - ConstructKind(ConstructKind), Args(nullptr) -{ + : Expr(SC, T, VK_RValue, OK_Ordinary, + T->isDependentType(), T->isDependentType(), + T->isInstantiationDependentType(), + T->containsUnexpandedParameterPack()), + Constructor(Ctor), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange), + NumArgs(Args.size()), Elidable(Elidable), + HadMultipleCandidates(HadMultipleCandidates), + ListInitialization(ListInitialization), + StdInitListInitialization(StdInitListInitialization), + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind) { if (NumArgs) { this->Args = new (C) Stmt*[Args.size()]; @@ -827,8 +849,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) - : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) -{ + : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; if (Implicit) Bits |= Capture_Implicit; @@ -995,7 +1016,7 @@ CompoundStmt *LambdaExpr::getBody() const { // initialized in ASTStmtReader::VisitLambdaExpr, but for reasons I // don't understand, that doesn't work. if (!getStoredStmts()[NumCaptures]) - *const_cast<clang::Stmt **>(&getStoredStmts()[NumCaptures]) = + *const_cast<Stmt **>(&getStoredStmts()[NumCaptures]) = getCallOperator()->getBody(); return static_cast<CompoundStmt *>(getStoredStmts()[NumCaptures]); @@ -1008,12 +1029,12 @@ bool LambdaExpr::isMutable() const { ExprWithCleanups::ExprWithCleanups(Expr *subexpr, bool CleanupsHaveSideEffects, ArrayRef<CleanupObject> objects) - : Expr(ExprWithCleanupsClass, subexpr->getType(), - subexpr->getValueKind(), subexpr->getObjectKind(), - subexpr->isTypeDependent(), subexpr->isValueDependent(), - subexpr->isInstantiationDependent(), - subexpr->containsUnexpandedParameterPack()), - SubExpr(subexpr) { + : Expr(ExprWithCleanupsClass, subexpr->getType(), + subexpr->getValueKind(), subexpr->getObjectKind(), + subexpr->isTypeDependent(), subexpr->isValueDependent(), + subexpr->isInstantiationDependent(), + subexpr->containsUnexpandedParameterPack()), + SubExpr(subexpr) { ExprWithCleanupsBits.CleanupsHaveSideEffects = CleanupsHaveSideEffects; ExprWithCleanupsBits.NumObjects = objects.size(); for (unsigned i = 0, e = objects.size(); i != e; ++i) @@ -1030,7 +1051,7 @@ ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr, } ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects) - : Expr(ExprWithCleanupsClass, empty) { + : Expr(ExprWithCleanupsClass, empty) { ExprWithCleanupsBits.NumObjects = numObjects; } @@ -1046,20 +1067,18 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, ArrayRef<Expr*> Args, SourceLocation RParenLoc) - : Expr(CXXUnresolvedConstructExprClass, - Type->getType().getNonReferenceType(), - (Type->getType()->isLValueReferenceType() ? VK_LValue - :Type->getType()->isRValueReferenceType()? VK_XValue - :VK_RValue), - OK_Ordinary, - Type->getType()->isDependentType() || - Type->getType()->getContainedDeducedType(), - true, true, - Type->getType()->containsUnexpandedParameterPack()), - Type(Type), - LParenLoc(LParenLoc), - RParenLoc(RParenLoc), - NumArgs(Args.size()) { + : Expr(CXXUnresolvedConstructExprClass, + Type->getType().getNonReferenceType(), + (Type->getType()->isLValueReferenceType() + ? VK_LValue + : Type->getType()->isRValueReferenceType() ? VK_XValue + : VK_RValue), + OK_Ordinary, + Type->getType()->isDependentType() || + Type->getType()->getContainedDeducedType(), + true, true, Type->getType()->containsUnexpandedParameterPack()), + Type(Type), LParenLoc(LParenLoc), RParenLoc(RParenLoc), + NumArgs(Args.size()) { Expr **StoredArgs = getTrailingObjects<Expr *>(); for (unsigned I = 0; I != Args.size(); ++I) { if (Args[I]->containsUnexpandedParameterPack()) @@ -1159,7 +1178,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C, void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); CXXDependentScopeMemberExpr *E = new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(), - 0, SourceLocation(), + false, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), nullptr, DeclarationNameInfo(), nullptr); @@ -1202,19 +1221,18 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, TemplateKWLoc, - MemberNameInfo, TemplateArgs, Begin, End, - // Dependent - ((Base && Base->isTypeDependent()) || - BaseType->isDependentType()), - ((Base && Base->isInstantiationDependent()) || - BaseType->isInstantiationDependentType()), - // Contains unexpanded parameter pack - ((Base && Base->containsUnexpandedParameterPack()) || - BaseType->containsUnexpandedParameterPack())), - IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), - Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { - + : OverloadExpr( + UnresolvedMemberExprClass, C, QualifierLoc, TemplateKWLoc, + MemberNameInfo, TemplateArgs, Begin, End, + // Dependent + ((Base && Base->isTypeDependent()) || BaseType->isDependentType()), + ((Base && Base->isInstantiationDependent()) || + BaseType->isInstantiationDependentType()), + // Contains unexpanded parameter pack + ((Base && Base->containsUnexpandedParameterPack()) || + BaseType->containsUnexpandedParameterPack())), + IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), + BaseType(BaseType), OperatorLoc(OperatorLoc) { // Check whether all of the members are non-static member functions, // and if so, mark give this bound-member type instead of overload type. if (hasOnlyNonStaticMemberFunctions(Begin, End)) @@ -1315,10 +1333,10 @@ SubstNonTypeTemplateParmPackExpr(QualType T, NonTypeTemplateParmDecl *Param, SourceLocation NameLoc, const TemplateArgument &ArgPack) - : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, - true, true, true, true), - Param(Param), Arguments(ArgPack.pack_begin()), - NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { } + : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, + true, true, true, true), + Param(Param), Arguments(ArgPack.pack_begin()), + NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) {} TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments)); @@ -1374,13 +1392,12 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc, bool Value) - : Expr(TypeTraitExprClass, T, VK_RValue, OK_Ordinary, - /*TypeDependent=*/false, - /*ValueDependent=*/false, - /*InstantiationDependent=*/false, - /*ContainsUnexpandedParameterPack=*/false), - Loc(Loc), RParenLoc(RParenLoc) -{ + : Expr(TypeTraitExprClass, T, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/false, + /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), + Loc(Loc), RParenLoc(RParenLoc) { TypeTraitExprBits.Kind = Kind; TypeTraitExprBits.Value = Value; TypeTraitExprBits.NumArgs = Args.size(); @@ -1415,4 +1432,4 @@ TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C, return new (Mem) TypeTraitExpr(EmptyShell()); } -void ArrayTypeTraitExpr::anchor() { } +void ArrayTypeTraitExpr::anchor() {} diff --git a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp index d149bdd0cdf97..3bb2b4eb5fc19 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp @@ -641,7 +641,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Records with any const fields (recursively) are not modifiable. if (const RecordType *R = CT->getAs<RecordType>()) if (R->hasConstFields()) - return Cl::CM_ConstQualified; + return Cl::CM_ConstQualifiedField; return Cl::CM_Modifiable; } @@ -695,6 +695,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { llvm_unreachable("CM_LValueCast and CL_LValue don't match"); case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty; case Cl::CM_ConstQualified: return MLV_ConstQualified; + case Cl::CM_ConstQualifiedField: return MLV_ConstQualifiedField; case Cl::CM_ConstAddrSpace: return MLV_ConstAddrSpace; case Cl::CM_ArrayType: return MLV_ArrayType; case Cl::CM_IncompleteType: return MLV_IncompleteType; diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index 792e8cc4a518b..9c9eeb79b40a4 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -62,7 +62,13 @@ namespace { static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) - return D->getType(); + // FIXME: It's unclear where we're supposed to take the type from, and + // this actually matters for arrays of unknown bound. Using the type of + // the most recent declaration isn't clearly correct in general. Eg: + // + // extern int arr[]; void f() { extern int arr[3]; }; + // constexpr int *p = &arr[1]; // valid? + return cast<ValueDecl>(D->getMostRecentDecl())->getType(); const Expr *Base = B.get<const Expr*>(); @@ -141,6 +147,12 @@ namespace { return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E); } + /// The bound to claim that an array of unknown bound has. + /// The value in MostDerivedArraySize is undefined in this case. So, set it + /// to an arbitrary value that's likely to loudly break things if it's used. + static const uint64_t AssumedSizeForUnsizedArray = + std::numeric_limits<uint64_t>::max() / 2; + /// Determines if an LValue with the given LValueBase will have an unsized /// array in its designator. /// Find the path length and type of the most-derived subobject in the given @@ -148,7 +160,8 @@ namespace { static unsigned findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base, ArrayRef<APValue::LValuePathEntry> Path, - uint64_t &ArraySize, QualType &Type, bool &IsArray) { + uint64_t &ArraySize, QualType &Type, bool &IsArray, + bool &FirstEntryIsUnsizedArray) { // This only accepts LValueBases from APValues, and APValues don't support // arrays that lack size info. assert(!isBaseAnAllocSizeCall(Base) && @@ -158,12 +171,18 @@ namespace { for (unsigned I = 0, N = Path.size(); I != N; ++I) { if (Type->isArrayType()) { - const ConstantArrayType *CAT = - cast<ConstantArrayType>(Ctx.getAsArrayType(Type)); - Type = CAT->getElementType(); - ArraySize = CAT->getSize().getZExtValue(); + const ArrayType *AT = Ctx.getAsArrayType(Type); + Type = AT->getElementType(); MostDerivedLength = I + 1; IsArray = true; + + if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) { + ArraySize = CAT->getSize().getZExtValue(); + } else { + assert(I == 0 && "unexpected unsized array designator"); + FirstEntryIsUnsizedArray = true; + ArraySize = AssumedSizeForUnsizedArray; + } } else if (Type->isAnyComplexType()) { const ComplexType *CT = Type->castAs<ComplexType>(); Type = CT->getElementType(); @@ -246,10 +265,12 @@ namespace { Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); if (V.getLValueBase()) { bool IsArray = false; + bool FirstIsUnsizedArray = false; MostDerivedPathLength = findMostDerivedSubobject( Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize, - MostDerivedType, IsArray); + MostDerivedType, IsArray, FirstIsUnsizedArray); MostDerivedIsArrayElement = IsArray; + FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray; } } } @@ -318,7 +339,7 @@ namespace { // The value in MostDerivedArraySize is undefined in this case. So, set it // to an arbitrary value that's likely to loudly break things if it's // used. - MostDerivedArraySize = std::numeric_limits<uint64_t>::max() / 2; + MostDerivedArraySize = AssumedSizeForUnsizedArray; MostDerivedPathLength = Entries.size(); } /// Update this designator to refer to the given base or member of this @@ -350,6 +371,7 @@ namespace { MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } + void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); /// Add N to the address of this subobject. @@ -357,6 +379,7 @@ namespace { if (Invalid || !N) return; uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); if (isMostDerivedAnUnsizedArray()) { + diagnoseUnsizedArrayPointerArithmetic(Info, E); // Can't verify -- trust that the user is doing the right thing (or if // not, trust that the caller will catch the bad behavior). // FIXME: Should we reject if this overflows, at least? @@ -573,6 +596,31 @@ namespace { /// declaration whose initializer is being evaluated, if any. APValue *EvaluatingDeclValue; + /// EvaluatingObject - Pair of the AST node that an lvalue represents and + /// the call index that that lvalue was allocated in. + typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject; + + /// EvaluatingConstructors - Set of objects that are currently being + /// constructed. + llvm::DenseSet<EvaluatingObject> EvaluatingConstructors; + + struct EvaluatingConstructorRAII { + EvalInfo &EI; + EvaluatingObject Object; + bool DidInsert; + EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object) + : EI(EI), Object(Object) { + DidInsert = EI.EvaluatingConstructors.insert(Object).second; + } + ~EvaluatingConstructorRAII() { + if (DidInsert) EI.EvaluatingConstructors.erase(Object); + } + }; + + bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) { + return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex)); + } + /// The current array initialization index, if we're performing array /// initialization. uint64_t ArrayInitIndex = -1; @@ -666,6 +714,7 @@ namespace { void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; + EvaluatingConstructors.insert({Base, 0}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -984,6 +1033,7 @@ namespace { void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) { Info = Other.Info; OldStatus = Other.OldStatus; + OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating; Other.Info = nullptr; } @@ -1067,9 +1117,19 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, setInvalid(); return false; } + // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there + // must actually be at least one array element; even a VLA cannot have a + // bound of zero. And if our index is nonzero, we already had a CCEDiag. return true; } +void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, + const Expr *E) { + Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed); + // Do not set the designator as invalid: we can represent this situation, + // and correct handling of __builtin_object_size requires us to do so. +} + void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N) { @@ -1213,8 +1273,6 @@ namespace { IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); - assert(!Designator.FirstEntryIsAnUnsizedArray && - "Unsized array with a valid base?"); V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); } @@ -1287,12 +1345,17 @@ namespace { if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base)) Designator.addDeclUnchecked(D, Virtual); } - void addUnsizedArray(EvalInfo &Info, QualType ElemTy) { - assert(Designator.Entries.empty() && getType(Base)->isPointerType()); - assert(isBaseAnAllocSizeCall(Base) && - "Only alloc_size bases can have unsized arrays"); - Designator.FirstEntryIsAnUnsizedArray = true; - Designator.addUnsizedArrayUnchecked(ElemTy); + void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { + if (!Designator.Entries.empty()) { + Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array); + Designator.setInvalid(); + return; + } + if (checkSubobject(Info, E, CSK_ArrayToPointer)) { + assert(getType(Base)->isPointerType() || getType(Base)->isArrayType()); + Designator.FirstEntryIsAnUnsizedArray = true; + Designator.addUnsizedArrayUnchecked(ElemTy); + } } void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { if (checkSubobject(Info, E, CSK_ArrayToPointer)) @@ -1756,6 +1819,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, } } for (const auto *I : RD->fields()) { + if (I->isUnnamedBitfield()) + continue; + if (!CheckConstantExpression(Info, DiagLoc, I->getType(), Value.getStructField(I->getFieldIndex()))) return false; @@ -2597,10 +2663,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if (Sub.Invalid) // A diagnostic will have already been produced. return handler.failed(); - if (Sub.isOnePastTheEnd()) { + if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) { if (Info.getLangOpts().CPlusPlus11) - Info.FFDiag(E, diag::note_constexpr_access_past_end) - << handler.AccessKind; + Info.FFDiag(E, Sub.isOnePastTheEnd() + ? diag::note_constexpr_access_past_end + : diag::note_constexpr_access_unsized_array) + << handler.AccessKind; else Info.FFDiag(E); return handler.failed(); @@ -3097,10 +3165,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } // During the construction of an object, it is not yet 'const'. - // FIXME: We don't set up EvaluatingDecl for local variables or temporaries, - // and this doesn't do quite the right thing for const subobjects of the + // FIXME: This doesn't do quite the right thing for const subobjects of the // object under construction. - if (LVal.getLValueBase() == Info.EvaluatingDecl) { + if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) { BaseType = Info.Ctx.getCanonicalType(BaseType); BaseType.removeLocalConst(); } @@ -4253,6 +4320,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, return false; } + EvalInfo::EvaluatingConstructorRAII EvalObj( + Info, {This.getLValueBase(), This.CallIndex}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -5459,7 +5528,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base, Result.setInvalid(E); QualType Pointee = E->getType()->castAs<PointerType>()->getPointeeType(); - Result.addUnsizedArray(Info, Pointee); + Result.addUnsizedArray(Info, E, Pointee); return true; } @@ -5669,7 +5738,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return true; } } - case CK_ArrayToPointerDecay: + + case CK_ArrayToPointerDecay: { if (SubExpr->isGLValue()) { if (!evaluateLValue(SubExpr, Result)) return false; @@ -5680,12 +5750,13 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return false; } // The result is a pointer to the first element of the array. - if (const ConstantArrayType *CAT - = Info.Ctx.getAsConstantArrayType(SubExpr->getType())) + auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType()); + if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) Result.addArray(Info, E, CAT); else - Result.Designator.setInvalid(); + Result.addUnsizedArray(Info, E, AT->getElementType()); return true; + } case CK_FunctionToPointerDecay: return evaluateLValue(SubExpr, Result); @@ -5752,7 +5823,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { Result.setInvalid(E); QualType PointeeTy = E->getType()->castAs<PointerType>()->getPointeeType(); - Result.addUnsizedArray(Info, PointeeTy); + Result.addUnsizedArray(Info, E, PointeeTy); return true; } @@ -7313,7 +7384,8 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) { /// Please note: this function is specialized for how __builtin_object_size /// views "objects". /// -/// If this encounters an invalid RecordDecl, it will always return true. +/// If this encounters an invalid RecordDecl or otherwise cannot determine the +/// correct result, it will always return true. static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { assert(!LVal.Designator.Invalid); @@ -7344,9 +7416,8 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { unsigned I = 0; QualType BaseType = getType(Base); if (LVal.Designator.FirstEntryIsAnUnsizedArray) { - assert(isBaseAnAllocSizeCall(Base) && - "Unsized array in non-alloc_size call?"); - // If this is an alloc_size base, we should ignore the initial array index + // If we don't know the array bound, conservatively assume we're looking at + // the final array element. ++I; BaseType = BaseType->castAs<PointerType>()->getPointeeType(); } @@ -7901,6 +7972,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return BuiltinOp == Builtin::BI__atomic_always_lock_free ? Success(0, E) : Error(E); } + case Builtin::BIomp_is_initial_device: + // We can decide statically which value the runtime would return if called. + return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); } } @@ -10397,6 +10471,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: + case BO_Cmp: // FIXME: Re-enable once we can evaluate this. // C99 6.6/3 allows assignments within unevaluated subexpressions of // constant expressions, but they can never be ICEs because an ICE cannot // contain an lvalue operand. diff --git a/contrib/llvm/tools/clang/lib/AST/ExprObjC.cpp b/contrib/llvm/tools/clang/lib/AST/ExprObjC.cpp index 31c1b3f156217..e1a23f5985892 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprObjC.cpp @@ -1,4 +1,4 @@ -//===--- ExprObjC.cpp - (ObjC) Expression AST Node Implementation ---------===// +//===- ExprObjC.cpp - (ObjC) Expression AST Node Implementation -----------===// // // The LLVM Compiler Infrastructure // @@ -12,8 +12,15 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ExprObjC.h" - #include "clang/AST/ASTContext.h" +#include "clang/AST/SelectorLocationsKind.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstdint> using namespace clang; @@ -45,7 +52,6 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C, ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements) { - void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumElements)); return new (Mem) ObjCArrayLiteral(EmptyShell(), NumElements); } diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp index 4f4a99794c5b0..6b75c51c6420f 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExternalASTMerger.h" @@ -32,26 +33,18 @@ template <typename T> struct Source { typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; -class LazyASTImporter : public ASTImporter { -public: - LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager, - ASTContext &FromContext, FileManager &FromFileManager) - : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, - /*MinimalImport=*/true) {} - Decl *Imported(Decl *From, Decl *To) override { - if (auto ToTag = dyn_cast<TagDecl>(To)) { - ToTag->setHasExternalLexicalStorage(); - ToTag->setMustBuildLookupTable(); - } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) { - ToNamespace->setHasExternalVisibleStorage(); - } - return ASTImporter::Imported(From, To); - } -}; +/// For the given DC, return the DC that is safe to perform lookups on. This is +/// the DC we actually want to work with most of the time. +const DeclContext *CanonicalizeDC(const DeclContext *DC) { + if (isa<LinkageSpecDecl>(DC)) + return DC->getRedeclContext(); + return DC; +} Source<const DeclContext *> LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, ASTImporter &ReverseImporter) { + DC = CanonicalizeDC(DC); if (DC->isTranslationUnit()) { return SourceTU; } @@ -61,100 +54,328 @@ LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, // If we couldn't find the parent DC in this TranslationUnit, give up. return nullptr; } - auto ND = cast<NamedDecl>(DC); + auto *ND = cast<NamedDecl>(DC); DeclarationName Name = ND->getDeclName(); Source<DeclarationName> SourceName = ReverseImporter.Import(Name); DeclContext::lookup_result SearchResult = SourceParentDC.get()->lookup(SourceName.get()); size_t SearchResultSize = SearchResult.size(); - // Handle multiple candidates once we have a test for it. - // This may turn up when we import template specializations correctly. - assert(SearchResultSize < 2); - if (SearchResultSize == 0) { - // couldn't find the name, so we have to give up + if (SearchResultSize == 0 || SearchResultSize > 1) { + // There are two cases here. First, we might not find the name. + // We might also find multiple copies, in which case we have no + // guarantee that the one we wanted is the one we pick. (E.g., + // if we have two specializations of the same template it is + // very hard to determine which is the one you want.) + // + // The Origins map fixes this problem by allowing the origin to be + // explicitly recorded, so we trigger that recording by returning + // nothing (rather than a possibly-inaccurate guess) here. return nullptr; } else { NamedDecl *SearchResultDecl = SearchResult[0]; - return dyn_cast<DeclContext>(SearchResultDecl); + if (isa<DeclContext>(SearchResultDecl) && + SearchResultDecl->getKind() == DC->getDeclKind()) + return cast<DeclContext>(SearchResultDecl)->getPrimaryContext(); + return nullptr; // This type of lookup is unsupported } } -bool IsForwardDeclaration(Decl *D) { - assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case - if (auto TD = dyn_cast<TagDecl>(D)) { - return !TD->isThisDeclarationADefinition(); - } else if (auto FD = dyn_cast<FunctionDecl>(D)) { - return !FD->isThisDeclarationADefinition(); - } else { - return false; - } -} +/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes. +/// +/// There are several modifications: +/// +/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few +/// others), which instructs Clang to refer to ExternalASTMerger. Also, it +/// forces MinimalImport to true, which is necessary to make this work. +/// - It maintains a reverse importer for use with names. This allows lookup of +/// arbitrary names in the source context. +/// - It updates the ExternalASTMerger's origin map as needed whenever a +/// it sees a DeclContext. +class LazyASTImporter : public ASTImporter { +private: + ExternalASTMerger &Parent; + ASTImporter Reverse; + const ExternalASTMerger::OriginMap &FromOrigins; -template <typename CallbackType> -void ForEachMatchingDC( - const DeclContext *DC, - llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers, - CallbackType Callback) { - for (const ExternalASTMerger::ImporterPair &IP : Importers) { - Source<TranslationUnitDecl *> SourceTU = - IP.Forward->getFromContext().getTranslationUnitDecl(); - if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) - Callback(IP, SourceDC); + llvm::raw_ostream &logs() { return Parent.logs(); } +public: + LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, + FileManager &ToFileManager, ASTContext &FromContext, + FileManager &FromFileManager, + const ExternalASTMerger::OriginMap &_FromOrigins) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + /*MinimalImport=*/true), + Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext, + ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {} + + /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin + /// map is kept up to date. Also set the appropriate flags. + Decl *Imported(Decl *From, Decl *To) override { + if (auto *ToDC = dyn_cast<DeclContext>(To)) { + const bool LoggingEnabled = Parent.LoggingEnabled(); + if (LoggingEnabled) + logs() << "(ExternalASTMerger*)" << (void*)&Parent + << " imported (DeclContext*)" << (void*)ToDC + << ", (ASTContext*)" << (void*)&getToContext() + << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From) + << ", (ASTContext*)" << (void*)&getFromContext() + << "\n"; + Source<DeclContext *> FromDC( + cast<DeclContext>(From)->getPrimaryContext()); + if (FromOrigins.count(FromDC) && + Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) { + if (LoggingEnabled) + logs() << "(ExternalASTMerger*)" << (void*)&Parent + << " forced origin (DeclContext*)" + << (void*)FromOrigins.at(FromDC).DC + << ", (ASTContext*)" + << (void*)FromOrigins.at(FromDC).AST + << "\n"; + Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC)); + } else { + if (LoggingEnabled) + logs() << "(ExternalASTMerger*)" << (void*)&Parent + << " maybe recording origin (DeclContext*)" << (void*)FromDC + << ", (ASTContext*)" << (void*)&getFromContext() + << "\n"; + Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()}); + } + } + if (auto *ToTag = dyn_cast<TagDecl>(To)) { + ToTag->setHasExternalLexicalStorage(); + ToTag->setMustBuildLookupTable(); + assert(Parent.CanComplete(ToTag)); + } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) { + ToNamespace->setHasExternalVisibleStorage(); + assert(Parent.CanComplete(ToNamespace)); + } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) { + ToContainer->setHasExternalLexicalStorage(); + ToContainer->setMustBuildLookupTable(); + assert(Parent.CanComplete(ToContainer)); + } + return ASTImporter::Imported(From, To); } -} + ASTImporter &GetReverse() { return Reverse; } +}; bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { + if (isa<FunctionDecl>(C.first.get())) + return false; return llvm::any_of(Decls, [&](const Candidate &D) { return C.first.get()->getKind() == D.first.get()->getKind(); }); } + } // end namespace -ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, - llvm::ArrayRef<ImporterEndpoint> Sources) { - for (const ImporterEndpoint &S : Sources) { - Importers.push_back( - {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM), - llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM, - /*MinimalImport=*/true)}); - } +ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr<ASTImporter> &I : Importers) + if (&I->getFromContext() == &OriginContext) + return *I; + llvm_unreachable("We should have an importer for this origin!"); } -bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, - DeclarationName Name) { - llvm::SmallVector<NamedDecl *, 1> Decls; - llvm::SmallVector<Candidate, 4> CompleteDecls; - llvm::SmallVector<Candidate, 4> ForwardDecls; +namespace { +LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger, + ASTContext &OriginContext) { + return static_cast<LazyASTImporter &>( + Merger.ImporterForOrigin(OriginContext)); +} +} - auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) { - if (IsForwardDeclaration(C.first.get())) { - if (!HasDeclOfSameType(ForwardDecls, C)) { - ForwardDecls.push_back(C); +bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr<ASTImporter> &I : Importers) + if (&I->getFromContext() == &OriginContext) + return true; + return false; +} + +template <typename CallbackType> +void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, + CallbackType Callback) { + if (Origins.count(DC)) { + ExternalASTMerger::DCOrigin Origin = Origins[DC]; + LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); + Callback(Importer, Importer.GetReverse(), Origin.DC); + } else { + bool DidCallback = false; + for (const std::unique_ptr<ASTImporter> &Importer : Importers) { + Source<TranslationUnitDecl *> SourceTU = + Importer->getFromContext().getTranslationUnitDecl(); + ASTImporter &Reverse = + static_cast<LazyASTImporter *>(Importer.get())->GetReverse(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) { + DidCallback = true; + if (Callback(*Importer, Reverse, SourceDC)) + break; } - } else { - CompleteDecls.push_back(C); } - }; + if (!DidCallback && LoggingEnabled()) + logs() << "(ExternalASTMerger*)" << (void*)this + << " asserting for (DeclContext*)" << (const void*)DC + << ", (ASTContext*)" << (void*)&Target.AST + << "\n"; + assert(DidCallback && "Couldn't find a source context matching our DC"); + } +} + +void ExternalASTMerger::CompleteType(TagDecl *Tag) { + assert(Tag->hasExternalLexicalStorage()); + ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get())); + if (SourceTag->hasExternalLexicalStorage()) + SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); + if (!SourceTag->getDefinition()) + return false; + Forward.Imported(SourceTag, Tag); + Forward.ImportDefinition(SourceTag); + Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); + return true; + }); +} +void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { + assert(Interface->hasExternalLexicalStorage()); ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { - DeclarationName FromName = IP.Reverse->Import(Name); - DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); - for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); - } + Interface, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + auto *SourceInterface = const_cast<ObjCInterfaceDecl *>( + cast<ObjCInterfaceDecl>(SourceDC.get())); + if (SourceInterface->hasExternalLexicalStorage()) + SourceInterface->getASTContext().getExternalSource()->CompleteType( + SourceInterface); + if (!SourceInterface->getDefinition()) + return false; + Forward.Imported(SourceInterface, Interface); + Forward.ImportDefinition(SourceInterface); + return true; }); +} - llvm::ArrayRef<Candidate> DeclsToReport = - CompleteDecls.empty() ? ForwardDecls : CompleteDecls; +bool ExternalASTMerger::CanComplete(DeclContext *Interface) { + assert(Interface->hasExternalLexicalStorage() || + Interface->hasExternalVisibleStorage()); + bool FoundMatchingDC = false; + ForEachMatchingDC(Interface, + [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + FoundMatchingDC = true; + return true; + }); + return FoundMatchingDC; +} - if (DeclsToReport.empty()) { - return false; +namespace { +bool IsSameDC(const DeclContext *D1, const DeclContext *D2) { + if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2)) + return true; // There are many cases where Objective-C is ambiguous. + if (auto *T1 = dyn_cast<TagDecl>(D1)) + if (auto *T2 = dyn_cast<TagDecl>(D2)) + if (T1->getFirstDecl() == T2->getFirstDecl()) + return true; + return D1 == D2 || D1 == CanonicalizeDC(D2); +} +} + +void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC, + DCOrigin Origin) { + LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); + ASTImporter &Reverse = Importer.GetReverse(); + Source<const DeclContext *> FoundFromDC = + LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse); + const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC); + if (DoRecord) + RecordOriginImpl(ToDC, Origin, Importer); + if (LoggingEnabled()) + logs() << "(ExternalASTMerger*)" << (void*)this + << (DoRecord ? " decided " : " decided NOT") + << " to record origin (DeclContext*)" << (void*)Origin.DC + << ", (ASTContext*)" << (void*)&Origin.AST + << "\n"; +} + +void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, + DCOrigin Origin) { + RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST)); +} + +void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, + ASTImporter &Importer) { + Origins[ToDC] = Origin; + Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC))); +} + +ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) { + AddSources(Sources); +} + +void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) { + for (const ImporterSource &S : Sources) { + assert(&S.AST != &Target.AST); + Importers.push_back(llvm::make_unique<LazyASTImporter>( + *this, Target.AST, Target.FM, S.AST, S.FM, S.OM)); + } +} + +void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { + if (LoggingEnabled()) + for (const ImporterSource &S : Sources) + logs() << "(ExternalASTMerger*)" << (void*)this + << " removing source (ASTContext*)" << (void*)&S.AST + << "\n"; + Importers.erase( + std::remove_if(Importers.begin(), Importers.end(), + [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool { + for (const ImporterSource &S : Sources) { + if (&Importer->getFromContext() == &S.AST) + return true; + } + return false; + }), + Importers.end()); + for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { + std::pair<const DeclContext *, DCOrigin> Origin = *OI; + bool Erase = false; + for (const ImporterSource &S : Sources) { + if (&S.AST == Origin.second.AST) { + Erase = true; + break; + } + } + if (Erase) + OI = Origins.erase(OI); + else + ++OI; } +} + +bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + llvm::SmallVector<NamedDecl *, 1> Decls; + llvm::SmallVector<Candidate, 4> Candidates; + + auto FilterFoundDecl = [&Candidates](const Candidate &C) { + if (!HasDeclOfSameType(Candidates, C)) + Candidates.push_back(C); + }; + + ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + DeclarationName FromName = Reverse.Import(Name); + DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, &Forward)); + } + return false; + }); - Decls.reserve(DeclsToReport.size()); - for (const Candidate &C : DeclsToReport) { + if (Candidates.empty()) + return false; + + Decls.reserve(Candidates.size()); + for (const Candidate &C : Candidates) { NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get())); assert(d); Decls.push_back(d); @@ -166,17 +387,16 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, void ExternalASTMerger::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Result) { - ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { - for (const Decl *SourceDecl : SourceDC.get()->decls()) { - if (IsKindWeWant(SourceDecl->getKind())) { - Decl *ImportedDecl = - IP.Forward->Import(const_cast<Decl *>(SourceDecl)); - assert(ImportedDecl->getDeclContext() == DC); - (void)ImportedDecl; - } - } - }); + ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + for (const Decl *SourceDecl : SourceDC.get()->decls()) { + if (IsKindWeWant(SourceDecl->getKind())) { + Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl)); + assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC)); + (void)ImportedDecl; + } + } + return false; + }); } diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp index 182d38242f596..198ba9d4fbdba 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp @@ -1,4 +1,4 @@ -//===- ExternalASTSource.cpp - Abstract External AST Interface --*- C++ -*-===// +//===- ExternalASTSource.cpp - Abstract External AST Interface ------------===// // // The LLVM Compiler Infrastructure // @@ -16,12 +16,16 @@ #include "clang/AST/ExternalASTSource.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/Module.h" +#include "llvm/ADT/None.h" #include "llvm/Support/ErrorHandling.h" +#include <cstdint> using namespace clang; -ExternalASTSource::~ExternalASTSource() { } +ExternalASTSource::~ExternalASTSource() = default; llvm::Optional<ExternalASTSource::ASTSourceDescriptor> ExternalASTSource::getSourceDescriptor(unsigned ID) { @@ -66,7 +70,7 @@ void ExternalASTSource::FinishedDeserializing() {} void ExternalASTSource::StartTranslationUnit(ASTConsumer *Consumer) {} -void ExternalASTSource::PrintStats() { } +void ExternalASTSource::PrintStats() {} bool ExternalASTSource::layoutRecordType( const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp index 692a455eafc08..d6bc16b6350fc 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp @@ -101,15 +101,17 @@ protected: public: ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { } - std::pair<uint64_t, unsigned> - getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override { + MemberPointerInfo + getMemberPointerInfo(const MemberPointerType *MPT) const override { const TargetInfo &Target = Context.getTargetInfo(); TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0); - uint64_t Width = Target.getTypeWidth(PtrDiff); - unsigned Align = Target.getTypeAlign(PtrDiff); + MemberPointerInfo MPI; + MPI.Width = Target.getTypeWidth(PtrDiff); + MPI.Align = Target.getTypeAlign(PtrDiff); + MPI.HasPadding = false; if (MPT->isMemberFunctionPointer()) - Width = 2 * Width; - return std::make_pair(Width, Align); + MPI.Width *= 2; + return MPI; } CallingConv getDefaultMethodCallConv(bool isVariadic) const override { diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp index 4e7c6c4edf370..f95dc8458e8a8 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp @@ -11,7 +11,7 @@ // which is used in GCC 3.2 and newer (and many compilers that are // ABI-compatible with GCC): // -// http://mentorembedded.github.io/cxx-abi/abi.html#mangling +// http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling // //===----------------------------------------------------------------------===// #include "clang/AST/Mangle.h" @@ -381,6 +381,7 @@ class CXXNameMangler { AbiTagState AbiTagsRoot; llvm::DenseMap<uintptr_t, unsigned> Substitutions; + llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -475,6 +476,8 @@ private: void mangleNameWithAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags); + void mangleModuleName(const Module *M); + void mangleModuleNamePrefix(StringRef Name); void mangleTemplateName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -517,7 +520,7 @@ private: void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleVendorQualifier(StringRef qualifier); - void mangleQualifiers(Qualifiers Quals); + void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr); void mangleRefQualifier(RefQualifierKind RefQualifier); void mangleObjCMethodName(const ObjCMethodDecl *MD); @@ -845,9 +848,9 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) { - // <name> ::= <nested-name> - // ::= <unscoped-name> - // ::= <unscoped-template-name> <template-args> + // <name> ::= [<module-name>] <nested-name> + // ::= [<module-name>] <unscoped-name> + // ::= [<module-name>] <unscoped-template-name> <template-args> // ::= <local-name> // const DeclContext *DC = getEffectiveDeclContext(ND); @@ -866,6 +869,19 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, DC = IgnoreLinkageSpecDecls(DC); + if (isLocalContainerContext(DC)) { + mangleLocalName(ND, AdditionalAbiTags); + return; + } + + // Do not mangle the owning module for an external linkage declaration. + // This enables backwards-compatibility with non-modular code, and is + // a valid choice since conflicts are not permitted by C++ Modules TS + // [basic.def.odr]/6.2. + if (!ND->hasExternalFormalLinkage()) + if (Module *M = ND->getOwningModuleForLinkage()) + mangleModuleName(M); + if (DC->isTranslationUnit() || isStdNamespace(DC)) { // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; @@ -879,12 +895,42 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, return; } - if (isLocalContainerContext(DC)) { - mangleLocalName(ND, AdditionalAbiTags); + mangleNestedName(ND, DC, AdditionalAbiTags); +} + +void CXXNameMangler::mangleModuleName(const Module *M) { + // Implement the C++ Modules TS name mangling proposal; see + // https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile + // + // <module-name> ::= W <unscoped-name>+ E + // ::= W <module-subst> <unscoped-name>* E + Out << 'W'; + mangleModuleNamePrefix(M->Name); + Out << 'E'; +} + +void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) { + // <module-subst> ::= _ <seq-id> # 0 < seq-id < 10 + // ::= W <seq-id - 10> _ # otherwise + auto It = ModuleSubstitutions.find(Name); + if (It != ModuleSubstitutions.end()) { + if (It->second < 10) + Out << '_' << static_cast<char>('0' + It->second); + else + Out << 'W' << (It->second - 10) << '_'; return; } - mangleNestedName(ND, DC, AdditionalAbiTags); + // FIXME: Preserve hierarchy in module names rather than flattening + // them to strings; use Module*s as substitution keys. + auto Parts = Name.rsplit('.'); + if (Parts.second.empty()) + Parts.second = Parts.first; + else + mangleModuleNamePrefix(Parts.first); + + Out << Parts.second.size() << Parts.second; + ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()}); } void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD, @@ -1233,14 +1279,23 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } if (II) { - // We must avoid conflicts between internally- and externally- - // linked variable and function declaration names in the same TU: + // Match GCC's naming convention for internal linkage symbols, for + // symbols that are not actually visible outside of this TU. GCC + // distinguishes between internal and external linkage symbols in + // its mangling, to support cases like this that were valid C++ prior + // to DR426: + // // void test() { extern void foo(); } // static void foo(); - // This naming convention is the same as that followed by GCC, - // though it shouldn't actually matter. + // + // Don't bother with the L marker for names in anonymous namespaces; the + // 12_GLOBAL__N_1 mangling is quite sufficient there, and this better + // matches GCC anyway, because GCC does not treat anonymous namespaces as + // implying internal linkage. if (ND && ND->getFormalLinkage() == InternalLinkage && - getEffectiveDeclContext(ND)->isFileContext()) + !ND->isExternallyVisible() && + getEffectiveDeclContext(ND)->isFileContext() && + !ND->isInAnonymousNamespace()) Out << 'L'; auto *FD = dyn_cast<FunctionDecl>(ND); @@ -1620,6 +1675,10 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { // the symbol in question isn't externally visible. if (!Number) Number = Context.getBlockId(Block, false); + else { + // Stored mangling numbers are 1-based. + --Number; + } Out << "Ub"; if (Number > 0) Out << Number - 1; @@ -1638,10 +1697,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // to emit that last part of the prefix here. if (Decl *Context = Lambda->getLambdaContextDecl()) { if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && - Context->getDeclContext()->isRecord()) { + !isa<ParmVarDecl>(Context)) { + // FIXME: 'inline auto [a, b] = []{ return ... };' does not get a + // reasonable mangling here. if (const IdentifierInfo *Name = cast<NamedDecl>(Context)->getIdentifier()) { mangleSourceName(Name); + const TemplateArgumentList *TemplateArgs = nullptr; + if (isTemplate(cast<NamedDecl>(Context), TemplateArgs)) + mangleTemplateArgs(*TemplateArgs); Out << 'M'; } } @@ -1866,6 +1930,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: + case Type::DependentAddressSpace: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -2130,6 +2195,9 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { // Proposal on cxx-abi-dev, 2015-10-21. // ::= aw # co_await case OO_Coawait: Out << "aw"; break; + // Proposed in cxx-abi github issue 43. + // ::= ss # <=> + case OO_Spaceship: Out << "ss"; break; case OO_None: case NUM_OVERLOADED_OPERATORS: @@ -2137,10 +2205,17 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { } } -void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { +void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST) { // Vendor qualifiers come first and if they are order-insensitive they must // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5. + // <type> ::= U <addrspace-expr> + if (DAST) { + Out << "U2ASI"; + mangleExpression(DAST->getAddrSpaceExpr()); + Out << "E"; + } + // Address space qualifiers start with an ordinary letter. if (Quals.hasAddressSpace()) { // Address space extension: @@ -2150,20 +2225,22 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // <type> ::= U <CUDA-addrspace> SmallString<64> ASString; - unsigned AS = Quals.getAddressSpace(); + LangAS AS = Quals.getAddressSpace(); if (Context.getASTContext().addressSpaceMapManglingFor(AS)) { // <target-addrspace> ::= "AS" <address-space-number> unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS); - ASString = "AS" + llvm::utostr(TargetAS); + if (TargetAS != 0) + ASString = "AS" + llvm::utostr(TargetAS); } else { switch (AS) { default: llvm_unreachable("Not a language specific address space"); - // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant | - // "generic" ] + // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" | + // "private"| "generic" ] case LangAS::opencl_global: ASString = "CLglobal"; break; case LangAS::opencl_local: ASString = "CLlocal"; break; case LangAS::opencl_constant: ASString = "CLconstant"; break; + case LangAS::opencl_private: ASString = "CLprivate"; break; case LangAS::opencl_generic: ASString = "CLgeneric"; break; // <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ] case LangAS::cuda_device: ASString = "CUdevice"; break; @@ -2171,7 +2248,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { case LangAS::cuda_shared: ASString = "CUshared"; break; } } - mangleVendorQualifier(ASString); + if (!ASString.empty()) + mangleVendorQualifier(ASString); } // The ARC ownership qualifiers start with underscores. @@ -2336,11 +2414,19 @@ void CXXNameMangler::mangleType(QualType T) { // substitution at the original type. } - if (quals) { - mangleQualifiers(quals); - // Recurse: even if the qualified type isn't yet substitutable, - // the unqualified type might be. - mangleType(QualType(ty, 0)); + if (quals || ty->isDependentAddressSpaceType()) { + if (const DependentAddressSpaceType *DAST = + dyn_cast<DependentAddressSpaceType>(ty)) { + SplitQualType splitDAST = DAST->getPointeeType().split(); + mangleQualifiers(splitDAST.Quals, DAST); + mangleType(QualType(splitDAST.Ty, 0)); + } else { + mangleQualifiers(quals); + + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. + mangleType(QualType(ty, 0)); + } } else { switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) @@ -2392,6 +2478,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) // ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits); // ::= Di # char32_t // ::= Ds # char16_t // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) @@ -2454,6 +2541,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Float16: + Out << "DF16_"; + break; case BuiltinType::Half: Out << "Dh"; break; @@ -2586,6 +2676,9 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) { if (PI.isConsumed()) mangleVendorQualifier("ns_consumed"); + + if (PI.isNoEscape()) + mangleVendorQualifier("noescape"); } // <type> ::= <function-type> @@ -2981,6 +3074,12 @@ void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { mangleType(T->getElementType()); } +void CXXNameMangler::mangleType(const DependentAddressSpaceType *T) { + SplitQualType split = T->getPointeeType().split(); + mangleQualifiers(split.Quals, T); + mangleType(QualType(split.Ty, 0)); +} + void CXXNameMangler::mangleType(const PackExpansionType *T) { // <type> ::= Dp <type> # pack expansion (C++0x) Out << "Dp"; @@ -3343,7 +3442,6 @@ recurse: case Expr::BlockExprClass: case Expr::ChooseExprClass: case Expr::CompoundLiteralExprClass: - case Expr::DesignatedInitExprClass: case Expr::ExtVectorElementExprClass: case Expr::GenericSelectionExprClass: case Expr::ObjCEncodeExprClass: @@ -3421,6 +3519,27 @@ recurse: break; } + case Expr::DesignatedInitExprClass: { + auto *DIE = cast<DesignatedInitExpr>(E); + for (const auto &Designator : DIE->designators()) { + if (Designator.isFieldDesignator()) { + Out << "di"; + mangleSourceName(Designator.getFieldName()); + } else if (Designator.isArrayDesignator()) { + Out << "dx"; + mangleExpression(DIE->getArrayIndex(Designator)); + } else { + assert(Designator.isArrayRangeDesignator() && + "unknown designator kind"); + Out << "dX"; + mangleExpression(DIE->getArrayRangeStart(Designator)); + mangleExpression(DIE->getArrayRangeEnd(Designator)); + } + } + mangleExpression(DIE->getInit()); + break; + } + case Expr::CXXDefaultArgExprClass: mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); break; @@ -3512,7 +3631,6 @@ recurse: if (const Expr *Base = PDE->getBase()) mangleMemberExprBase(Base, PDE->isArrow()); NestedNameSpecifier *Qualifier = PDE->getQualifier(); - QualType ScopeType; if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { if (Qualifier) { mangleUnresolvedPrefix(Qualifier, @@ -3578,6 +3696,16 @@ recurse: const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); unsigned N = CE->arg_size(); + if (CE->isListInitialization()) { + assert(N == 1 && "unexpected form for list initialization"); + auto *IL = cast<InitListExpr>(CE->getArg(0)); + Out << "tl"; + mangleType(CE->getType()); + mangleInitListElements(IL); + Out << "E"; + return; + } + Out << "cv"; mangleType(CE->getType()); if (N != 1) Out << '_'; @@ -4114,7 +4242,13 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { // get mangled if used as an rvalue of a known non-class type? assert(!parm->getType()->isArrayType() && "parameter's type is still an array type?"); - mangleQualifiers(parm->getType().getQualifiers()); + + if (const DependentAddressSpaceType *DAST = + dyn_cast<DependentAddressSpaceType>(parm->getType())) { + mangleQualifiers(DAST->getPointeeType().getQualifiers(), DAST); + } else { + mangleQualifiers(parm->getType().getQualifiers()); + } // Parameter index. if (parmIndex != 0) { diff --git a/contrib/llvm/tools/clang/lib/AST/Linkage.h b/contrib/llvm/tools/clang/lib/AST/Linkage.h new file mode 100644 index 0000000000000..e6489c7ef2b31 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Linkage.h @@ -0,0 +1,159 @@ +//===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides AST-internal utilities for linkage and visibility +// calculation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_AST_LINKAGE_H +#define LLVM_CLANG_LIB_AST_LINKAGE_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" + +namespace clang { +/// Kinds of LV computation. The linkage side of the computation is +/// always the same, but different things can change how visibility is +/// computed. +struct LVComputationKind { + /// The kind of entity whose visibility is ultimately being computed; + /// visibility computations for types and non-types follow different rules. + unsigned ExplicitKind : 1; + /// Whether explicit visibility attributes should be ignored. When set, + /// visibility may only be restricted by the visibility of template arguments. + unsigned IgnoreExplicitVisibility : 1; + /// Whether all visibility should be ignored. When set, we're only interested + /// in computing linkage. + unsigned IgnoreAllVisibility : 1; + + explicit LVComputationKind(NamedDecl::ExplicitVisibilityKind EK) + : ExplicitKind(EK), IgnoreExplicitVisibility(false), + IgnoreAllVisibility(false) {} + + NamedDecl::ExplicitVisibilityKind getExplicitVisibilityKind() const { + return static_cast<NamedDecl::ExplicitVisibilityKind>(ExplicitKind); + } + + bool isTypeVisibility() const { + return getExplicitVisibilityKind() == NamedDecl::VisibilityForType; + } + bool isValueVisibility() const { + return getExplicitVisibilityKind() == NamedDecl::VisibilityForValue; + } + + /// Do an LV computation when we only care about the linkage. + static LVComputationKind forLinkageOnly() { + LVComputationKind Result(NamedDecl::VisibilityForValue); + Result.IgnoreExplicitVisibility = true; + Result.IgnoreAllVisibility = true; + return Result; + } + + unsigned toBits() { + unsigned Bits = 0; + Bits = (Bits << 1) | ExplicitKind; + Bits = (Bits << 1) | IgnoreExplicitVisibility; + Bits = (Bits << 1) | IgnoreAllVisibility; + return Bits; + } +}; + +class LinkageComputer { + // We have a cache for repeated linkage/visibility computations. This saves us + // from exponential behavior in heavily templated code, such as: + // + // template <typename T, typename V> struct {}; + // using A = int; + // using B = Foo<A, A>; + // using C = Foo<B, B>; + // using D = Foo<C, C>; + // + // The unsigned represents an LVComputationKind. + using QueryType = std::pair<const NamedDecl *, unsigned>; + llvm::SmallDenseMap<QueryType, LinkageInfo, 8> CachedLinkageInfo; + + static QueryType makeCacheKey(const NamedDecl *ND, LVComputationKind Kind) { + return std::make_pair(ND, Kind.toBits()); + } + + llvm::Optional<LinkageInfo> lookup(const NamedDecl *ND, + LVComputationKind Kind) const { + auto Iter = CachedLinkageInfo.find(makeCacheKey(ND, Kind)); + if (Iter == CachedLinkageInfo.end()) + return None; + return Iter->second; + } + + void cache(const NamedDecl *ND, LVComputationKind Kind, LinkageInfo Info) { + CachedLinkageInfo[makeCacheKey(ND, Kind)] = Info; + } + + LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, + LVComputationKind computation); + + LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, + const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation); + + void mergeTemplateLV(LinkageInfo &LV, + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation); + + LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage); + + LinkageInfo getLVForClassMember(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage); + + LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, + LVComputationKind computation); + + LinkageInfo getLVForLocalDecl(const NamedDecl *D, + LVComputationKind computation); + + LinkageInfo getLVForType(const Type &T, LVComputationKind computation); + + LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params, + LVComputationKind computation); + +public: + LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation, + bool IgnoreVarTypeLinkage = false); + + LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); + + LinkageInfo computeTypeLinkageInfo(const Type *T); + LinkageInfo computeTypeLinkageInfo(QualType T) { + return computeTypeLinkageInfo(T.getTypePtr()); + } + + LinkageInfo getDeclLinkageAndVisibility(const NamedDecl *D); + + LinkageInfo getTypeLinkageAndVisibility(const Type *T); + LinkageInfo getTypeLinkageAndVisibility(QualType T) { + return getTypeLinkageAndVisibility(T.getTypePtr()); + } +}; +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp index 00d50c0e3bdf4..56a2500274a72 100644 --- a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp @@ -103,6 +103,11 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { if (CC != CCM_Other) return true; + // If the declaration has an owning module for linkage purposes that needs to + // be mangled, we must mangle its name. + if (!D->hasExternalFormalLinkage() && D->getOwningModuleForLinkage()) + return true; + // In C, functions with no attributes never need to be mangled. Fastpath them. if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) return false; diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp index 73324e40f3b10..b19491f313047 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp @@ -76,8 +76,8 @@ class MicrosoftCXXABI : public CXXABI { public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } - std::pair<uint64_t, unsigned> - getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override; + MemberPointerInfo + getMemberPointerInfo(const MemberPointerType *MPT) const override; CallingConv getDefaultMethodCallConv(bool isVariadic) const override { if (!isVariadic && @@ -227,7 +227,7 @@ getMSMemberPointerSlots(const MemberPointerType *MPT) { return std::make_pair(Ptrs, Ints); } -std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( +CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo( const MemberPointerType *MPT) const { // The nominal struct is laid out with pointers followed by ints and aligned // to a pointer width if any are present and an int width otherwise. @@ -237,22 +237,25 @@ std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( unsigned Ptrs, Ints; std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); - uint64_t Width = Ptrs * PtrSize + Ints * IntSize; - unsigned Align; + MemberPointerInfo MPI; + MPI.HasPadding = false; + MPI.Width = Ptrs * PtrSize + Ints * IntSize; // When MSVC does x86_32 record layout, it aligns aggregate member pointers to // 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for // function memptrs. if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit()) - Align = 64; + MPI.Align = 64; else if (Ptrs) - Align = Target.getPointerAlign(0); + MPI.Align = Target.getPointerAlign(0); else - Align = Target.getIntAlign(); + MPI.Align = Target.getIntAlign(); - if (Target.getTriple().isArch64Bit()) - Width = llvm::alignTo(Width, Align); - return std::make_pair(Width, Align); + if (Target.getTriple().isArch64Bit()) { + MPI.Width = llvm::alignTo(MPI.Width, MPI.Align); + MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize); + } + return MPI; } CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp index 24b16f892e7a9..0c55c1a922873 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp @@ -1192,6 +1192,15 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, // <operator-name> ::= ?__L # co_await case OO_Coawait: Out << "?__L"; break; + case OO_Spaceship: { + // FIXME: Once MS picks a mangling, use it. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this three-way comparison operator yet"); + Diags.Report(Loc, DiagID); + break; + } + case OO_Conditional: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -1866,6 +1875,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, Out << "$$T"; break; + case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Half: { DiagnosticsEngine &Diags = Context.getDiags(); @@ -2324,13 +2334,15 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, manglePointerExtQualifiers(Quals, PointeeType); mangleType(PointeeType, Range); } + void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, Qualifiers Quals, SourceRange Range) { + if (T->isObjCIdType() || T->isObjCClassType()) + return mangleType(T->getPointeeType(), Range, QMM_Drop); + QualType PointeeType = T->getPointeeType(); manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); - // Object pointers never have qualifiers. - Out << 'A'; mangleType(PointeeType, Range); } @@ -2427,6 +2439,15 @@ void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, << Range; } +void MicrosoftCXXNameMangler::mangleType(const DependentAddressSpaceType *T, + Qualifiers, SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle this dependent address space type yet"); + Diags.Report(Range.getBegin(), DiagID) << Range; +} + void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers, SourceRange) { // ObjC interfaces have structs underlying them. @@ -2438,7 +2459,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers, SourceRange Range) { // We don't allow overloading by different protocol qualification, // so mangling them isn't necessary. - mangleType(T->getBaseType(), Range); + mangleType(T->getBaseType(), Range, QMM_Drop); } void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, diff --git a/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp b/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp index e7c8c16b01452..8adaef1fb6402 100644 --- a/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp +++ b/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp @@ -441,6 +441,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::Int128: case BuiltinType::LongDouble: case BuiltinType::UInt128: + case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::NullPtr: case BuiltinType::ObjCClass: diff --git a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp index e2e0dbeec0dd3..889f8308a93c6 100644 --- a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp +++ b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp @@ -1,4 +1,4 @@ -//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=// +//===- NestedNameSpecifier.cpp - C++ nested name specifiers ---------------===// // // The LLVM Compiler Infrastructure // @@ -11,16 +11,28 @@ // a C++ nested-name-specifier. // //===----------------------------------------------------------------------===// + #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" -#include "llvm/Support/AlignOf.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> #include <cassert> +#include <cstdlib> +#include <cstring> using namespace clang; @@ -314,8 +326,8 @@ NestedNameSpecifier::print(raw_ostream &OS, SpecType->getTemplateName().print(OS, InnerPolicy, true); // Print the template argument list. - TemplateSpecializationType::PrintTemplateArgumentList( - OS, SpecType->template_arguments(), InnerPolicy); + printTemplateArgumentList(OS, SpecType->template_arguments(), + InnerPolicy); } else { // Print the type normally QualType(T, 0).print(OS, InnerPolicy); @@ -375,22 +387,20 @@ NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { return Length; } -namespace { - /// \brief Load a (possibly unaligned) source location from a given address - /// and offset. - SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { - unsigned Raw; - memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned)); - return SourceLocation::getFromRawEncoding(Raw); - } +/// \brief Load a (possibly unaligned) source location from a given address +/// and offset. +static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { + unsigned Raw; + memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned)); + return SourceLocation::getFromRawEncoding(Raw); +} - /// \brief Load a (possibly unaligned) pointer from a given address and - /// offset. - void *LoadPointer(void *Data, unsigned Offset) { - void *Result; - memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); - return Result; - } +/// \brief Load a (possibly unaligned) pointer from a given address and +/// offset. +static void *LoadPointer(void *Data, unsigned Offset) { + void *Result; + memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); + return Result; } SourceRange NestedNameSpecifierLoc::getSourceRange() const { @@ -446,53 +456,49 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { return TypeLoc(Qualifier->getAsType(), TypeData); } -namespace { - void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, +static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, unsigned &BufferCapacity) { - if (Start == End) - return; + if (Start == End) + return; - if (BufferSize + (End - Start) > BufferCapacity) { - // Reallocate the buffer. - unsigned NewCapacity = std::max( - (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2), - (unsigned)(BufferSize + (End - Start))); - char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); - if (BufferCapacity) { - memcpy(NewBuffer, Buffer, BufferSize); - free(Buffer); - } - Buffer = NewBuffer; - BufferCapacity = NewCapacity; + if (BufferSize + (End - Start) > BufferCapacity) { + // Reallocate the buffer. + unsigned NewCapacity = std::max( + (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2), + (unsigned)(BufferSize + (End - Start))); + char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); + if (BufferCapacity) { + memcpy(NewBuffer, Buffer, BufferSize); + free(Buffer); } - - memcpy(Buffer + BufferSize, Start, End - Start); - BufferSize += End-Start; + Buffer = NewBuffer; + BufferCapacity = NewCapacity; } + + memcpy(Buffer + BufferSize, Start, End - Start); + BufferSize += End-Start; +} - /// \brief Save a source location to the given buffer. - void SaveSourceLocation(SourceLocation Loc, char *&Buffer, - unsigned &BufferSize, unsigned &BufferCapacity) { - unsigned Raw = Loc.getRawEncoding(); - Append(reinterpret_cast<char *>(&Raw), - reinterpret_cast<char *>(&Raw) + sizeof(unsigned), - Buffer, BufferSize, BufferCapacity); - } +/// \brief Save a source location to the given buffer. +static void SaveSourceLocation(SourceLocation Loc, char *&Buffer, + unsigned &BufferSize, unsigned &BufferCapacity) { + unsigned Raw = Loc.getRawEncoding(); + Append(reinterpret_cast<char *>(&Raw), + reinterpret_cast<char *>(&Raw) + sizeof(unsigned), + Buffer, BufferSize, BufferCapacity); +} - /// \brief Save a pointer to the given buffer. - void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, - unsigned &BufferCapacity) { - Append(reinterpret_cast<char *>(&Ptr), - reinterpret_cast<char *>(&Ptr) + sizeof(void *), - Buffer, BufferSize, BufferCapacity); - } +/// \brief Save a pointer to the given buffer. +static void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + Append(reinterpret_cast<char *>(&Ptr), + reinterpret_cast<char *>(&Ptr) + sizeof(void *), + Buffer, BufferSize, BufferCapacity); } NestedNameSpecifierLocBuilder:: NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) - : Representation(Other.Representation), Buffer(nullptr), - BufferSize(0), BufferCapacity(0) -{ + : Representation(Other.Representation) { if (!Other.Buffer) return; diff --git a/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp index 121724a731526..17c95f2a0af77 100644 --- a/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp @@ -158,7 +158,14 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) { } } -void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {} +void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) { + assert(TPL && "Expecting non-null pointer."); + + ID.AddInteger(TPL->size()); + for (auto *ND : TPL->asArray()) { + AddSubDecl(ND); + } +} void ODRHash::clear() { DeclMap.clear(); @@ -199,6 +206,7 @@ unsigned ODRHash::CalculateHash() { return ID.ComputeHash(); } +namespace { // Process a Decl pointer. Add* methods call back into ODRHash while Visit* // methods process the relevant parts of the Decl. class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> { @@ -235,6 +243,10 @@ public: } } + void AddTemplateArgument(TemplateArgument TA) { + Hash.AddTemplateArgument(TA); + } + void Visit(const Decl *D) { ID.AddInteger(D->getKind()); Inherited::Visit(D); @@ -342,7 +354,44 @@ public: AddDecl(D->getFriendDecl()); } } + + void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + // Only care about default arguments as part of the definition. + const bool hasDefaultArgument = + D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); + Hash.AddBoolean(hasDefaultArgument); + if (hasDefaultArgument) { + AddTemplateArgument(D->getDefaultArgument()); + } + + Inherited::VisitTemplateTypeParmDecl(D); + } + + void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { + // Only care about default arguments as part of the definition. + const bool hasDefaultArgument = + D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); + Hash.AddBoolean(hasDefaultArgument); + if (hasDefaultArgument) { + AddStmt(D->getDefaultArgument()); + } + + Inherited::VisitNonTypeTemplateParmDecl(D); + } + + void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { + // Only care about default arguments as part of the definition. + const bool hasDefaultArgument = + D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); + Hash.AddBoolean(hasDefaultArgument); + if (hasDefaultArgument) { + AddTemplateArgument(D->getDefaultArgument().getArgument()); + } + + Inherited::VisitTemplateTemplateParmDecl(D); + } }; +} // namespace // Only allow a small portion of Decl's to be processed. Remove this once // all Decl's can be handled. @@ -401,6 +450,20 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { for (auto SubDecl : Decls) { AddSubDecl(SubDecl); } + + const ClassTemplateDecl *TD = Record->getDescribedClassTemplate(); + AddBoolean(TD); + if (TD) { + AddTemplateParameterList(TD->getTemplateParameters()); + } + + ID.AddInteger(Record->getNumBases()); + auto Bases = Record->bases(); + for (auto Base : Bases) { + AddQualType(Base.getType()); + ID.AddInteger(Base.isVirtual()); + ID.AddInteger(Base.getAccessSpecifierAsWritten()); + } } void ODRHash::AddDecl(const Decl *D) { @@ -420,6 +483,7 @@ void ODRHash::AddDecl(const Decl *D) { } } +namespace { // Process a Type pointer. Add* methods call back into ODRHash while Visit* // methods process the relevant parts of the Type. class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> { @@ -608,6 +672,7 @@ public: AddDecl(T->getDecl()); } }; +} // namespace void ODRHash::AddType(const Type *T) { assert(T && "Expecting non-null pointer."); diff --git a/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp b/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp index 2c4d159a1bc82..4feac0cfd0416 100644 --- a/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp +++ b/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp @@ -1,4 +1,4 @@ -//===--- OpenMPClause.cpp - Classes for OpenMP clauses --------------------===// +//===- OpenMPClause.cpp - Classes for OpenMP clauses ----------------------===// // // The LLVM Compiler Infrastructure // @@ -12,8 +12,14 @@ //===----------------------------------------------------------------------===// #include "clang/AST/OpenMPClause.h" - #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> using namespace clang; @@ -48,6 +54,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast<const OMPReductionClause *>(C); case OMPC_task_reduction: return static_cast<const OMPTaskReductionClause *>(C); + case OMPC_in_reduction: + return static_cast<const OMPInReductionClause *>(C); case OMPC_linear: return static_cast<const OMPLinearClause *>(C); case OMPC_if: @@ -58,6 +66,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast<const OMPNumTeamsClause *>(C); case OMPC_thread_limit: return static_cast<const OMPThreadLimitClause *>(C); + case OMPC_device: + return static_cast<const OMPDeviceClause *>(C); case OMPC_default: case OMPC_proc_bind: case OMPC_final: @@ -81,7 +91,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: - case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: @@ -116,6 +125,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) return static_cast<const OMPReductionClause *>(C); case OMPC_task_reduction: return static_cast<const OMPTaskReductionClause *>(C); + case OMPC_in_reduction: + return static_cast<const OMPInReductionClause *>(C); case OMPC_linear: return static_cast<const OMPLinearClause *>(C); case OMPC_schedule: @@ -562,6 +573,69 @@ OMPTaskReductionClause *OMPTaskReductionClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPTaskReductionClause(N); } +void OMPInReductionClause::setPrivates(ArrayRef<Expr *> Privates) { + assert(Privates.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(Privates.begin(), Privates.end(), varlist_end()); +} + +void OMPInReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) { + assert( + LHSExprs.size() == varlist_size() && + "Number of LHS expressions is not the same as the preallocated buffer"); + std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end()); +} + +void OMPInReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) { + assert( + RHSExprs.size() == varlist_size() && + "Number of RHS expressions is not the same as the preallocated buffer"); + std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); +} + +void OMPInReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) { + assert(ReductionOps.size() == varlist_size() && "Number of in reduction " + "expressions is not the same " + "as the preallocated buffer"); + std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); +} + +void OMPInReductionClause::setTaskgroupDescriptors( + ArrayRef<Expr *> TaskgroupDescriptors) { + assert(TaskgroupDescriptors.size() == varlist_size() && + "Number of in reduction descriptors is not the same as the " + "preallocated buffer"); + std::copy(TaskgroupDescriptors.begin(), TaskgroupDescriptors.end(), + getReductionOps().end()); +} + +OMPInReductionClause *OMPInReductionClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, + ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs, + ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, + ArrayRef<Expr *> TaskgroupDescriptors, Stmt *PreInit, Expr *PostUpdate) { + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * VL.size())); + OMPInReductionClause *Clause = new (Mem) OMPInReductionClause( + StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); + Clause->setVarRefs(VL); + Clause->setPrivates(Privates); + Clause->setLHSExprs(LHSExprs); + Clause->setRHSExprs(RHSExprs); + Clause->setReductionOps(ReductionOps); + Clause->setTaskgroupDescriptors(TaskgroupDescriptors); + Clause->setPreInitStmt(PreInit); + Clause->setPostUpdateExpr(PostUpdate); + return Clause; +} + +OMPInReductionClause *OMPInReductionClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * N)); + return new (Mem) OMPInReductionClause(N); +} + OMPFlushClause *OMPFlushClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -648,7 +722,6 @@ OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc, MappableExprComponentListsRef ComponentLists, OpenMPMapClauseKind TypeModifier, OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) { - unsigned NumVars = Vars.size(); unsigned NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/QualTypeNames.cpp b/contrib/llvm/tools/clang/lib/AST/QualTypeNames.cpp index 721c2c92fc274..86c0eff9f78c3 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Core/QualTypeNames.cpp +++ b/contrib/llvm/tools/clang/lib/AST/QualTypeNames.cpp @@ -9,11 +9,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Tooling/Core/QualTypeNames.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/GlobalDecl.h" #include "clang/AST/Mangle.h" +#include "clang/AST/QualTypeNames.h" #include <stdio.h> #include <memory> @@ -21,17 +21,6 @@ namespace clang { namespace TypeName { -/// \brief Generates a QualType that can be used to name the same type -/// if used at the end of the current translation unit. This ignores -/// issues such as type shadowing. -/// -/// \param[in] QT - the type for which the fully qualified type will be -/// returned. -/// \param[in] Ctx - the ASTContext to be used. -/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace -/// specifier "::" should be prepended or not. -static QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, - bool WithGlobalNsPrefix); /// \brief Create a NestedNameSpecifier for Namesp and its enclosing /// scopes. diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp index 299fd111bf6a6..37fe029f53bd3 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp @@ -1,4 +1,4 @@ -//===-- RecordLayout.cpp - Layout information for a struct/union -*- C++ -*-==// +//===- RecordLayout.cpp - Layout information for a struct/union -----------===// // // The LLVM Compiler Infrastructure // @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" +#include <cassert> using namespace clang; @@ -32,7 +34,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets) : Size(size), DataSize(datasize), Alignment(alignment), - RequiredAlignment(requiredAlignment), CXXInfo(nullptr) { + RequiredAlignment(requiredAlignment) { FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end()); } @@ -73,7 +75,6 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CXXInfo->EndsWithZeroSizedObject = EndsWithZeroSizedObject; CXXInfo->LeadsWithZeroSizedBase = LeadsWithZeroSizedBase; - #ifndef NDEBUG if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { if (isPrimaryBaseVirtual()) { diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp index c0b9cadca4227..a9d43dfa80c54 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp @@ -632,6 +632,9 @@ protected: /// pointer, as opposed to inheriting one from a primary base class. bool HasOwnVFPtr; + /// \brief the flag of field offset changing due to packed attribute. + bool HasPackedField; + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// Bases - base classes and their offsets in the record. @@ -666,7 +669,7 @@ protected: NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), PrimaryBase(nullptr), PrimaryBaseIsVirtual(false), HasOwnVFPtr(false), - FirstNearlyEmptyVBase(nullptr) {} + HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {} void Layout(const RecordDecl *D); void Layout(const CXXRecordDecl *D); @@ -1166,7 +1169,6 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { // Query the external layout to see if it provides an offset. bool HasExternalLayout = false; if (UseExternalLayout) { - llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known; if (Base->IsVirtual) HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset); else @@ -1729,7 +1731,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, const ArrayType* ATy = Context.getAsArrayType(D->getType()); FieldAlign = Context.getTypeAlignInChars(ATy->getElementType()); } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); + unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType()); FieldSize = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS)); FieldAlign = @@ -1847,7 +1849,6 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit; uint64_t UnpackedSizeInBits = llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment)); - CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); uint64_t RoundedSize = llvm::alignTo(getSizeInBits(), Context.toBits(Alignment)); @@ -1882,10 +1883,11 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { << (InBits ? 1 : 0); // (byte|bit) } - // Warn if we packed it unnecessarily. If the alignment is 1 byte don't - // bother since there won't be alignment issues. - if (Packed && UnpackedAlignment > CharUnits::One() && - getSize() == UnpackedSize) + // Warn if we packed it unnecessarily, when the unpacked alignment is not + // greater than the one after packing, the size in bits doesn't change and + // the offset of each field is identical. + if (Packed && UnpackedAlignment <= Alignment && + UnpackedSizeInBits == getSizeInBits() && !HasPackedField) Diag(D->getLocation(), diag::warn_unnecessary_packed) << Context.getTypeDeclType(RD); } @@ -1977,13 +1979,10 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding( << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) - } - - // Warn if we packed it unnecessarily. If the alignment is 1 byte don't - // bother since there won't be alignment issues. - if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset) - Diag(D->getLocation(), diag::warn_unnecessary_packed) - << D->getIdentifier(); + } + if (isPacked && Offset != UnpackedOffset) { + HasPackedField = true; + } } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, @@ -2084,7 +2083,7 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) { // rules, we should implement the restrictions about over-sized // bitfields: // - // http://mentorembedded.github.com/cxx-abi/abi.html#POD : + // http://itanium-cxx-abi.github.io/cxx-abi/abi.html#POD : // In general, a type is considered a POD for the purposes of // layout if it is a POD type (in the sense of ISO C++ // [basic.types]). However, a POD-struct or POD-union (in the @@ -2896,13 +2895,12 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet( Work.insert(MD); while (!Work.empty()) { const CXXMethodDecl *MD = *Work.begin(); - CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(), - e = MD->end_overridden_methods(); + auto MethodRange = MD->overridden_methods(); // If a virtual method has no-overrides it lives in its parent's vtable. - if (i == e) + if (MethodRange.begin() == MethodRange.end()) BasesWithOverriddenMethods.insert(MD->getParent()); else - Work.insert(i, e); + Work.insert(MethodRange.begin(), MethodRange.end()); // We've finished processing this element, remove it from the working set. Work.erase(MD); } diff --git a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp index 2367cadf645c6..8d240c1336abd 100644 --- a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp @@ -1,4 +1,4 @@ -//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// +//===- Stmt.cpp - Statement AST Node Implementation -----------------------===// // // The LLVM Compiler Infrastructure // @@ -13,6 +13,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclGroup.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" @@ -22,10 +24,24 @@ #include "clang/AST/StmtOpenMP.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstring> +#include <string> +#include <utility> + using namespace clang; static struct StmtClassNameTable { @@ -150,6 +166,7 @@ const Stmt *Stmt::stripLabelLikeStatements() const { } namespace { + struct good {}; struct bad {}; @@ -191,7 +208,8 @@ namespace { (void) is_good(implements_getLocStart(&type::getLocStart)) #define ASSERT_IMPLEMENTS_getLocEnd(type) \ (void) is_good(implements_getLocEnd(&type::getLocEnd)) -} + +} // namespace /// Check whether the various Stmt classes implement their member /// functions. @@ -222,6 +240,7 @@ Stmt::child_range Stmt::children() { // // See also Expr.cpp:getExprLoc(). namespace { + /// This implementation is used when a class provides a custom /// implementation of getSourceRange. template <class S, class T> @@ -240,7 +259,8 @@ namespace { return SourceRange(static_cast<const S*>(stmt)->getLocStart(), static_cast<const S*>(stmt)->getLocEnd()); } -} + +} // namespace SourceRange Stmt::getSourceRange() const { switch (getStmtClass()) { @@ -286,7 +306,7 @@ CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts, assert(CompoundStmtBits.NumStmts == Stmts.size() && "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!"); - if (Stmts.size() == 0) { + if (Stmts.empty()) { Body = nullptr; return; } @@ -408,6 +428,7 @@ StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const { Expr *GCCAsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } + void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } @@ -506,7 +527,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, unsigned LastAsmStringToken = 0; unsigned LastAsmStringOffset = 0; - while (1) { + while (true) { // Done with the string? if (CurPtr == StrEnd) { if (!CurStringPiece.empty()) @@ -682,6 +703,7 @@ Expr *MSAsmStmt::getOutputExpr(unsigned i) { Expr *MSAsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } + void MSAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } @@ -696,9 +718,8 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) - : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, - numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { - + : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { unsigned NumExprs = NumOutputs + NumInputs; Names = new (C) IdentifierInfo*[NumExprs]; @@ -721,10 +742,9 @@ MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc, ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, StringRef asmstr, ArrayRef<StringRef> clobbers, SourceLocation endloc) - : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, - numinputs, clobbers.size()), LBraceLoc(lbraceloc), - EndLoc(endloc), NumAsmToks(asmtoks.size()) { - + : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, clobbers.size()), LBraceLoc(lbraceloc), + EndLoc(endloc), NumAsmToks(asmtoks.size()) { initialize(C, asmstr, asmtoks, constraints, exprs, clobbers); } @@ -909,14 +929,9 @@ Expr* ReturnStmt::getRetValue() { return cast_or_null<Expr>(RetExpr); } -SEHTryStmt::SEHTryStmt(bool IsCXXTry, - SourceLocation TryLoc, - Stmt *TryBlock, +SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler) - : Stmt(SEHTryStmtClass), - IsCXXTry(IsCXXTry), - TryLoc(TryLoc) -{ + : Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc) { Children[TRY] = TryBlock; Children[HANDLER] = Handler; } @@ -935,12 +950,8 @@ SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const { return dyn_cast<SEHFinallyStmt>(getHandler()); } -SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, - Expr *FilterExpr, - Stmt *Block) - : Stmt(SEHExceptStmtClass), - Loc(Loc) -{ +SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) + : Stmt(SEHExceptStmtClass), Loc(Loc) { Children[FILTER_EXPR] = FilterExpr; Children[BLOCK] = Block; } @@ -950,12 +961,8 @@ SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc, return new(C) SEHExceptStmt(Loc,FilterExpr,Block); } -SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, - Stmt *Block) - : Stmt(SEHFinallyStmtClass), - Loc(Loc), - Block(Block) -{} +SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, Stmt *Block) + : Stmt(SEHFinallyStmtClass), Loc(Loc), Block(Block) {} SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc, Stmt *Block) { @@ -1037,7 +1044,7 @@ CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind, CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), - CapDeclAndKind(nullptr, CR_Default), TheRecordDecl(nullptr) { + CapDeclAndKind(nullptr, CR_Default) { getStoredStmts()[NumCaptures] = nullptr; } @@ -1090,6 +1097,7 @@ Stmt::child_range CapturedStmt::children() { CapturedDecl *CapturedStmt::getCapturedDecl() { return CapDeclAndKind.getPointer(); } + const CapturedDecl *CapturedStmt::getCapturedDecl() const { return CapDeclAndKind.getPointer(); } @@ -1114,11 +1122,7 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const { for (const auto &I : captures()) { if (!I.capturesVariable() && !I.capturesVariableByCopy()) continue; - - // This does not handle variable redeclarations. This should be - // extended to capture variables with redeclarations, for example - // a thread-private variable in OpenMP. - if (I.getCapturedVar() == Var) + if (I.getCapturedVar()->getCanonicalDecl() == Var->getCanonicalDecl()) return true; } diff --git a/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp b/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp index 861d0908209dc..00056e83af2c0 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp @@ -1,4 +1,4 @@ -//===--- StmtIterator.cpp - Iterators for Statements ------------------------===// +//===- StmtIterator.cpp - Iterators for Statements ------------------------===// // // The LLVM Compiler Infrastructure // @@ -13,6 +13,11 @@ #include "clang/AST/StmtIterator.h" #include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstdint> using namespace clang; @@ -31,7 +36,7 @@ static inline const VariableArrayType *FindVA(const Type* t) { } void StmtIteratorBase::NextVA() { - assert (getVAPtr()); + assert(getVAPtr()); const VariableArrayType *p = getVAPtr(); p = FindVA(p->getElementType().getTypePtr()); @@ -93,22 +98,22 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { } StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) - : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { + : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { NextDecl(false); } StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t) - : DGI(nullptr), RawVAPtr(SizeOfTypeVAMode) { + : DGI(nullptr), RawVAPtr(SizeOfTypeVAMode) { RawVAPtr |= reinterpret_cast<uintptr_t>(t); } Stmt*& StmtIteratorBase::GetDeclExpr() const { if (const VariableArrayType* VAPtr = getVAPtr()) { - assert (VAPtr->SizeExpr); + assert(VAPtr->SizeExpr); return const_cast<Stmt*&>(VAPtr->SizeExpr); } - assert (inDeclGroup()); + assert(inDeclGroup()); VarDecl* VD = cast<VarDecl>(*DGI); return *VD->getInitAddress(); } diff --git a/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp b/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp index 1dcb4fd5196be..87bf5aaaa585d 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp @@ -524,14 +524,15 @@ OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C, OMPTaskgroupDirective *OMPTaskgroupDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *ReductionRef) { unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) + sizeof(OMPClause *) * Clauses.size(), alignof(Stmt *)); - void *Mem = C.Allocate(Size + sizeof(Stmt *)); + void *Mem = C.Allocate(Size + sizeof(Stmt *) + sizeof(Expr *)); OMPTaskgroupDirective *Dir = new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc, Clauses.size()); Dir->setAssociatedStmt(AssociatedStmt); + Dir->setReductionRef(ReductionRef); Dir->setClauses(Clauses); return Dir; } @@ -542,7 +543,7 @@ OMPTaskgroupDirective *OMPTaskgroupDirective::CreateEmpty(const ASTContext &C, unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) + sizeof(OMPClause *) * NumClauses, alignof(Stmt *)); - void *Mem = C.Allocate(Size + sizeof(Stmt *)); + void *Mem = C.Allocate(Size + sizeof(Stmt *) + sizeof(Expr *)); return new (Mem) OMPTaskgroupDirective(NumClauses); } @@ -794,13 +795,14 @@ OMPTargetDataDirective *OMPTargetDataDirective::CreateEmpty(const ASTContext &C, OMPTargetEnterDataDirective *OMPTargetEnterDataDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses) { + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { void *Mem = C.Allocate( llvm::alignTo(sizeof(OMPTargetEnterDataDirective), alignof(OMPClause *)) + - sizeof(OMPClause *) * Clauses.size()); + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); OMPTargetEnterDataDirective *Dir = new (Mem) OMPTargetEnterDataDirective(StartLoc, EndLoc, Clauses.size()); Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); return Dir; } @@ -809,20 +811,20 @@ OMPTargetEnterDataDirective::CreateEmpty(const ASTContext &C, unsigned N, EmptyShell) { void *Mem = C.Allocate( llvm::alignTo(sizeof(OMPTargetEnterDataDirective), alignof(OMPClause *)) + - sizeof(OMPClause *) * N); + sizeof(OMPClause *) * N + sizeof(Stmt *)); return new (Mem) OMPTargetEnterDataDirective(N); } -OMPTargetExitDataDirective * -OMPTargetExitDataDirective::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses) { +OMPTargetExitDataDirective *OMPTargetExitDataDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { void *Mem = C.Allocate( llvm::alignTo(sizeof(OMPTargetExitDataDirective), alignof(OMPClause *)) + - sizeof(OMPClause *) * Clauses.size()); + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); OMPTargetExitDataDirective *Dir = new (Mem) OMPTargetExitDataDirective(StartLoc, EndLoc, Clauses.size()); Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); return Dir; } @@ -831,7 +833,7 @@ OMPTargetExitDataDirective::CreateEmpty(const ASTContext &C, unsigned N, EmptyShell) { void *Mem = C.Allocate( llvm::alignTo(sizeof(OMPTargetExitDataDirective), alignof(OMPClause *)) + - sizeof(OMPClause *) * N); + sizeof(OMPClause *) * N + sizeof(Stmt *)); return new (Mem) OMPTargetExitDataDirective(N); } @@ -1006,16 +1008,17 @@ OMPDistributeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses, return new (Mem) OMPDistributeDirective(CollapsedNum, NumClauses); } -OMPTargetUpdateDirective * -OMPTargetUpdateDirective::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef<OMPClause *> Clauses) { +OMPTargetUpdateDirective *OMPTargetUpdateDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { unsigned Size = llvm::alignTo(sizeof(OMPTargetUpdateDirective), alignof(OMPClause *)); - void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); OMPTargetUpdateDirective *Dir = new (Mem) OMPTargetUpdateDirective(StartLoc, EndLoc, Clauses.size()); Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); return Dir; } @@ -1024,14 +1027,15 @@ OMPTargetUpdateDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses, EmptyShell) { unsigned Size = llvm::alignTo(sizeof(OMPTargetUpdateDirective), alignof(OMPClause *)); - void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); return new (Mem) OMPTargetUpdateDirective(NumClauses); } OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, - const HelperExprs &Exprs) { + const HelperExprs &Exprs, bool HasCancel) { unsigned Size = llvm::alignTo(sizeof(OMPDistributeParallelForDirective), alignof(OMPClause *)); void *Mem = C.Allocate( @@ -1075,6 +1079,7 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create( Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); + Dir->HasCancel = HasCancel; return Dir; } @@ -1475,7 +1480,7 @@ OMPTeamsDistributeParallelForDirective * OMPTeamsDistributeParallelForDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, - const HelperExprs &Exprs) { + const HelperExprs &Exprs, bool HasCancel) { auto Size = llvm::alignTo(sizeof(OMPTeamsDistributeParallelForDirective), alignof(OMPClause *)); void *Mem = C.Allocate( @@ -1519,6 +1524,7 @@ OMPTeamsDistributeParallelForDirective::Create( Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); + Dir->HasCancel = HasCancel; return Dir; } @@ -1618,7 +1624,7 @@ OMPTargetTeamsDistributeParallelForDirective * OMPTargetTeamsDistributeParallelForDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, - const HelperExprs &Exprs) { + const HelperExprs &Exprs, bool HasCancel) { auto Size = llvm::alignTo(sizeof(OMPTargetTeamsDistributeParallelForDirective), alignof(OMPClause *)); @@ -1664,6 +1670,7 @@ OMPTargetTeamsDistributeParallelForDirective::Create( Dir->setCombinedCond(Exprs.DistCombinedFields.Cond); Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB); Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); + Dir->HasCancel = HasCancel; return Dir; } diff --git a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp index 5ebaa32b49c80..d7e668a832809 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp @@ -24,6 +24,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/CharInfo.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Format.h" using namespace clang; @@ -38,12 +39,14 @@ namespace { unsigned IndentLevel; clang::PrinterHelper* Helper; PrintingPolicy Policy; + const ASTContext *Context; public: - StmtPrinter(raw_ostream &os, PrinterHelper* helper, - const PrintingPolicy &Policy, - unsigned Indentation = 0) - : OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy) {} + StmtPrinter(raw_ostream &os, PrinterHelper *helper, + const PrintingPolicy &Policy, unsigned Indentation = 0, + const ASTContext *Context = nullptr) + : OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy), + Context(Context) {} void PrintStmt(Stmt *S) { PrintStmt(S, Policy.Indentation); @@ -72,7 +75,8 @@ namespace { void PrintCallArgs(CallExpr *E); void PrintRawSEHExceptHandler(SEHExceptStmt *S); void PrintRawSEHFinallyStmt(SEHFinallyStmt *S); - void PrintOMPExecutableDirective(OMPExecutableDirective *S); + void PrintOMPExecutableDirective(OMPExecutableDirective *S, + bool ForceNoStmt = false); void PrintExpr(Expr *E) { if (E) @@ -859,6 +863,28 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( } } +void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) { + if (!Node->varlist_empty()) { + OS << "in_reduction("; + NestedNameSpecifier *QualifierLoc = + Node->getQualifierLoc().getNestedNameSpecifier(); + OverloadedOperatorKind OOK = + Node->getNameInfo().getName().getCXXOverloadedOperator(); + if (QualifierLoc == nullptr && OOK != OO_None) { + // Print reduction identifier in C format + OS << getOperatorSpelling(OOK); + } else { + // Use C++ format + if (QualifierLoc != nullptr) + QualifierLoc->print(OS, Policy); + OS << Node->getNameInfo(); + } + OS << ":"; + VisitOMPClauseList(Node, ' '); + OS << ")"; + } +} + void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) { if (!Node->varlist_empty()) { OS << "linear"; @@ -997,7 +1023,8 @@ void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) { // OpenMP directives printing methods //===----------------------------------------------------------------------===// -void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S) { +void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S, + bool ForceNoStmt) { OMPClausePrinter Printer(OS, Policy); ArrayRef<OMPClause *> Clauses = S->clauses(); for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); @@ -1007,7 +1034,7 @@ void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S) { OS << ' '; } OS << "\n"; - if (S->hasAssociatedStmt() && S->getAssociatedStmt()) { + if (S->hasAssociatedStmt() && S->getAssociatedStmt() && !ForceNoStmt) { assert(isa<CapturedStmt>(S->getAssociatedStmt()) && "Expected captured statement!"); Stmt *CS = cast<CapturedStmt>(S->getAssociatedStmt())->getCapturedStmt(); @@ -1136,13 +1163,13 @@ void StmtPrinter::VisitOMPTargetDataDirective(OMPTargetDataDirective *Node) { void StmtPrinter::VisitOMPTargetEnterDataDirective( OMPTargetEnterDataDirective *Node) { Indent() << "#pragma omp target enter data "; - PrintOMPExecutableDirective(Node); + PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPTargetExitDataDirective( OMPTargetExitDataDirective *Node) { Indent() << "#pragma omp target exit data "; - PrintOMPExecutableDirective(Node); + PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPTargetParallelDirective( @@ -1194,7 +1221,7 @@ void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { void StmtPrinter::VisitOMPTargetUpdateDirective( OMPTargetUpdateDirective *Node) { Indent() << "#pragma omp target update "; - PrintOMPExecutableDirective(Node); + PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPDistributeParallelForDirective( @@ -1294,8 +1321,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { OS << "template "; OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); } void StmtPrinter::VisitDependentScopeDeclRefExpr( @@ -1306,8 +1332,7 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr( OS << "template "; OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); } void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { @@ -1317,14 +1342,28 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { OS << "template "; OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); +} + +static bool isImplicitSelf(const Expr *E) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const ImplicitParamDecl *PD = + dyn_cast<ImplicitParamDecl>(DRE->getDecl())) { + if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf && + DRE->getLocStart().isInvalid()) + return true; + } + } + return false; } void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { if (Node->getBase()) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Policy.SuppressImplicitBase || + !isImplicitSelf(Node->getBase()->IgnoreImpCasts())) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } } OS << *Node->getDecl(); } @@ -1419,7 +1458,26 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { } } +/// Prints the given expression using the original source text. Returns true on +/// success, false otherwise. +static bool printExprAsWritten(raw_ostream &OS, Expr *E, + const ASTContext *Context) { + if (!Context) + return false; + bool Invalid = false; + StringRef Source = Lexer::getSourceText( + CharSourceRange::getTokenRange(E->getSourceRange()), + Context->getSourceManager(), Context->getLangOpts(), &Invalid); + if (!Invalid) { + OS << Source; + return true; + } + return false; +} + void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { + if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context)) + return; bool isSigned = Node->getType()->isSignedIntegerType(); OS << Node->getValue().toString(10, isSigned); @@ -1456,6 +1514,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, default: llvm_unreachable("Unexpected type for float literal!"); case BuiltinType::Half: break; // FIXME: suffix? case BuiltinType::Double: break; // no suffix. + case BuiltinType::Float16: OS << "F16"; break; case BuiltinType::Float: OS << 'F'; break; case BuiltinType::LongDouble: OS << 'L'; break; case BuiltinType::Float128: OS << 'Q'; break; @@ -1463,6 +1522,8 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, } void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context)) + return; PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true); } @@ -1623,16 +1684,25 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) { PrintCallArgs(Call); OS << ")"; } + +static bool isImplicitThis(const Expr *E) { + if (const auto *TE = dyn_cast<CXXThisExpr>(E)) + return TE->isImplicit(); + return false; +} + void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { - // FIXME: Suppress printing implicit bases (like "this") - PrintExpr(Node->getBase()); + if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) { + PrintExpr(Node->getBase()); - MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase()); - FieldDecl *ParentDecl = ParentMember - ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr; + MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase()); + FieldDecl *ParentDecl = + ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) + : nullptr; - if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) - OS << (Node->isArrow() ? "->" : "."); + if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) + OS << (Node->isArrow() ? "->" : "."); + } if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl())) if (FD->isAnonymousStructOrUnion()) @@ -1644,8 +1714,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { OS << "template "; OS << Node->getMemberNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); } void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { PrintExpr(Node->getBase()); @@ -1869,7 +1938,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { // AtomicExpr stores its subexpressions in a permuted order. PrintExpr(Node->getPtr()); if (Node->getOp() != AtomicExpr::AO__c11_atomic_load && - Node->getOp() != AtomicExpr::AO__atomic_load_n) { + Node->getOp() != AtomicExpr::AO__atomic_load_n && + Node->getOp() != AtomicExpr::AO__opencl_atomic_load) { OS << ", "; PrintExpr(Node->getVal1()); } @@ -1883,7 +1953,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { OS << ", "; PrintExpr(Node->getWeak()); } - if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) { + if (Node->getOp() != AtomicExpr::AO__c11_atomic_init && + Node->getOp() != AtomicExpr::AO__opencl_atomic_init) { OS << ", "; PrintExpr(Node->getOrder()); } @@ -2036,8 +2107,7 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { if (Args->size() != 1) { OS << "operator\"\"" << Node->getUDSuffix()->getName(); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Args->asArray(), Policy); + printTemplateArgumentList(OS, Args->asArray(), Policy); OS << "()"; return; } @@ -2159,6 +2229,9 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { CEnd = Node->explicit_capture_end(); C != CEnd; ++C) { + if (C->capturesVLAType()) + continue; + if (NeedComma) OS << ", "; NeedComma = true; @@ -2361,8 +2434,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( OS << "template "; OS << Node->getMemberNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); } void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { @@ -2376,8 +2448,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { OS << "template "; OS << Node->getMemberNameInfo(); if (Node->hasExplicitTemplateArgs()) - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Node->template_arguments(), Policy); + printTemplateArgumentList(OS, Node->template_arguments(), Policy); } static const char *getTypeTraitName(TypeTrait TT) { @@ -2672,11 +2743,10 @@ void Stmt::dumpPretty(const ASTContext &Context) const { printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts())); } -void Stmt::printPretty(raw_ostream &OS, - PrinterHelper *Helper, - const PrintingPolicy &Policy, - unsigned Indentation) const { - StmtPrinter P(OS, Helper, Policy, Indentation); +void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, unsigned Indentation, + const ASTContext *Context) const { + StmtPrinter P(OS, Helper, Policy, Indentation, Context); P.Visit(const_cast<Stmt*>(this)); } diff --git a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp index 7ec0d1d5e0176..00ef0da18bbbf 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp @@ -573,6 +573,34 @@ void OMPClauseProfiler::VisitOMPTaskReductionClause( Profiler->VisitStmt(E); } } +void OMPClauseProfiler::VisitOMPInReductionClause( + const OMPInReductionClause *C) { + Profiler->VisitNestedNameSpecifier( + C->getQualifierLoc().getNestedNameSpecifier()); + Profiler->VisitName(C->getNameInfo().getName()); + VisitOMPClauseList(C); + VistOMPClauseWithPostUpdate(C); + for (auto *E : C->privates()) { + if (E) + Profiler->VisitStmt(E); + } + for (auto *E : C->lhs_exprs()) { + if (E) + Profiler->VisitStmt(E); + } + for (auto *E : C->rhs_exprs()) { + if (E) + Profiler->VisitStmt(E); + } + for (auto *E : C->reduction_ops()) { + if (E) + Profiler->VisitStmt(E); + } + for (auto *E : C->taskgroup_descriptors()) { + if (E) + Profiler->VisitStmt(E); + } +} void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C); VistOMPClauseWithPostUpdate(C); @@ -774,6 +802,8 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) { void StmtProfiler::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *S) { VisitOMPExecutableDirective(S); + if (const Expr *E = S->getReductionRef()) + VisitStmt(E); } void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) { @@ -1354,6 +1384,10 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, case OO_GreaterEqual: BinaryOp = BO_GE; return Stmt::BinaryOperatorClass; + + case OO_Spaceship: + // FIXME: Update this once we support <=> expressions. + llvm_unreachable("<=> expressions not supported yet"); case OO_AmpAmp: BinaryOp = BO_LAnd; @@ -1388,7 +1422,7 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, llvm_unreachable("Invalid overloaded operator expression"); } -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER == 1911 // Work around https://developercommunity.visualstudio.com/content/problem/84002/clang-cl-when-built-with-vc-2017-crashes-cause-vc.html // MSVC 2017 update 3 miscompiles this function, and a clang built with it @@ -1429,7 +1463,7 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { ID.AddInteger(S->getOperator()); } -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER == 1911 #pragma optimize("", on) #endif @@ -1560,6 +1594,9 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), CEnd = S->explicit_capture_end(); C != CEnd; ++C) { + if (C->capturesVLAType()) + continue; + ID.AddInteger(C->getCaptureKind()); switch (C->getCaptureKind()) { case LCK_StarThis: @@ -1671,6 +1708,7 @@ void StmtProfiler::VisitCXXUnresolvedConstructExpr( const CXXUnresolvedConstructExpr *S) { VisitExpr(S); VisitType(S->getTypeAsWritten()); + ID.AddInteger(S->isListInitialization()); } void StmtProfiler::VisitCXXDependentScopeMemberExpr( diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp index e4998c37a4ef0..e81c11a778255 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp @@ -1,4 +1,4 @@ -//===--- TemplateBase.cpp - Common template AST class implementation ------===// +//===- TemplateBase.cpp - Common template AST class implementation --------===// // // The LLVM Compiler Infrastructure // @@ -14,17 +14,32 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> using namespace clang; @@ -37,7 +52,7 @@ using namespace clang; /// \param Policy the printing policy for EnumConstantDecl printing. static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, const PrintingPolicy& Policy) { - const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); + const Type *T = TemplArg.getIntegralType().getTypePtr(); const llvm::APSInt &Val = TemplArg.getAsIntegral(); if (const EnumType *ET = T->getAs<EnumType>()) { @@ -415,10 +430,9 @@ void TemplateArgument::print(const PrintingPolicy &Policy, Out << "..."; break; - case Integral: { + case Integral: printIntegral(*this, Out, Policy); break; - } case Expression: getAsExpr()->printPretty(Out, nullptr, Policy); diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp index 47a7d47e7a489..bd04fd8366b3f 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp @@ -1,4 +1,4 @@ -//===--- TemplateName.cpp - C++ Template Name Representation---------------===// +//===- TemplateName.cpp - C++ Template Name Representation ----------------===// // // The LLVM Compiler Infrastructure // @@ -12,15 +12,24 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TemplateName.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> + using namespace clang; -using namespace llvm; TemplateArgument SubstTemplateTemplateParmPackStorage::getArgumentPack() const { @@ -131,6 +140,23 @@ DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast<DependentTemplateName *>(); } +TemplateName TemplateName::getNameToSubstitute() const { + TemplateDecl *Decl = getAsTemplateDecl(); + + // Substituting a dependent template name: preserve it as written. + if (!Decl) + return *this; + + // If we have a template declaration, use the most recent non-friend + // declaration of that template. + Decl = cast<TemplateDecl>(Decl->getMostRecentDecl()); + while (Decl->getFriendObjectKind()) { + Decl = cast<TemplateDecl>(Decl->getPreviousDecl()); + assert(Decl && "all declarations of template are friends"); + } + return TemplateName(Decl); +} + bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { if (isa<TemplateTemplateParmDecl>(Template)) @@ -209,7 +235,7 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, TemplateName N) { std::string NameStr; - raw_string_ostream OS(NameStr); + llvm::raw_string_ostream OS(NameStr); LangOptions LO; LO.CPlusPlus = true; LO.Bool = true; diff --git a/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp index d21781dc38992..38f2a16fa16ff 100644 --- a/contrib/llvm/tools/clang/lib/AST/Type.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Type.cpp @@ -1,4 +1,4 @@ -//===--- Type.cpp - Type representation and manipulation ------------------===// +//===- Type.cpp - Type representation and manipulation --------------------===// // // The LLVM Compiler Infrastructure // @@ -12,20 +12,44 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Type.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/TypeVisitor.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Linkage.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + using namespace clang; bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { @@ -125,12 +149,10 @@ DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) - : ArrayType(DependentSizedArray, et, can, sm, tq, + : ArrayType(DependentSizedArray, et, can, sm, tq, (et->containsUnexpandedParameterPack() || (e && e->containsUnexpandedParameterPack()))), - Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) -{ -} + Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {} void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, @@ -152,13 +174,11 @@ DependentSizedExtVectorType::DependentSizedExtVectorType(const SourceLocation loc) : Type(DependentSizedExtVector, can, /*Dependent=*/true, /*InstantiationDependent=*/true, - ElementType->isVariablyModifiedType(), + ElementType->isVariablyModifiedType(), (ElementType->containsUnexpandedParameterPack() || (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))), Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), - loc(loc) -{ -} + loc(loc) {} void DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, @@ -168,18 +188,37 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, SizeExpr->Profile(ID, Context, true); } +DependentAddressSpaceType::DependentAddressSpaceType( + const ASTContext &Context, QualType PointeeType, QualType can, + Expr *AddrSpaceExpr, SourceLocation loc) + : Type(DependentAddressSpace, can, /*Dependent=*/true, + /*InstantiationDependent=*/true, + PointeeType->isVariablyModifiedType(), + (PointeeType->containsUnexpandedParameterPack() || + (AddrSpaceExpr && + AddrSpaceExpr->containsUnexpandedParameterPack()))), + Context(Context), AddrSpaceExpr(AddrSpaceExpr), PointeeType(PointeeType), + loc(loc) {} + +void DependentAddressSpaceType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + QualType PointeeType, + Expr *AddrSpaceExpr) { + ID.AddPointer(PointeeType.getAsOpaquePtr()); + AddrSpaceExpr->Profile(ID, Context, true); +} + VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) : VectorType(Vector, vecType, nElements, canonType, vecKind) {} VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) - : Type(tc, canonType, vecType->isDependentType(), - vecType->isInstantiationDependentType(), - vecType->isVariablyModifiedType(), - vecType->containsUnexpandedParameterPack()), - ElementType(vecType) -{ + : Type(tc, canonType, vecType->isDependentType(), + vecType->isInstantiationDependentType(), + vecType->isVariablyModifiedType(), + vecType->containsUnexpandedParameterPack()), + ElementType(vecType) { VectorTypeBits.VecKind = vecKind; VectorTypeBits.NumElements = nElements; } @@ -354,11 +393,13 @@ const Type *Type::getUnqualifiedDesugaredType() const { } } } + bool Type::isClassType() const { if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isClass(); return false; } + bool Type::isStructureType() const { if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isStruct(); @@ -381,6 +422,7 @@ bool Type::isStructureOrClassType() const { } return false; } + bool Type::isVoidPointerType() const { if (const PointerType *PT = getAs<PointerType>()) return PT->getPointeeType()->isVoidType(); @@ -534,12 +576,11 @@ bool Type::isObjCInertUnsafeUnretainedType() const { ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef<ObjCProtocolDecl *> protocols) - : Type(ObjCTypeParam, can, can->isDependentType(), - can->isInstantiationDependentType(), - can->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), - OTPDecl(const_cast<ObjCTypeParamDecl*>(D)) -{ + : Type(ObjCTypeParam, can, can->isDependentType(), + can->isInstantiationDependentType(), + can->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + OTPDecl(const_cast<ObjCTypeParamDecl*>(D)) { initialize(protocols); } @@ -547,12 +588,11 @@ ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ArrayRef<QualType> typeArgs, ArrayRef<ObjCProtocolDecl *> protocols, bool isKindOf) - : Type(ObjCObject, Canonical, Base->isDependentType(), - Base->isInstantiationDependentType(), - Base->isVariablyModifiedType(), - Base->containsUnexpandedParameterPack()), - BaseType(Base) -{ + : Type(ObjCObject, Canonical, Base->isDependentType(), + Base->isInstantiationDependentType(), + Base->isVariablyModifiedType(), + Base->containsUnexpandedParameterPack()), + BaseType(Base) { ObjCObjectTypeBits.IsKindOf = isKindOf; ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); @@ -603,13 +643,13 @@ ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { // Terminate when we reach an interface type. if (isa<ObjCInterfaceType>(objcObject)) - return { }; + return {}; return objcObject->getTypeArgs(); } // No type arguments. - return { }; + return {}; } bool ObjCObjectType::isKindOfType() const { @@ -645,7 +685,7 @@ QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( return ctx.getObjCObjectType(ctx.getQualifiedType(baseType, splitBaseType.Quals), getTypeArgsAsWritten(), - /*protocols=*/{ }, + /*protocols=*/{}, /*isKindOf=*/false); } @@ -658,10 +698,10 @@ const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>(); } -namespace { - template<typename F> -QualType simpleTransform(ASTContext &ctx, QualType type, F &&f); +static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f); + +namespace { /// Visitor used by simpleTransform() to perform the transformation. template<typename F> @@ -675,7 +715,8 @@ struct SimpleTransformVisitor } public: - SimpleTransformVisitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { } + SimpleTransformVisitor(ASTContext &ctx, F &&f) + : Ctx(ctx), TheFunc(std::move(f)) {} // None of the clients of this transformation can occur where // there are dependent types, so skip dependent types. @@ -1044,10 +1085,12 @@ public: #undef TRIVIAL_TYPE_CLASS }; +} // namespace + /// Perform a simple type transformation that does not change the /// semantics of the type. template<typename F> -QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { +static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { // Transform the type. If it changed, return the transformed result. QualType transformed = f(type); if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr()) @@ -1067,8 +1110,6 @@ QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { return ctx.getQualifiedType(result, splitType.Quals); } -} // end anonymous namespace - /// Substitute the given type arguments for Objective-C type /// parameters within the given type, recursively. QualType QualType::substObjCTypeArgs( @@ -1233,7 +1274,7 @@ QualType QualType::substObjCTypeArgs( if (typeArgs.empty() && context != ObjCSubstitutionContext::Superclass) { return ctx.getObjCObjectType( - objcObjectType->getBaseType(), { }, + objcObjectType->getBaseType(), {}, protocols, objcObjectType->isKindOfTypeAsWritten()); } @@ -1343,7 +1384,7 @@ Optional<ArrayRef<QualType>> Type::getObjCSubstitutions( objectType = objectPointerType->getObjectType(); } else if (getAs<BlockPointerType>()) { ASTContext &ctx = dc->getParentASTContext(); - objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { }) + objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, {}, {}) ->castAs<ObjCObjectType>(); } else { objectType = getAs<ObjCObjectType>(); @@ -1522,6 +1563,7 @@ const ObjCObjectType *Type::getAsObjCInterfaceType() const { } return nullptr; } + const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) @@ -1559,14 +1601,17 @@ TagDecl *Type::getAsTagDecl() const { } namespace { + class GetContainedDeducedTypeVisitor : public TypeVisitor<GetContainedDeducedTypeVisitor, Type*> { bool Syntactic; + public: GetContainedDeducedTypeVisitor(bool Syntactic = false) : Syntactic(Syntactic) {} using TypeVisitor<GetContainedDeducedTypeVisitor, Type*>::Visit; + Type *Visit(QualType T) { if (T.isNull()) return nullptr; @@ -1579,50 +1624,64 @@ namespace { } // Only these types can contain the desired 'auto' type. + Type *VisitElaboratedType(const ElaboratedType *T) { return Visit(T->getNamedType()); } + Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } + Type *VisitBlockPointerType(const BlockPointerType *T) { return Visit(T->getPointeeType()); } + Type *VisitReferenceType(const ReferenceType *T) { return Visit(T->getPointeeTypeAsWritten()); } + Type *VisitMemberPointerType(const MemberPointerType *T) { return Visit(T->getPointeeType()); } + Type *VisitArrayType(const ArrayType *T) { return Visit(T->getElementType()); } + Type *VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { return Visit(T->getElementType()); } + Type *VisitVectorType(const VectorType *T) { return Visit(T->getElementType()); } + Type *VisitFunctionProtoType(const FunctionProtoType *T) { if (Syntactic && T->hasTrailingReturn()) return const_cast<FunctionProtoType*>(T); return VisitFunctionType(T); } + Type *VisitFunctionType(const FunctionType *T) { return Visit(T->getReturnType()); } + Type *VisitParenType(const ParenType *T) { return Visit(T->getInnerType()); } + Type *VisitAttributedType(const AttributedType *T) { return Visit(T->getModifiedType()); } + Type *VisitAdjustedType(const AdjustedType *T) { return Visit(T->getOriginalType()); } }; -} + +} // namespace DeducedType *Type::getContainedDeducedType() const { return cast_or_null<DeducedType>( @@ -1673,7 +1732,6 @@ bool Type::isIntegralType(const ASTContext &Ctx) const { return false; } - bool Type::isIntegralOrUnscopedEnumerationType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && @@ -1689,8 +1747,6 @@ bool Type::isIntegralOrUnscopedEnumerationType() const { return false; } - - bool Type::isCharType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Char_U || @@ -2015,7 +2071,7 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. if (isNull()) - return 0; + return false; if ((*this)->isIncompleteArrayType()) return Context.getBaseElementType(*this).isCXX98PODType(Context); @@ -2063,7 +2119,7 @@ bool QualType::isTrivialType(const ASTContext &Context) const { // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. if (isNull()) - return 0; + return false; if ((*this)->isArrayType()) return Context.getBaseElementType(*this).isTrivialType(Context); @@ -2563,6 +2619,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "double"; case LongDouble: return "long double"; + case Float16: + return "_Float16"; case Float128: return "__float128"; case WChar_S: @@ -2835,7 +2893,6 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumParams, const ExtProtoInfo &epi, const ASTContext &Context, bool Canonical) { - // We have to be careful not to get ambiguous profile encodings. // Note that valid type pointers are never ambiguous with anything else. // @@ -2897,12 +2954,11 @@ QualType TypedefType::desugar() const { } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) - : Type(TypeOfExpr, can, E->isTypeDependent(), - E->isInstantiationDependent(), - E->getType()->isVariablyModifiedType(), - E->containsUnexpandedParameterPack()), - TOExpr(E) { -} + : Type(TypeOfExpr, can, E->isTypeDependent(), + E->isInstantiationDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + TOExpr(E) {} bool TypeOfExprType::isSugared() const { return !TOExpr->isTypeDependent(); @@ -2924,13 +2980,11 @@ DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) // C++11 [temp.type]p2: "If an expression e involves a template parameter, // decltype(e) denotes a unique dependent type." Hence a decltype type is // type-dependent even if its expression is only instantiation-dependent. - : Type(Decltype, can, E->isInstantiationDependent(), - E->isInstantiationDependent(), - E->getType()->isVariablyModifiedType(), - E->containsUnexpandedParameterPack()), - E(E), - UnderlyingType(underlyingType) { -} + : Type(Decltype, can, E->isInstantiationDependent(), + E->isInstantiationDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + E(E), UnderlyingType(underlyingType) {} bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); } @@ -2942,7 +2996,7 @@ QualType DecltypeType::desugar() const { } DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) - : DecltypeType(E, Context.DependentTy), Context(Context) { } + : DecltypeType(E, Context.DependentTy), Context(Context) {} void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E) { @@ -2953,26 +3007,23 @@ UnaryTransformType::UnaryTransformType(QualType BaseType, QualType UnderlyingType, UTTKind UKind, QualType CanonicalType) - : Type(UnaryTransform, CanonicalType, BaseType->isDependentType(), - BaseType->isInstantiationDependentType(), - BaseType->isVariablyModifiedType(), - BaseType->containsUnexpandedParameterPack()) - , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) -{} + : Type(UnaryTransform, CanonicalType, BaseType->isDependentType(), + BaseType->isInstantiationDependentType(), + BaseType->isVariablyModifiedType(), + BaseType->containsUnexpandedParameterPack()), + BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind) - : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) -{} - + : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) - : Type(TC, can, D->isDependentType(), - /*InstantiationDependent=*/D->isDependentType(), - /*VariablyModified=*/false, - /*ContainsUnexpandedParameterPack=*/false), - decl(const_cast<TagDecl*>(D)) {} + : Type(TC, can, D->isDependentType(), + /*InstantiationDependent=*/D->isDependentType(), + /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), + decl(const_cast<TagDecl*>(D)) {} static TagDecl *getInterestingTagDecl(TagDecl *decl) { for (auto I : decl->redecls()) { @@ -2991,6 +3042,19 @@ bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +bool RecordType::hasConstFields() const { + for (FieldDecl *FD : getDecl()->fields()) { + QualType FieldTy = FD->getType(); + if (FieldTy.isConstQualified()) + return true; + FieldTy = FieldTy.getCanonicalType(); + if (const RecordType *FieldRecTy = FieldTy->getAs<RecordType>()) + if (FieldRecTy->hasConstFields()) + return true; + } + return false; +} + bool AttributedType::isQualifier() const { switch (getAttrKind()) { // These are type qualifiers in the traditional C sense: they annotate @@ -3104,11 +3168,9 @@ SubstTemplateTypeParmPackType:: SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack) - : Type(SubstTemplateTypeParmPack, Canon, true, true, false, true), - Replaced(Param), - Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()) -{ -} + : Type(SubstTemplateTypeParmPack, Canon, true, true, false, true), + Replaced(Param), + Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()) {} TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments)); @@ -3275,11 +3337,13 @@ public: L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType()); } }; -} + +} // namespace static CachedProperties computeCachedProperties(const Type *T); namespace clang { + /// The type-property cache. This is templated so as to be /// instantiated at an internal type to prevent unnecessary symbol /// leakage. @@ -3317,13 +3381,19 @@ public: T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType(); } }; -} + +} // namespace clang // Instantiate the friend template at a private class. In a // reasonable implementation, these symbols will be internal. // It is terrible that this is the best way to accomplish this. -namespace { class Private {}; } -typedef TypePropertyCache<Private> Cache; +namespace { + +class Private {}; + +} // namespace + +using Cache = TypePropertyCache<Private>; static CachedProperties computeCachedProperties(const Type *T) { switch (T->getTypeClass()) { @@ -3428,9 +3498,7 @@ bool Type::hasUnnamedOrLocalType() const { return TypeBits.hasLocalOrUnnamedType(); } -static LinkageInfo computeLinkageInfo(QualType T); - -static LinkageInfo computeLinkageInfo(const Type *T) { +LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { switch (T->getTypeClass()) { #define TYPE(Class,Base) #define NON_CANONICAL_TYPE(Class,Base) case Type::Class: @@ -3454,75 +3522,78 @@ static LinkageInfo computeLinkageInfo(const Type *T) { case Type::Record: case Type::Enum: - return cast<TagType>(T)->getDecl()->getLinkageAndVisibility(); + return getDeclLinkageAndVisibility(cast<TagType>(T)->getDecl()); case Type::Complex: - return computeLinkageInfo(cast<ComplexType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType()); case Type::Pointer: - return computeLinkageInfo(cast<PointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<PointerType>(T)->getPointeeType()); case Type::BlockPointer: - return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType()); case Type::LValueReference: case Type::RValueReference: - return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); + return computeTypeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { const MemberPointerType *MPT = cast<MemberPointerType>(T); - LinkageInfo LV = computeLinkageInfo(MPT->getClass()); - LV.merge(computeLinkageInfo(MPT->getPointeeType())); + LinkageInfo LV = computeTypeLinkageInfo(MPT->getClass()); + LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; } case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: - return computeLinkageInfo(cast<ArrayType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<ArrayType>(T)->getElementType()); case Type::Vector: case Type::ExtVector: - return computeLinkageInfo(cast<VectorType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<VectorType>(T)->getElementType()); case Type::FunctionNoProto: - return computeLinkageInfo(cast<FunctionType>(T)->getReturnType()); + return computeTypeLinkageInfo(cast<FunctionType>(T)->getReturnType()); case Type::FunctionProto: { const FunctionProtoType *FPT = cast<FunctionProtoType>(T); - LinkageInfo LV = computeLinkageInfo(FPT->getReturnType()); + LinkageInfo LV = computeTypeLinkageInfo(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) - LV.merge(computeLinkageInfo(ai)); + LV.merge(computeTypeLinkageInfo(ai)); return LV; } case Type::ObjCInterface: - return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility(); + return getDeclLinkageAndVisibility(cast<ObjCInterfaceType>(T)->getDecl()); case Type::ObjCObject: - return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType()); + return computeTypeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType()); case Type::ObjCObjectPointer: - return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType()); + return computeTypeLinkageInfo( + cast<ObjCObjectPointerType>(T)->getPointeeType()); case Type::Atomic: - return computeLinkageInfo(cast<AtomicType>(T)->getValueType()); + return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType()); case Type::Pipe: - return computeLinkageInfo(cast<PipeType>(T)->getElementType()); + return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType()); } llvm_unreachable("unhandled type class"); } -static LinkageInfo computeLinkageInfo(QualType T) { - return computeLinkageInfo(T.getTypePtr()); -} - bool Type::isLinkageValid() const { if (!TypeBits.isCacheValid()) return true; - return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() == - TypeBits.getLinkage(); + Linkage L = LinkageComputer{} + .computeTypeLinkageInfo(getCanonicalTypeInternal()) + .getLinkage(); + return L == TypeBits.getLinkage(); } -LinkageInfo Type::getLinkageAndVisibility() const { - if (!isCanonicalUnqualified()) - return computeLinkageInfo(getCanonicalTypeInternal()); +LinkageInfo LinkageComputer::getTypeLinkageAndVisibility(const Type *T) { + if (!T->isCanonicalUnqualified()) + return computeTypeLinkageInfo(T->getCanonicalTypeInternal()); - LinkageInfo LV = computeLinkageInfo(this); - assert(LV.getLinkage() == getLinkage()); + LinkageInfo LV = computeTypeLinkageInfo(T); + assert(LV.getLinkage() == T->getLinkage()); return LV; } +LinkageInfo Type::getLinkageAndVisibility() const { + return LinkageComputer{}.getTypeLinkageAndVisibility(this); +} + Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const { QualType type(this, 0); do { @@ -3634,6 +3705,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: + case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: case Type::Record: @@ -3748,11 +3820,13 @@ bool Type::isObjCIndependentClassType() const { return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>(); return false; } + bool Type::isObjCRetainableType() const { return isObjCObjectPointerType() || isBlockPointerType() || isObjCNSObjectType(); } + bool Type::isObjCIndirectLifetimeType() const { if (isObjCLifetimeType()) return true; diff --git a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp index c9a268655723b..b05c5fc680962 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp @@ -1,4 +1,4 @@ -//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- C++ -*-===// +//===- TypeLoc.cpp - Type Source Info Wrapper -----------------------------===// // // The LLVM Compiler Infrastructure // @@ -14,8 +14,19 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/TypeLocVisitor.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + using namespace clang; static const unsigned TypeLocMaxDataAlign = alignof(void *); @@ -25,16 +36,18 @@ static const unsigned TypeLocMaxDataAlign = alignof(void *); //===----------------------------------------------------------------------===// namespace { - class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { - public: + +class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { +public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getLocalSourceRange(); \ - } + SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalSourceRange(); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; + +} // namespace SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { if (TL.isNull()) return SourceRange(); @@ -42,16 +55,18 @@ SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { } namespace { - class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> { - public: + +class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> { +public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getLocalDataAlignment(); \ - } + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalDataAlignment(); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; + +} // namespace /// \brief Returns the alignment of the type source info data block. unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) { @@ -60,16 +75,18 @@ unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) { } namespace { - class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { - public: + +class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { +public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getLocalDataSize(); \ - } + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalDataSize(); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; + +} // namespace /// \brief Returns the size of the type source info data block. unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { @@ -88,16 +105,18 @@ unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { } namespace { - class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { - public: + +class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { +public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getNextTypeLoc(); \ - } + TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getNextTypeLoc(); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; + +} // namespace /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". @@ -127,20 +146,22 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, } namespace { - class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> { - TypeLoc Source; - public: - TypeLocCopier(TypeLoc source) : Source(source) { } + +class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> { + TypeLoc Source; + +public: + TypeLocCopier(TypeLoc source) : Source(source) {} #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \ - dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \ - } + void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \ + dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; +} // namespace void TypeLoc::copy(TypeLoc other) { assert(getFullDataSize() == other.getFullDataSize()); @@ -243,22 +264,22 @@ SourceLocation TypeLoc::getEndLoc() const { } } - namespace { - struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { - // Overload resolution does the real work for us. - static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } - static bool isTypeSpec(TypeLoc _) { return false; } + +struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return isTypeSpec(TyLoc); \ - } + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } #include "clang/AST/TypeLocNodes.def" - }; -} +}; +} // namespace /// \brief Determines if the given type loc corresponds to a /// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in @@ -319,6 +340,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: + case BuiltinType::Float16: case BuiltinType::Float128: llvm_unreachable("Builtin type needs extra local data!"); // Fall through, if the impossible happens. @@ -363,7 +385,7 @@ SourceLocation TypeLoc::findNullabilityLoc() const { return attributedLoc.getAttrNameLoc(); } - return SourceLocation(); + return {}; } TypeLoc TypeLoc::findExplicitQualifierLoc() const { @@ -384,7 +406,7 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const { return atomic; } - return TypeLoc(); + return {}; } void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context, @@ -422,6 +444,15 @@ void TypeOfTypeLoc::initializeLocal(ASTContext &Context, getUnderlyingType(), Loc); } +void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKWLoc(Loc); + setRParenLoc(Loc); + setLParenLoc(Loc); + this->setUnderlyingTInfo( + Context.getTrivialTypeSourceInfo(getTypePtr()->getBaseType(), Loc)); +} + void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setElaboratedKeywordLoc(Loc); diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp index 15c63bf4ed988..35e0b75f3c22e 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp @@ -222,6 +222,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: + case Type::DependentAddressSpace: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -527,6 +528,19 @@ void TypePrinter::printDependentSizedArrayAfter( printAfter(T->getElementType(), OS); } +void TypePrinter::printDependentAddressSpaceBefore( + const DependentAddressSpaceType *T, raw_ostream &OS) { + printBefore(T->getPointeeType(), OS); +} +void TypePrinter::printDependentAddressSpaceAfter( + const DependentAddressSpaceType *T, raw_ostream &OS) { + OS << " __attribute__((address_space("; + if (T->getAddrSpaceExpr()) + T->getAddrSpaceExpr()->printPretty(OS, nullptr, Policy); + OS << ")))"; + printAfter(T->getPointeeType(), OS); +} + void TypePrinter::printDependentSizedExtVectorBefore( const DependentSizedExtVectorType *T, raw_ostream &OS) { @@ -665,6 +679,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, auto EPI = T->getExtParameterInfo(i); if (EPI.isConsumed()) OS << "__attribute__((ns_consumed)) "; + if (EPI.isNoEscape()) + OS << "__attribute__((noescape)) "; auto ABI = EPI.getABI(); if (ABI != ParameterABI::Ordinary) OS << "__attribute__((" << getParameterABISpelling(ABI) << ")) "; @@ -966,8 +982,7 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); OS << Spec->getIdentifier()->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, TemplateArgs.asArray(), Policy); + printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy); OS << "::"; } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl()) @@ -1054,7 +1069,7 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { Args = TemplateArgs.asArray(); } IncludeStrongLifetimeRAII Strong(Policy); - TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, Policy); + printTemplateArgumentList(OS, Args, Policy); } spaceBeforePlaceHolder(OS); @@ -1113,8 +1128,7 @@ void TypePrinter::printTemplateSpecializationBefore( IncludeStrongLifetimeRAII Strong(Policy); T->getTemplateName().print(OS, Policy); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, T->template_arguments(), Policy); + printTemplateArgumentList(OS, T->template_arguments(), Policy); spaceBeforePlaceHolder(OS); } void TypePrinter::printTemplateSpecializationAfter( @@ -1182,19 +1196,18 @@ void TypePrinter::printDependentNameAfter(const DependentNameType *T, void TypePrinter::printDependentTemplateSpecializationBefore( const DependentTemplateSpecializationType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); if (T->getKeyword() != ETK_None) OS << " "; - + if (T->getQualifier()) - T->getQualifier()->print(OS, Policy); + T->getQualifier()->print(OS, Policy); OS << T->getIdentifier()->getName(); - TemplateSpecializationType::PrintTemplateArgumentList(OS, - T->template_arguments(), - Policy); + printTemplateArgumentList(OS, T->template_arguments(), Policy); spaceBeforePlaceHolder(OS); } + void TypePrinter::printDependentTemplateSpecializationAfter( const DependentTemplateSpecializationType *T, raw_ostream &OS) { } @@ -1304,7 +1317,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, default: llvm_unreachable("This attribute should have been handled already"); case AttributedType::attr_address_space: OS << "address_space("; - OS << T->getEquivalentType().getAddressSpace(); + // FIXME: printing the raw LangAS value is wrong. This should probably + // use the same code as Qualifiers::print() + OS << (unsigned)T->getEquivalentType().getAddressSpace(); OS << ')'; break; @@ -1503,41 +1518,39 @@ void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, OS << '*'; } } + void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, raw_ostream &OS) { } -void TemplateSpecializationType:: - PrintTemplateArgumentList(raw_ostream &OS, - const TemplateArgumentListInfo &Args, - const PrintingPolicy &Policy) { - return PrintTemplateArgumentList(OS, - Args.arguments(), - Policy); +static +const TemplateArgument &getArgument(const TemplateArgument &A) { return A; } + +static const TemplateArgument &getArgument(const TemplateArgumentLoc &A) { + return A.getArgument(); } -void TemplateSpecializationType::PrintTemplateArgumentList( - raw_ostream &OS, ArrayRef<TemplateArgument> Args, - const PrintingPolicy &Policy, bool SkipBrackets) { +template<typename TA> +static void printTo(raw_ostream &OS, ArrayRef<TA> Args, + const PrintingPolicy &Policy, bool SkipBrackets) { const char *Comma = Policy.MSVCFormatting ? "," : ", "; if (!SkipBrackets) OS << '<'; - bool needSpace = false; + bool NeedSpace = false; bool FirstArg = true; - for (const TemplateArgument &Arg : Args) { + for (const auto &Arg : Args) { // Print the argument into a string. SmallString<128> Buf; llvm::raw_svector_ostream ArgOS(Buf); - if (Arg.getKind() == TemplateArgument::Pack) { - if (Arg.pack_size() && !FirstArg) + const TemplateArgument &Argument = getArgument(Arg); + if (Argument.getKind() == TemplateArgument::Pack) { + if (Argument.pack_size() && !FirstArg) OS << Comma; - PrintTemplateArgumentList(ArgOS, - Arg.getPackAsArray(), - Policy, true); + printTo(ArgOS, Argument.getPackAsArray(), Policy, true); } else { if (!FirstArg) OS << Comma; - Arg.print(Policy, ArgOS); + Argument.print(Policy, ArgOS); } StringRef ArgString = ArgOS.str(); @@ -1549,65 +1562,36 @@ void TemplateSpecializationType::PrintTemplateArgumentList( OS << ArgString; - needSpace = (!ArgString.empty() && ArgString.back() == '>'); + NeedSpace = (!ArgString.empty() && ArgString.back() == '>'); FirstArg = false; } // If the last character of our string is '>', add another space to // keep the two '>''s separate tokens. We don't *have* to do this in // C++0x, but it's still good hygiene. - if (needSpace) + if (NeedSpace) OS << ' '; if (!SkipBrackets) OS << '>'; } -// Sadly, repeat all that with TemplateArgLoc. -void TemplateSpecializationType:: -PrintTemplateArgumentList(raw_ostream &OS, - ArrayRef<TemplateArgumentLoc> Args, - const PrintingPolicy &Policy) { - OS << '<'; - const char *Comma = Policy.MSVCFormatting ? "," : ", "; - - bool needSpace = false; - bool FirstArg = true; - for (const TemplateArgumentLoc &Arg : Args) { - if (!FirstArg) - OS << Comma; - - // Print the argument into a string. - SmallString<128> Buf; - llvm::raw_svector_ostream ArgOS(Buf); - if (Arg.getArgument().getKind() == TemplateArgument::Pack) { - PrintTemplateArgumentList(ArgOS, - Arg.getArgument().getPackAsArray(), - Policy, true); - } else { - Arg.getArgument().print(Policy, ArgOS); - } - StringRef ArgString = ArgOS.str(); - - // If this is the first argument and its string representation - // begins with the global scope specifier ('::foo'), add a space - // to avoid printing the diagraph '<:'. - if (FirstArg && !ArgString.empty() && ArgString[0] == ':') - OS << ' '; - - OS << ArgString; - - needSpace = (!ArgString.empty() && ArgString.back() == '>'); - FirstArg = false; - } +void clang::printTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy) { + return printTo(OS, Args.arguments(), Policy, false); +} - // If the last character of our string is '>', add another space to - // keep the two '>''s separate tokens. We don't *have* to do this in - // C++0x, but it's still good hygiene. - if (needSpace) - OS << ' '; +void clang::printTemplateArgumentList(raw_ostream &OS, + ArrayRef<TemplateArgument> Args, + const PrintingPolicy &Policy) { + printTo(OS, Args, Policy, false); +} - OS << '>'; +void clang::printTemplateArgumentList(raw_ostream &OS, + ArrayRef<TemplateArgumentLoc> Args, + const PrintingPolicy &Policy) { + printTo(OS, Args, Policy, false); } std::string Qualifiers::getAsString() const { @@ -1629,7 +1613,7 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (getCVRQualifiers()) return false; - if (getAddressSpace()) + if (getAddressSpace() != LangAS::Default) return false; if (getObjCGCAttr()) @@ -1660,17 +1644,21 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, OS << "__unaligned"; addSpace = true; } - if (unsigned addrspace = getAddressSpace()) { - if (addSpace) - OS << ' '; - addSpace = true; - switch (addrspace) { + LangAS addrspace = getAddressSpace(); + if (addrspace != LangAS::Default) { + if (addrspace != LangAS::opencl_private) { + if (addSpace) + OS << ' '; + addSpace = true; + switch (addrspace) { case LangAS::opencl_global: OS << "__global"; break; case LangAS::opencl_local: OS << "__local"; break; + case LangAS::opencl_private: + break; case LangAS::opencl_constant: case LangAS::cuda_constant: OS << "__constant"; @@ -1685,10 +1673,10 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, OS << "__shared"; break; default: - assert(addrspace >= LangAS::FirstTargetAddressSpace); OS << "__attribute__((address_space("; - OS << addrspace - LangAS::FirstTargetAddressSpace; + OS << toTargetAddressSpace(addrspace); OS << ")))"; + } } } if (Qualifiers::GC gc = getObjCGCAttr()) { diff --git a/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp index 53461ebbb8120..b946f10105f42 100644 --- a/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp @@ -1,4 +1,4 @@ -//===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===// +//===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===// // // The LLVM Compiler Infrastructure // @@ -14,12 +14,16 @@ #include "clang/AST/VTTBuilder.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/CXXInheritance.h" +#include "clang/AST/BaseSubobject.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/RecordLayout.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/Support/Format.h" -#include <algorithm> -#include <cstdio> +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstdint> using namespace clang; @@ -28,9 +32,9 @@ using namespace clang; VTTBuilder::VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, bool GenerateDefinition) - : Ctx(Ctx), MostDerivedClass(MostDerivedClass), - MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)), - GenerateDefinition(GenerateDefinition) { + : Ctx(Ctx), MostDerivedClass(MostDerivedClass), + MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)), + GenerateDefinition(GenerateDefinition) { // Lay out this VTT. LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), /*BaseIsVirtual=*/false); @@ -56,7 +60,7 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { const CXXRecordDecl *RD = Base.getBase(); - for (const auto &I : RD->bases()) { + for (const auto &I : RD->bases()) { // Don't layout virtual bases. if (I.isVirtual()) continue; diff --git a/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp index e60ae33f2e5c0..347c516ef6a5e 100644 --- a/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp @@ -1079,9 +1079,7 @@ static void visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { assert(MD->isVirtual() && "Method is not virtual!"); - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; + for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { if (!Visitor(OverriddenMD)) continue; visitAllOverriddenMethods(OverriddenMD, Visitor); @@ -1329,11 +1327,8 @@ static bool OverridesIndirectMethodInBases( ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) { if (Bases.count(MD->getParent())) return true; - - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - + + for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { // Check "indirect overriders". if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) return true; @@ -2963,6 +2958,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, CalculateVtordispAdjustment(FinalOverrider, ThisOffset, ThisAdjustmentOffset); + unsigned VBIndex = + LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; + if (OverriddenMD) { // If MD overrides anything in this vftable, we need to update the // entries. @@ -2975,6 +2973,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; + VBIndex = OverriddenMethodInfo.VBTableIndex; + // Let's check if the overrider requires any return adjustments. // We must create a new slot if the MD's return type is not trivially // convertible to the OverriddenMD's one. @@ -2987,8 +2987,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, if (!ReturnAdjustingThunk) { // No return adjustment needed - just replace the overridden method info // with the current info. - MethodInfo MI(OverriddenMethodInfo.VBTableIndex, - OverriddenMethodInfo.VFTableIndex); + MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex); MethodInfoMap.erase(OverriddenMDIterator); assert(!MethodInfoMap.count(MD) && @@ -3015,8 +3014,6 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // If we got here, MD is a method not seen in any of the sub-bases or // it requires return adjustment. Insert the method info for this method. - unsigned VBIndex = - LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; MethodInfo MI(VBIndex, HasRTTIComponent ? Components.size() - 1 : Components.size(), ReturnAdjustingThunk); diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 49b15ee68500a..02aee4b46ddd1 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -734,7 +734,10 @@ private: BoundNodesTreeBuilder *Builder) { const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); - for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) { + auto Aliases = TypeAliases.find(CanonicalType); + if (Aliases == TypeAliases.end()) + return false; + for (const TypedefNameDecl *Alias : Aliases->second) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(*Alias, this, &Result)) { *Builder = std::move(Result); diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index f0bfbf9e32d87..0bcdd8e328048 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -1,4 +1,4 @@ -//===--- ASTMatchersInternal.cpp - Structural query framework -------------===// +//===- ASTMatchersInternal.cpp - Structural query framework ---------------===// // // The LLVM Compiler Infrastructure // @@ -11,11 +11,30 @@ // //===----------------------------------------------------------------------===// -#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { @@ -40,7 +59,6 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); - void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); @@ -51,7 +69,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { namespace { -typedef bool (*VariadicOperatorFunction)( +using VariadicOperatorFunction = bool (*)( const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); @@ -100,20 +118,22 @@ public: TrueMatcherImpl() { Retain(); // Reference count will never become zero. } + bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *, BoundNodesTreeBuilder *) const override { return true; } }; -static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance; -} // namespace +} // namespace + +static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance; DynTypedMatcher DynTypedMatcher::constructVariadic( DynTypedMatcher::VariadicOperator Op, ast_type_traits::ASTNodeKind SupportedKind, std::vector<DynTypedMatcher> InnerMatchers) { - assert(InnerMatchers.size() > 0 && "Array must not be empty."); + assert(!InnerMatchers.empty() && "Array must not be empty."); assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(), [SupportedKind](const DynTypedMatcher &M) { return M.canConvertTo(SupportedKind); @@ -314,9 +334,7 @@ HasNameMatcher::HasNameMatcher(std::vector<std::string> N) #endif } -namespace { - -bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) { +static bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) { StringRef Name = FullName; if (!Name.endswith(Suffix)) return false; @@ -330,7 +348,8 @@ bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) { return true; } -StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) { +static StringRef getNodeName(const NamedDecl &Node, + llvm::SmallString<128> &Scratch) { // Simple name. if (Node.getIdentifier()) return Node.getName(); @@ -346,7 +365,8 @@ StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) { return "(anonymous)"; } -StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) { +static StringRef getNodeName(const RecordDecl &Node, + llvm::SmallString<128> &Scratch) { if (Node.getIdentifier()) { return Node.getName(); } @@ -354,11 +374,12 @@ StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) { return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch); } -StringRef getNodeName(const NamespaceDecl &Node, - llvm::SmallString<128> &Scratch) { +static StringRef getNodeName(const NamespaceDecl &Node, + llvm::SmallString<128> &Scratch) { return Node.isAnonymousNamespace() ? "(anonymous namespace)" : Node.getName(); } +namespace { class PatternSet { public: @@ -397,10 +418,11 @@ private: StringRef P; bool IsFullyQualified; }; + llvm::SmallVector<Pattern, 8> Patterns; }; -} // namespace +} // namespace bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const { assert(UseUnqualifiedMatch); @@ -504,5 +526,282 @@ bool HasNameMatcher::matchesNode(const NamedDecl &Node) const { } } // end namespace internal + +const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl> + translationUnitDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl> + typedefNameDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl> + typeAliasTemplateDecl; +const internal::VariadicAllOfMatcher<Decl> decl; +const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> + linkageSpecDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceDecl> namespaceDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, NamespaceAliasDecl> + namespaceAliasDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, RecordDecl> recordDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, CXXRecordDecl> cxxRecordDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ClassTemplateDecl> + classTemplateDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, + ClassTemplateSpecializationDecl> + classTemplateSpecializationDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> + declaratorDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl> + accessSpecDecl; +const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; +const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; +const internal::VariadicAllOfMatcher<TemplateName> templateName; +const internal::VariadicDynCastAllOfMatcher<Decl, NonTypeTemplateParmDecl> + nonTypeTemplateParmDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTypeParmDecl> + templateTypeParmDecl; +const internal::VariadicAllOfMatcher<QualType> qualType; +const internal::VariadicAllOfMatcher<Type> type; +const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; +const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr> + unaryExprOrTypeTraitExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl> + cxxConstructorDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl> + cxxDestructorDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, EnumConstantDecl> + enumConstantDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> + cxxConversionDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> functionDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, FunctionTemplateDecl> + functionTemplateDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl; +const internal::VariadicAllOfMatcher<Stmt> stmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, DeclStmt> declStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr> + cxxMemberCallExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCMessageExpr> + objcMessageExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCInterfaceDecl> + objcInterfaceDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCImplementationDecl> + objcImplementationDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCProtocolDecl> + objcProtocolDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryDecl> + objcCategoryDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCCategoryImplDecl> + objcCategoryImplDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCMethodDecl> + objcMethodDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCIvarDecl> objcIvarDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, ObjCPropertyDecl> + objcPropertyDecl; +const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtThrowStmt> + objcThrowStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtTryStmt> objcTryStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtCatchStmt> + objcCatchStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtFinallyStmt> + objcFinallyStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ExprWithCleanups> + exprWithCleanups; +const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXStdInitializerListExpr> + cxxStdInitializerListExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr> + implicitValueInitExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> parenListExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, SubstNonTypeTemplateParmExpr> + substNonTypeTemplateParmExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, UsingDirectiveDecl> + usingDirectiveDecl; +const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedLookupExpr> + unresolvedLookupExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, UnresolvedUsingValueDecl> + unresolvedUsingValueDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, UnresolvedUsingTypenameDecl> + unresolvedUsingTypenameDecl; +const internal::VariadicDynCastAllOfMatcher<Stmt, ParenExpr> parenExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstructExpr> + cxxConstructExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXUnresolvedConstructExpr> + cxxUnresolvedConstructExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> cxxThisExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBindTemporaryExpr> + cxxBindTemporaryExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, MaterializeTemporaryExpr> + materializeTemporaryExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> cxxNewExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> cxxDeleteExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ArraySubscriptExpr> + arraySubscriptExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr> + cxxDefaultArgExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr> + cxxOperatorCallExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; +const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXForRangeStmt> + cxxForRangeStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> continueStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr> addrLabelExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase; +const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> compoundStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> cxxCatchStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBoolLiteralExpr> + cxxBoolLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral> stringLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, CharacterLiteral> + characterLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, IntegerLiteral> + integerLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, FloatingLiteral> floatLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, UserDefinedLiteral> + userDefinedLiteral; +const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr> + compoundLiteralExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr> + cxxNullPtrLiteralExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> gnuNullExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryOperator> + binaryOperator; +const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryOperator> unaryOperator; +const internal::VariadicDynCastAllOfMatcher<Stmt, ConditionalOperator> + conditionalOperator; +const internal::VariadicDynCastAllOfMatcher<Stmt, BinaryConditionalOperator> + binaryConditionalOperator; +const internal::VariadicDynCastAllOfMatcher<Stmt, OpaqueValueExpr> + opaqueValueExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, StaticAssertDecl> + staticAssertDecl; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXReinterpretCastExpr> + cxxReinterpretCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXStaticCastExpr> + cxxStaticCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDynamicCastExpr> + cxxDynamicCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr> + cxxConstCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr> + cStyleCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr> + explicitCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitCastExpr> + implicitCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFunctionalCastExpr> + cxxFunctionalCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTemporaryObjectExpr> + cxxTemporaryObjectExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, PredefinedExpr> + predefinedExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, DesignatedInitExpr> + designatedInitExpr; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + eachOf = {internal::DynTypedMatcher::VO_EachOf}; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + anyOf = {internal::DynTypedMatcher::VO_AnyOf}; +const internal::VariadicOperatorMatcherFunc< + 2, std::numeric_limits<unsigned>::max()> + allOf = {internal::DynTypedMatcher::VO_AllOf}; +const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, + internal::hasAnyNameFunc> + hasAnyName = {}; +const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher> has = {}; +const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher> + hasDescendant = {}; +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher> forEach = + {}; +const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher> + forEachDescendant = {}; +const internal::ArgumentAdaptingMatcherFunc< + internal::HasParentMatcher, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> + hasParent = {}; +const internal::ArgumentAdaptingMatcherFunc< + internal::HasAncestorMatcher, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> + hasAncestor = {}; +const internal::VariadicOperatorMatcherFunc<1, 1> unless = { + internal::DynTypedMatcher::VO_UnaryNot}; +const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; +const internal::VariadicAllOfMatcher<NestedNameSpecifierLoc> + nestedNameSpecifierLoc; +const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr> + cudaKernelCallExpr; +const AstTypeMatcher<BuiltinType> builtinType; +const AstTypeMatcher<ArrayType> arrayType; +const AstTypeMatcher<ComplexType> complexType; +const AstTypeMatcher<ConstantArrayType> constantArrayType; +const AstTypeMatcher<DependentSizedArrayType> dependentSizedArrayType; +const AstTypeMatcher<IncompleteArrayType> incompleteArrayType; +const AstTypeMatcher<VariableArrayType> variableArrayType; +const AstTypeMatcher<AtomicType> atomicType; +const AstTypeMatcher<AutoType> autoType; +const AstTypeMatcher<FunctionType> functionType; +const AstTypeMatcher<FunctionProtoType> functionProtoType; +const AstTypeMatcher<ParenType> parenType; +const AstTypeMatcher<BlockPointerType> blockPointerType; +const AstTypeMatcher<MemberPointerType> memberPointerType; +const AstTypeMatcher<PointerType> pointerType; +const AstTypeMatcher<ObjCObjectPointerType> objcObjectPointerType; +const AstTypeMatcher<ReferenceType> referenceType; +const AstTypeMatcher<LValueReferenceType> lValueReferenceType; +const AstTypeMatcher<RValueReferenceType> rValueReferenceType; +const AstTypeMatcher<TypedefType> typedefType; +const AstTypeMatcher<EnumType> enumType; +const AstTypeMatcher<TemplateSpecializationType> templateSpecializationType; +const AstTypeMatcher<UnaryTransformType> unaryTransformType; +const AstTypeMatcher<RecordType> recordType; +const AstTypeMatcher<TagType> tagType; +const AstTypeMatcher<ElaboratedType> elaboratedType; +const AstTypeMatcher<SubstTemplateTypeParmType> substTemplateTypeParmType; +const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType; +const AstTypeMatcher<InjectedClassNameType> injectedClassNameType; +const AstTypeMatcher<DecayedType> decayedType; +AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasElementType, + AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType, + ComplexType)); +AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType, + AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType)); +AST_TYPELOC_TRAVERSE_MATCHER_DEF( + pointee, + AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType, + PointerType, ReferenceType)); + } // end namespace ast_matchers } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h index c557ff162691a..af90e2c7eca1d 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -1,4 +1,4 @@ -//===--- Marshallers.h - Generic matcher function marshallers ---*- C++ -*-===// +//===- Marshallers.h - Generic matcher function marshallers -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,7 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Functions templates and classes to wrap matcher construct functions. /// @@ -14,18 +14,33 @@ /// marshalling layer on top of matcher construct functions. /// These are used by the registry to export all marshaller constructors with /// the same generic interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H #define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H -#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/OperationKinds.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/AttrKinds.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <limits> +#include <memory> #include <string> +#include <utility> +#include <vector> namespace clang { namespace ast_matchers { @@ -41,9 +56,11 @@ template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> { template <> struct ArgTypeTraits<std::string> { static bool is(const VariantValue &Value) { return Value.isString(); } + static const std::string &get(const VariantValue &Value) { return Value.getString(); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } @@ -53,13 +70,15 @@ template <> struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> { }; -template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { +template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> { static bool is(const VariantValue &Value) { return Value.isMatcher() && Value.getMatcher().hasTypedMatcher<T>(); } + static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { return Value.getMatcher().getTypedMatcher<T>(); } + static ArgKind getKind() { return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); } @@ -67,9 +86,11 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { template <> struct ArgTypeTraits<bool> { static bool is(const VariantValue &Value) { return Value.isBoolean(); } + static bool get(const VariantValue &Value) { return Value.getBoolean(); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_Boolean); } @@ -77,9 +98,11 @@ template <> struct ArgTypeTraits<bool> { template <> struct ArgTypeTraits<double> { static bool is(const VariantValue &Value) { return Value.isDouble(); } + static double get(const VariantValue &Value) { return Value.getDouble(); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_Double); } @@ -87,9 +110,11 @@ template <> struct ArgTypeTraits<double> { template <> struct ArgTypeTraits<unsigned> { static bool is(const VariantValue &Value) { return Value.isUnsigned(); } + static unsigned get(const VariantValue &Value) { return Value.getUnsigned(); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_Unsigned); } @@ -97,42 +122,45 @@ template <> struct ArgTypeTraits<unsigned> { template <> struct ArgTypeTraits<attr::Kind> { private: - static attr::Kind getAttrKind(llvm::StringRef AttrKind) { - return llvm::StringSwitch<attr::Kind>(AttrKind) + static Optional<attr::Kind> getAttrKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<Optional<attr::Kind>>(AttrKind) #define ATTR(X) .Case("attr::" #X, attr:: X) #include "clang/Basic/AttrList.inc" - .Default(attr::Kind(-1)); + .Default(llvm::None); } + public: static bool is(const VariantValue &Value) { - return Value.isString() && - getAttrKind(Value.getString()) != attr::Kind(-1); + return Value.isString() && getAttrKind(Value.getString()); } + static attr::Kind get(const VariantValue &Value) { - return getAttrKind(Value.getString()); + return *getAttrKind(Value.getString()); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } }; -template <> struct ArgTypeTraits<clang::CastKind> { +template <> struct ArgTypeTraits<CastKind> { private: - static clang::CastKind getCastKind(llvm::StringRef AttrKind) { - return llvm::StringSwitch<clang::CastKind>(AttrKind) + static Optional<CastKind> getCastKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<Optional<CastKind>>(AttrKind) #define CAST_OPERATION(Name) .Case( #Name, CK_##Name) #include "clang/AST/OperationKinds.def" - .Default(CK_Invalid); + .Default(llvm::None); } public: static bool is(const VariantValue &Value) { - return Value.isString() && - getCastKind(Value.getString()) != CK_Invalid; + return Value.isString() && getCastKind(Value.getString()); } - static clang::CastKind get(const VariantValue &Value) { - return getCastKind(Value.getString()); + + static CastKind get(const VariantValue &Value) { + return *getCastKind(Value.getString()); } + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } @@ -144,7 +172,8 @@ public: /// arguments, and various other methods for type introspection. class MatcherDescriptor { public: - virtual ~MatcherDescriptor() {} + virtual ~MatcherDescriptor() = default; + virtual VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, Diagnostics *Error) const = 0; @@ -201,11 +230,11 @@ inline bool isRetKindConvertibleTo( /// their types, unpacking them and calling the underlying function. class FixedArgCountMatcherDescriptor : public MatcherDescriptor { public: - typedef VariantMatcher (*MarshallerType)(void (*Func)(), - StringRef MatcherName, - SourceRange NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error); + using MarshallerType = VariantMatcher (*)(void (*Func)(), + StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); /// \param Marshaller Function to unpack the arguments and call \c Func /// \param Func Matcher construct function. This is the function that @@ -229,10 +258,12 @@ public: bool isVariadic() const override { return false; } unsigned getNumArgs() const override { return ArgKinds.size(); } + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ArgKinds[ArgNo]); } + bool isConvertibleTo( ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { @@ -303,14 +334,14 @@ struct BuildReturnTypeVector { }; template <typename T> -struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T> > { +struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T>> { static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); } }; template <typename T> -struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T> > { +struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T>> { static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) { RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); } @@ -326,7 +357,8 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange, bool HasError = false; for (size_t i = 0, e = Args.size(); i != e; ++i) { - typedef ArgTypeTraits<ArgT> ArgTraits; + using ArgTraits = ArgTypeTraits<ArgT>; + const ParserValue &Arg = Args[i]; const VariantValue &Value = Arg.Value; if (!ArgTraits::is(Value)) { @@ -360,10 +392,10 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange, /// object file. class VariadicFuncMatcherDescriptor : public MatcherDescriptor { public: - typedef VariantMatcher (*RunFunc)(StringRef MatcherName, - SourceRange NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error); + using RunFunc = VariantMatcher (*)(StringRef MatcherName, + SourceRange NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error); template <typename ResultT, typename ArgT, ResultT (*F)(ArrayRef<const ArgT *>)> @@ -384,10 +416,12 @@ public: bool isVariadic() const override { return true; } unsigned getNumArgs() const override { return 0; } + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ArgsKind); } + bool isConvertibleTo( ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { @@ -458,7 +492,7 @@ static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef<ParserValue> Args, Diagnostics *Error) { - typedef ReturnType (*FuncType)(); + using FuncType = ReturnType (*)(); CHECK_ARG_COUNT(0); return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)()); } @@ -469,7 +503,7 @@ static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef<ParserValue> Args, Diagnostics *Error) { - typedef ReturnType (*FuncType)(ArgType1); + using FuncType = ReturnType (*)(ArgType1); CHECK_ARG_COUNT(1); CHECK_ARG_TYPE(0, ArgType1); return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)( @@ -482,7 +516,7 @@ static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef<ParserValue> Args, Diagnostics *Error) { - typedef ReturnType (*FuncType)(ArgType1, ArgType2); + using FuncType = ReturnType (*)(ArgType1, ArgType2); CHECK_ARG_COUNT(2); CHECK_ARG_TYPE(0, ArgType1); CHECK_ARG_TYPE(1, ArgType2); @@ -507,8 +541,8 @@ public: } private: - typedef ast_matchers::internal::ArgumentAdaptingMatcherFunc< - ArgumentAdapterT, FromTypes, ToTypes> AdaptativeFunc; + using AdaptativeFunc = ast_matchers::internal::ArgumentAdaptingMatcherFunc< + ArgumentAdapterT, FromTypes, ToTypes>; /// \brief End case for the recursion static void collect(ast_matchers::internal::EmptyTypeList) {} @@ -534,7 +568,7 @@ public: : Overloads(std::make_move_iterator(Callbacks.begin()), std::make_move_iterator(Callbacks.end())) {} - ~OverloadedMatcherDescriptor() override {} + ~OverloadedMatcherDescriptor() override = default; VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, @@ -604,7 +638,8 @@ private: /// \brief Variadic operator marshaller function. class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { public: - typedef DynTypedMatcher::VariadicOperator VarOp; + using VarOp = DynTypedMatcher::VariadicOperator; + VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount, VarOp Op, StringRef MatcherName) : MinCount(MinCount), MaxCount(MaxCount), Op(Op), @@ -615,7 +650,9 @@ public: Diagnostics *Error) const override { if (Args.size() < MinCount || MaxCount < Args.size()) { const std::string MaxStr = - (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str(); + (MaxCount == std::numeric_limits<unsigned>::max() ? "" + : Twine(MaxCount)) + .str(); Error->addError(NameRange, Error->ET_RegistryWrongArgCount) << ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size(); return VariantMatcher(); @@ -637,10 +674,12 @@ public: bool isVariadic() const override { return true; } unsigned getNumArgs() const override { return 0; } + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ThisKind); } + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { if (Specificity) @@ -649,6 +688,7 @@ public: *LeastDerivedKind = Kind; return true; } + bool isPolymorphic() const override { return true; } private: diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp index f5bd296689951..89e1a2695860c 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp @@ -1,4 +1,4 @@ -//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===// +//===- Parser.cpp - Matcher expression parser -----------------------------===// // // The LLVM Compiler Infrastructure // @@ -13,11 +13,21 @@ //===----------------------------------------------------------------------===// #include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/Registry.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstddef> +#include <cstdlib> #include <string> +#include <utility> #include <vector> namespace clang { @@ -43,10 +53,10 @@ struct Parser::TokenInfo { /// \brief Some known identifiers. static const char* const ID_Bind; - TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {} + TokenInfo() = default; StringRef Text; - TokenKind Kind; + TokenKind Kind = TK_Eof; SourceRange Range; VariantValue Value; }; @@ -57,14 +67,13 @@ const char* const Parser::TokenInfo::ID_Bind = "bind"; class Parser::CodeTokenizer { public: explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) - : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error), - CodeCompletionLocation(nullptr) { + : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) { NextToken = getNextToken(); } CodeTokenizer(StringRef MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset) - : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error), + : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error), CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) { NextToken = getNextToken(); } @@ -138,7 +147,7 @@ private: if (isAlphanumeric(Code[0])) { // Parse an identifier size_t TokenLength = 1; - while (1) { + while (true) { // A code completion location in/immediately after an identifier will // cause the portion of the identifier before the code completion // location to become a code completion token. @@ -283,22 +292,22 @@ private: StringRef Code; StringRef StartOfLine; - unsigned Line; + unsigned Line = 1; Diagnostics *Error; TokenInfo NextToken; - const char *CodeCompletionLocation; + const char *CodeCompletionLocation = nullptr; }; -Parser::Sema::~Sema() {} +Parser::Sema::~Sema() = default; std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes( llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { - return std::vector<ArgKind>(); + return {}; } std::vector<MatcherCompletion> Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) { - return std::vector<MatcherCompletion>(); + return {}; } struct Parser::ScopedContextEntry { @@ -384,7 +393,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, EndToken = Tokenizer->consumeNextToken(); break; } - if (Args.size() > 0) { + if (!Args.empty()) { // We must find a , token to continue. const TokenInfo CommaToken = Tokenizer->consumeNextToken(); if (CommaToken.Kind != TokenInfo::TK_Comma) { @@ -558,7 +567,7 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema), NamedValues(NamedValues), Error(Error) {} -Parser::RegistrySema::~RegistrySema() {} +Parser::RegistrySema::~RegistrySema() = default; llvm::Optional<MatcherCtor> Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) { @@ -640,6 +649,6 @@ Parser::parseMatcherExpression(StringRef Code, Sema *S, return Result; } -} // namespace dynamic -} // namespace ast_matchers -} // namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 031ceb320306d..2b7bb7a2120d1 100644 --- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -1,37 +1,49 @@ -//===--- Registry.cpp - Matcher registry -------------------------===// +//===- Registry.cpp - Matcher registry ------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===------------------------------------------------------------===// -/// +//===----------------------------------------------------------------------===// +// /// \file /// \brief Registry map populated at static initialization time. -/// -//===------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// #include "clang/ASTMatchers/Dynamic/Registry.h" #include "Marshallers.h" +#include "clang/AST/ASTTypeTraits.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <iterator> +#include <memory> #include <set> +#include <string> #include <utility> +#include <vector> using namespace clang::ast_type_traits; namespace clang { namespace ast_matchers { namespace dynamic { + namespace { using internal::MatcherDescriptor; -typedef llvm::StringMap<std::unique_ptr<const MatcherDescriptor>> ConstructorMap; +using ConstructorMap = llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>; + class RegistryMaps { public: RegistryMaps(); @@ -46,6 +58,8 @@ private: ConstructorMap Constructors; }; +} // namespace + void RegistryMaps::registerMatcher( StringRef MatcherName, std::unique_ptr<MatcherDescriptor> Callback) { assert(Constructors.find(MatcherName) == Constructors.end()); @@ -74,7 +88,7 @@ void RegistryMaps::registerMatcher( MATCHER_OVERLOAD_ENTRY(name, 0), \ MATCHER_OVERLOAD_ENTRY(name, 1)}; \ REGISTER_MATCHER_OVERLOAD(name); \ - } while (0) + } while (false) /// \brief Generate a registry map with all the known matchers. RegistryMaps::RegistryMaps() { @@ -196,6 +210,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forEachArgumentWithParam); REGISTER_MATCHER(forEachConstructorInitializer); REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachOverridden); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); REGISTER_MATCHER(forFunction); @@ -219,6 +234,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnyUsingShadowDecl); REGISTER_MATCHER(hasArgument); REGISTER_MATCHER(hasArgumentOfType); + REGISTER_MATCHER(hasArraySize); REGISTER_MATCHER(hasAttr); REGISTER_MATCHER(hasAutomaticStorageDuration); REGISTER_MATCHER(hasBase); @@ -233,6 +249,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasDeclaration); REGISTER_MATCHER(hasDeclContext); REGISTER_MATCHER(hasDeducedType); + REGISTER_MATCHER(hasDefaultArgument); + REGISTER_MATCHER(hasDefinition); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); REGISTER_MATCHER(hasDynamicExceptionSpec); @@ -301,6 +319,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isAnonymous); REGISTER_MATCHER(isAnyCharacter); REGISTER_MATCHER(isAnyPointer); + REGISTER_MATCHER(isArray); REGISTER_MATCHER(isArrow); REGISTER_MATCHER(isBaseInitializer); REGISTER_MATCHER(isBitField); @@ -355,6 +374,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(labelDecl); REGISTER_MATCHER(labelStmt); REGISTER_MATCHER(lambdaExpr); + REGISTER_MATCHER(linkageSpecDecl); REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(matchesName); REGISTER_MATCHER(matchesSelector); @@ -372,7 +392,11 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(nullStmt); REGISTER_MATCHER(numSelectorArgs); REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(objcCatchStmt); REGISTER_MATCHER(objcCategoryDecl); + REGISTER_MATCHER(objcCategoryImplDecl); + REGISTER_MATCHER(objcFinallyStmt); + REGISTER_MATCHER(objcImplementationDecl); REGISTER_MATCHER(objcInterfaceDecl); REGISTER_MATCHER(objcIvarDecl); REGISTER_MATCHER(objcMessageExpr); @@ -380,6 +404,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(objcObjectPointerType); REGISTER_MATCHER(objcPropertyDecl); REGISTER_MATCHER(objcProtocolDecl); + REGISTER_MATCHER(objcThrowStmt); + REGISTER_MATCHER(objcTryStmt); REGISTER_MATCHER(on); REGISTER_MATCHER(onImplicitObjectArgument); REGISTER_MATCHER(opaqueValueExpr); @@ -450,12 +476,10 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(withInitializer); } -RegistryMaps::~RegistryMaps() {} +RegistryMaps::~RegistryMaps() = default; static llvm::ManagedStatic<RegistryMaps> RegistryData; -} // anonymous namespace - // static llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) { auto it = RegistryData->constructors().find(MatcherName); @@ -464,10 +488,8 @@ llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) { : it->second.get(); } -namespace { - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const std::set<ASTNodeKind> &KS) { +static llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const std::set<ASTNodeKind> &KS) { unsigned Count = 0; for (std::set<ASTNodeKind>::const_iterator I = KS.begin(), E = KS.end(); I != E; ++I) { @@ -482,8 +504,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } -} // namespace - std::vector<ArgKind> Registry::getAcceptedCompletionTypes( ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { ASTNodeKind InitialTypes[] = { @@ -593,7 +613,6 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) { return Completions; } -// static VariantMatcher Registry::constructMatcher(MatcherCtor Ctor, SourceRange NameRange, ArrayRef<ParserValue> Args, @@ -601,7 +620,6 @@ VariantMatcher Registry::constructMatcher(MatcherCtor Ctor, return Ctor->create(NameRange, Args, Error); } -// static VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, @@ -621,6 +639,6 @@ VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor, return VariantMatcher(); } -} // namespace dynamic -} // namespace ast_matchers -} // namespace clang +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp index ec15f34fb231d..181edff0a03f5 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -12,8 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/AnalysisContext.h" -#include "BodyFarm.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -23,6 +22,7 @@ #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Support/BumpVector.h" @@ -63,33 +63,25 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } -AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, - bool addImplicitDtors, - bool addInitializers, - bool addTemporaryDtors, - bool addLifetime, - bool synthesizeBodies, - bool addStaticInitBranch, - bool addCXXNewAllocator, - CodeInjector *injector) - : Injector(injector), SynthesizeBodies(synthesizeBodies) -{ +AnalysisDeclContextManager::AnalysisDeclContextManager( + ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors, + bool addInitializers, bool addTemporaryDtors, bool addLifetime, + bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch, + bool addCXXNewAllocator, CodeInjector *injector) + : Injector(injector), FunctionBodyFarm(ASTCtx, injector), + SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; cfgBuildOptions.AddLifetime = addLifetime; + cfgBuildOptions.AddLoopExit = addLoopExit; cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; } void AnalysisDeclContextManager::clear() { Contexts.clear(); } -static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) { - static BodyFarm *BF = new BodyFarm(C, injector); - return *BF; -} - Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { IsAutosynthesized = false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -97,8 +89,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body)) Body = CoroBody->getBody(); if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = - getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD); + Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -109,8 +100,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { Stmt *Body = MD->getBody(); if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = - getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD); + Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -315,6 +305,8 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { return AC.get(); } +BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; } + const StackFrameContext * AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, const CFGBlock *Blk, unsigned Idx) { @@ -608,8 +600,6 @@ AnalysisDeclContext::~AnalysisDeclContext() { } } -AnalysisDeclContextManager::~AnalysisDeclContextManager() {} - LocationContext::~LocationContext() {} LocationContextManager::~LocationContextManager() { diff --git a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp index 59127246105d3..e5d3c5ce5bc2a 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp @@ -12,13 +12,20 @@ // //===----------------------------------------------------------------------===// -#include "BodyFarm.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/Analysis/CodeInjector.h" +#include "clang/Basic/OperatorKinds.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "body-farm" using namespace clang; @@ -55,7 +62,8 @@ public: CompoundStmt *makeCompound(ArrayRef<Stmt*>); /// Create a new DeclRefExpr for the referenced variable. - DeclRefExpr *makeDeclRefExpr(const VarDecl *D); + DeclRefExpr *makeDeclRefExpr(const VarDecl *D, + bool RefersToEnclosingVariableOrCapture = false); /// Create a new UnaryOperator representing a dereference. UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); @@ -66,9 +74,19 @@ public: /// Create an implicit cast to a builtin boolean type. ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); - // Create an implicit cast for lvalue-to-rvaluate conversions. + /// Create an implicit cast for lvalue-to-rvaluate conversions. ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); + /// Make RValue out of variable declaration, creating a temporary + /// DeclRefExpr in the process. + ImplicitCastExpr * + makeLvalueToRvalue(const VarDecl *Decl, + bool RefersToEnclosingVariableOrCapture = false); + + /// Create an implicit cast of the given type. + ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty, + CastKind CK = CK_LValueToRValue); + /// Create an Objective-C bool literal. ObjCBoolLiteralExpr *makeObjCBool(bool Val); @@ -78,6 +96,18 @@ public: /// Create a Return statement. ReturnStmt *makeReturn(const Expr *RetVal); + /// Create an integer literal expression of the given type. + IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty); + + /// Create a member expression. + MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl, + bool IsArrow = false, + ExprValueKind ValueKind = VK_LValue); + + /// Returns a *first* member field of a record declaration with a given name. + /// \return an nullptr if no member with such a name exists. + ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name); + private: ASTContext &C; }; @@ -106,16 +136,14 @@ CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation()); } -DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { - DeclRefExpr *DR = - DeclRefExpr::Create(/* Ctx = */ C, - /* QualifierLoc = */ NestedNameSpecifierLoc(), - /* TemplateKWLoc = */ SourceLocation(), - /* D = */ const_cast<VarDecl*>(D), - /* RefersToEnclosingVariableOrCapture = */ false, - /* NameLoc = */ SourceLocation(), - /* T = */ D->getType(), - /* VK = */ VK_LValue); +DeclRefExpr *ASTMaker::makeDeclRefExpr( + const VarDecl *D, + bool RefersToEnclosingVariableOrCapture) { + QualType Type = D->getType().getNonReferenceType(); + + DeclRefExpr *DR = DeclRefExpr::Create( + C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D), + RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue); return DR; } @@ -125,8 +153,25 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { } ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { - return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, - const_cast<Expr*>(Arg), nullptr, VK_RValue); + return makeImplicitCast(Arg, Ty, CK_LValueToRValue); +} + +ImplicitCastExpr * +ASTMaker::makeLvalueToRvalue(const VarDecl *Arg, + bool RefersToEnclosingVariableOrCapture) { + QualType Type = Arg->getType().getNonReferenceType(); + return makeLvalueToRvalue(makeDeclRefExpr(Arg, + RefersToEnclosingVariableOrCapture), + Type); +} + +ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty, + CastKind CK) { + return ImplicitCastExpr::Create(C, Ty, + /* CastKind=*/ CK, + /* Expr=*/ const_cast<Expr *>(Arg), + /* CXXCastPath=*/ nullptr, + /* ExprValueKind=*/ VK_RValue); } Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { @@ -161,12 +206,259 @@ ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { nullptr); } +IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) { + llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value); + return IntegerLiteral::Create(C, APValue, Ty, SourceLocation()); +} + +MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl, + bool IsArrow, + ExprValueKind ValueKind) { + + DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public); + return MemberExpr::Create( + C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), MemberDecl, FoundDecl, + DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), + /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, + OK_Ordinary); +} + +ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { + + CXXBasePaths Paths( + /* FindAmbiguities=*/false, + /* RecordPaths=*/false, + /* DetectVirtual=*/ false); + const IdentifierInfo &II = C.Idents.get(Name); + DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); + + DeclContextLookupResult Decls = RD->lookup(DeclName); + for (NamedDecl *FoundDecl : Decls) + if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) + return cast<ValueDecl>(FoundDecl); + + return nullptr; +} + //===----------------------------------------------------------------------===// // Creation functions for faux ASTs. //===----------------------------------------------------------------------===// typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); +static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, + const ParmVarDecl *Callback, + ArrayRef<Expr *> CallArgs) { + + QualType Ty = Callback->getType(); + DeclRefExpr *Call = M.makeDeclRefExpr(Callback); + CastKind CK; + if (Ty->isRValueReferenceType()) { + CK = CK_LValueToRValue; + } else { + assert(Ty->isLValueReferenceType()); + CK = CK_FunctionToPointerDecay; + Ty = C.getPointerType(Ty.getNonReferenceType()); + } + + return new (C) + CallExpr(C, M.makeImplicitCast(Call, Ty.getNonReferenceType(), CK), + /*args=*/CallArgs, + /*QualType=*/C.VoidTy, + /*ExprValueType=*/VK_RValue, + /*SourceLocation=*/SourceLocation()); +} + +static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, + const ParmVarDecl *Callback, + CXXRecordDecl *CallbackDecl, + ArrayRef<Expr *> CallArgs) { + assert(CallbackDecl != nullptr); + assert(CallbackDecl->isLambda()); + FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); + assert(callOperatorDecl != nullptr); + + DeclRefExpr *callOperatorDeclRef = + DeclRefExpr::Create(/* Ctx =*/ C, + /* QualifierLoc =*/ NestedNameSpecifierLoc(), + /* TemplateKWLoc =*/ SourceLocation(), + const_cast<FunctionDecl *>(callOperatorDecl), + /* RefersToEnclosingVariableOrCapture=*/ false, + /* NameLoc =*/ SourceLocation(), + /* T =*/ callOperatorDecl->getType(), + /* VK =*/ VK_LValue); + + return new (C) + CXXOperatorCallExpr(/*AstContext=*/C, OO_Call, callOperatorDeclRef, + /*args=*/CallArgs, + /*QualType=*/C.VoidTy, + /*ExprValueType=*/VK_RValue, + /*SourceLocation=*/SourceLocation(), FPOptions()); +} + +/// Create a fake body for std::call_once. +/// Emulates the following function body: +/// +/// \code +/// typedef struct once_flag_s { +/// unsigned long __state = 0; +/// } once_flag; +/// template<class Callable> +/// void call_once(once_flag& o, Callable func) { +/// if (!o.__state) { +/// func(); +/// } +/// o.__state = 1; +/// } +/// \endcode +static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { + DEBUG(llvm::dbgs() << "Generating body for call_once\n"); + + // We need at least two parameters. + if (D->param_size() < 2) + return nullptr; + + ASTMaker M(C); + + const ParmVarDecl *Flag = D->getParamDecl(0); + const ParmVarDecl *Callback = D->getParamDecl(1); + + if (!Callback->getType()->isReferenceType()) { + llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; + return nullptr; + } + if (!Flag->getType()->isReferenceType()) { + llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; + return nullptr; + } + + QualType CallbackType = Callback->getType().getNonReferenceType(); + + // Nullable pointer, non-null iff function is a CXXRecordDecl. + CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); + QualType FlagType = Flag->getType().getNonReferenceType(); + auto *FlagRecordDecl = dyn_cast_or_null<RecordDecl>(FlagType->getAsTagDecl()); + + if (!FlagRecordDecl) { + DEBUG(llvm::dbgs() << "Flag field is not a record: " + << "unknown std::call_once implementation, " + << "ignoring the call.\n"); + return nullptr; + } + + // We initially assume libc++ implementation of call_once, + // where the once_flag struct has a field `__state_`. + ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); + + // Otherwise, try libstdc++ implementation, with a field + // `_M_once` + if (!FlagFieldDecl) { + FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); + } + + if (!FlagFieldDecl) { + DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " + << "std::once_flag struct: unknown std::call_once " + << "implementation, ignoring the call."); + return nullptr; + } + + bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); + if (CallbackRecordDecl && !isLambdaCall) { + DEBUG(llvm::dbgs() << "Not supported: synthesizing body for functors when " + << "body farming std::call_once, ignoring the call."); + return nullptr; + } + + SmallVector<Expr *, 5> CallArgs; + const FunctionProtoType *CallbackFunctionType; + if (isLambdaCall) { + + // Lambda requires callback itself inserted as a first parameter. + CallArgs.push_back( + M.makeDeclRefExpr(Callback, + /* RefersToEnclosingVariableOrCapture=*/ true)); + CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() + ->getType() + ->getAs<FunctionProtoType>(); + } else if (!CallbackType->getPointeeType().isNull()) { + CallbackFunctionType = + CallbackType->getPointeeType()->getAs<FunctionProtoType>(); + } else { + CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); + } + + if (!CallbackFunctionType) + return nullptr; + + // First two arguments are used for the flag and for the callback. + if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { + DEBUG(llvm::dbgs() << "Types of params of the callback do not match " + << "params passed to std::call_once, " + << "ignoring the call\n"); + return nullptr; + } + + // All arguments past first two ones are passed to the callback, + // and we turn lvalues into rvalues if the argument is not passed by + // reference. + for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { + const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); + Expr *ParamExpr = M.makeDeclRefExpr(PDecl); + if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { + QualType PTy = PDecl->getType().getNonReferenceType(); + ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); + } + CallArgs.push_back(ParamExpr); + } + + CallExpr *CallbackCall; + if (isLambdaCall) { + + CallbackCall = create_call_once_lambda_call(C, M, Callback, + CallbackRecordDecl, CallArgs); + } else { + + // Function pointer case. + CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); + } + + DeclRefExpr *FlagDecl = + M.makeDeclRefExpr(Flag, + /* RefersToEnclosingVariableOrCapture=*/true); + + + MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); + assert(Deref->isLValue()); + QualType DerefType = Deref->getType(); + + // Negation predicate. + UnaryOperator *FlagCheck = new (C) UnaryOperator( + /* input=*/ + M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, + CK_IntegralToBoolean), + /* opc=*/ UO_LNot, + /* QualType=*/ C.IntTy, + /* ExprValueKind=*/ VK_RValue, + /* ExprObjectKind=*/ OK_Ordinary, SourceLocation()); + + // Create assignment. + BinaryOperator *FlagAssignment = M.makeAssignment( + Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType), + DerefType); + + IfStmt *Out = new (C) + IfStmt(C, SourceLocation(), + /* IsConstexpr=*/ false, + /* init=*/ nullptr, + /* var=*/ nullptr, + /* cond=*/ FlagCheck, + /* then=*/ M.makeCompound({CallbackCall, FlagAssignment})); + + return Out; +} + /// Create a fake body for dispatch_once. static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // Check if we have at least two parameters. @@ -193,8 +485,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // sets it, and calls the block. Basically, an AST dump of: // // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { - // if (!*predicate) { - // *predicate = 1; + // if (*predicate != ~0l) { + // *predicate = ~0l; // block(); // } // } @@ -202,22 +494,26 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { ASTMaker M(C); // (1) Create the call. - DeclRefExpr *DR = M.makeDeclRefExpr(Block); - ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, - SourceLocation()); + CallExpr *CE = new (C) CallExpr( + /*ASTContext=*/C, + /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), + /*args=*/None, + /*QualType=*/C.VoidTy, + /*ExprValueType=*/VK_RValue, + /*SourceLocation=*/SourceLocation()); // (2) Create the assignment to the predicate. - IntegerLiteral *IL = - IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1), - C.IntTy, SourceLocation()); + Expr *DoneValue = + new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, + VK_RValue, OK_Ordinary, SourceLocation()); + BinaryOperator *B = M.makeAssignment( M.makeDereference( M.makeLvalueToRvalue( M.makeDeclRefExpr(Predicate), PredicateQPtrTy), PredicateTy), - M.makeIntegralCast(IL, PredicateTy), + M.makeIntegralCast(DoneValue, PredicateTy), PredicateTy); // (3) Create the compound statement. @@ -233,14 +529,15 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { PredicateQPtrTy), PredicateTy), PredicateTy); - - UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy, - VK_RValue, OK_Ordinary, - SourceLocation()); - + + Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); // (5) Create the 'if' statement. - IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, - UO, CS); + IfStmt *If = new (C) IfStmt(C, SourceLocation(), + /* IsConstexpr=*/ false, + /* init=*/ nullptr, + /* var=*/ nullptr, + /* cond=*/ GuardCondition, + /* then=*/ CS); return If; } @@ -370,8 +667,9 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { if (Name.startswith("OSAtomicCompareAndSwap") || Name.startswith("objc_atomicCompareAndSwap")) { FF = create_OSAtomicCompareAndSwap; - } - else { + } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { + FF = create_call_once; + } else { FF = llvm::StringSwitch<FunctionFarmer>(Name) .Case("dispatch_sync", create_dispatch_sync) .Case("dispatch_once", create_dispatch_once) diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index 6a77455edeef6..714b85d3a9fff 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp @@ -1,4 +1,4 @@ -//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===// +//===- CFG.cpp - Classes for representing and building CFGs ---------------===// // // The LLVM Compiler Infrastructure // @@ -15,23 +15,53 @@ #include "clang/Analysis/CFG.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" -#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include <memory> +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <memory> +#include <string> +#include <tuple> +#include <utility> +#include <vector> using namespace clang; -namespace { - static SourceLocation GetEndLoc(Decl *D) { if (VarDecl *VD = dyn_cast<VarDecl>(D)) if (Expr *Ex = VD->getInit()) @@ -41,7 +71,7 @@ static SourceLocation GetEndLoc(Decl *D) { /// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral /// or EnumConstantDecl from the given Expr. If it fails, returns nullptr. -const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { +static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { E = E->IgnoreParens(); if (isa<IntegerLiteral>(E)) return E; @@ -111,6 +141,8 @@ static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) { return DC1 == DC2; } +namespace { + class CFGBuilder; /// The CFG builder uses a recursive algorithm to build the CFG. When @@ -125,7 +157,6 @@ class CFGBuilder; /// contextual information. If AddStmtChoice is 'NotAlwaysAdd', then /// the builder has an option not to add a subexpression as a /// block-level expression. -/// class AddStmtChoice { public: enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 }; @@ -168,23 +199,24 @@ private: /// class LocalScope { public: - typedef BumpVector<VarDecl*> AutomaticVarsTy; + friend class const_iterator; + + using AutomaticVarsTy = BumpVector<VarDecl *>; /// const_iterator - Iterates local scope backwards and jumps to previous /// scope on reaching the beginning of currently iterated scope. class const_iterator { - const LocalScope* Scope; + const LocalScope* Scope = nullptr; /// VarIter is guaranteed to be greater then 0 for every valid iterator. /// Invalid iterator (with null Scope) has VarIter equal to 0. - unsigned VarIter; + unsigned VarIter = 0; public: /// Create invalid iterator. Dereferencing invalid iterator is not allowed. /// Incrementing invalid iterator is allowed and will result in invalid /// iterator. - const_iterator() - : Scope(nullptr), VarIter(0) {} + const_iterator() = default; /// Create valid iterator. In case when S.Prev is an invalid iterator and /// I is equal to 0, this will create invalid iterator. @@ -197,8 +229,8 @@ public: } VarDecl *const* operator->() const { - assert (Scope && "Dereferencing invalid iterator is not allowed"); - assert (VarIter != 0 && "Iterator has invalid value of VarIter member"); + assert(Scope && "Dereferencing invalid iterator is not allowed"); + assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); return &Scope->Vars[VarIter - 1]; } VarDecl *operator*() const { @@ -209,7 +241,7 @@ public: if (!Scope) return *this; - assert (VarIter != 0 && "Iterator has invalid value of VarIter member"); + assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); --VarIter; if (VarIter == 0) *this = Scope->Prev; @@ -236,13 +268,12 @@ public: const_iterator shared_parent(const_iterator L); }; - friend class const_iterator; - private: BumpVectorContext ctx; /// Automatic variables in order of declaration. AutomaticVarsTy Vars; + /// Iterator to variable in previous scope that was declared just before /// begin of this scope. const_iterator Prev; @@ -260,6 +291,8 @@ public: } }; +} // namespace + /// distance - Calculates distance from this to L. L must be reachable from this /// (with use of ++ operator). Cost of calculating the distance is linear w.r.t. /// number of scopes between this and L. @@ -267,8 +300,8 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { int D = 0; const_iterator F = *this; while (F.Scope != L.Scope) { - assert (F != const_iterator() - && "L iterator is not reachable from F iterator."); + assert(F != const_iterator() && + "L iterator is not reachable from F iterator."); D += F.VarIter; F = F.Scope->Prev; } @@ -300,16 +333,18 @@ LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) { } } +namespace { + /// Structure for specifying position in CFG during its build process. It /// consists of CFGBlock that specifies position in CFG and /// LocalScope::const_iterator that specifies position in LocalScope graph. struct BlockScopePosPair { - BlockScopePosPair() : block(nullptr) {} + CFGBlock *block = nullptr; + LocalScope::const_iterator scopePosition; + + BlockScopePosPair() = default; BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos) : block(b), scopePosition(scopePos) {} - - CFGBlock *block; - LocalScope::const_iterator scopePosition; }; /// TryResult - a class representing a variant over the values @@ -317,37 +352,46 @@ struct BlockScopePosPair { /// and is used by the CFGBuilder to decide if a branch condition /// can be decided up front during CFG construction. class TryResult { - int X; + int X = -1; + public: + TryResult() = default; TryResult(bool b) : X(b ? 1 : 0) {} - TryResult() : X(-1) {} bool isTrue() const { return X == 1; } bool isFalse() const { return X == 0; } bool isKnown() const { return X >= 0; } + void negate() { assert(isKnown()); X ^= 0x1; } }; -TryResult bothKnownTrue(TryResult R1, TryResult R2) { +} // namespace + +static TryResult bothKnownTrue(TryResult R1, TryResult R2) { if (!R1.isKnown() || !R2.isKnown()) return TryResult(); return TryResult(R1.isTrue() && R2.isTrue()); } +namespace { + class reverse_children { llvm::SmallVector<Stmt *, 12> childrenBuf; - ArrayRef<Stmt*> children; + ArrayRef<Stmt *> children; + public: reverse_children(Stmt *S); - typedef ArrayRef<Stmt*>::reverse_iterator iterator; + using iterator = ArrayRef<Stmt *>::reverse_iterator; + iterator begin() const { return children.rbegin(); } iterator end() const { return children.rend(); } }; +} // namespace reverse_children::reverse_children(Stmt *S) { if (CallExpr *CE = dyn_cast<CallExpr>(S)) { @@ -374,6 +418,8 @@ reverse_children::reverse_children(Stmt *S) { children = childrenBuf; } +namespace { + /// CFGBuilder - This class implements CFG construction from an AST. /// The builder is stateful: an instance of the builder should be used to only /// construct a single CFG. @@ -387,62 +433,65 @@ reverse_children::reverse_children(Stmt *S) { /// the AST in reverse order so that the successor of a basic block is /// constructed prior to its predecessor. This allows us to nicely capture /// implicit fall-throughs without extra basic blocks. -/// class CFGBuilder { - typedef BlockScopePosPair JumpTarget; - typedef BlockScopePosPair JumpSource; + using JumpTarget = BlockScopePosPair; + using JumpSource = BlockScopePosPair; ASTContext *Context; std::unique_ptr<CFG> cfg; - CFGBlock *Block; - CFGBlock *Succ; + // Current block. + CFGBlock *Block = nullptr; + + // Block after the current block. + CFGBlock *Succ = nullptr; + JumpTarget ContinueJumpTarget; JumpTarget BreakJumpTarget; - CFGBlock *SwitchTerminatedBlock; - CFGBlock *DefaultCaseBlock; - CFGBlock *TryTerminatedBlock; + JumpTarget SEHLeaveJumpTarget; + CFGBlock *SwitchTerminatedBlock = nullptr; + CFGBlock *DefaultCaseBlock = nullptr; + + // This can point either to a try or a __try block. The frontend forbids + // mixing both kinds in one function, so having one for both is enough. + CFGBlock *TryTerminatedBlock = nullptr; // Current position in local scope. LocalScope::const_iterator ScopePos; // LabelMap records the mapping from Label expressions to their jump targets. - typedef llvm::DenseMap<LabelDecl*, JumpTarget> LabelMapTy; + using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>; LabelMapTy LabelMap; // A list of blocks that end with a "goto" that must be backpatched to their // resolved targets upon completion of CFG construction. - typedef std::vector<JumpSource> BackpatchBlocksTy; + using BackpatchBlocksTy = std::vector<JumpSource>; BackpatchBlocksTy BackpatchBlocks; // A list of labels whose address has been taken (for indirect gotos). - typedef llvm::SmallPtrSet<LabelDecl*, 5> LabelSetTy; + using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>; LabelSetTy AddressTakenLabels; - bool badCFG; + bool badCFG = false; const CFG::BuildOptions &BuildOpts; // State to track for building switch statements. - bool switchExclusivelyCovered; - Expr::EvalResult *switchCond; + bool switchExclusivelyCovered = false; + Expr::EvalResult *switchCond = nullptr; - CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry; - const Stmt *lastLookup; + CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry = nullptr; + const Stmt *lastLookup = nullptr; // Caches boolean evaluations of expressions to avoid multiple re-evaluations // during construction of branches for chained logical operators. - typedef llvm::DenseMap<Expr *, TryResult> CachedBoolEvalsTy; + using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>; CachedBoolEvalsTy CachedBoolEvals; public: explicit CFGBuilder(ASTContext *astContext, - const CFG::BuildOptions &buildOpts) - : Context(astContext), cfg(new CFG()), // crew a new CFG - Block(nullptr), Succ(nullptr), - SwitchTerminatedBlock(nullptr), DefaultCaseBlock(nullptr), - TryTerminatedBlock(nullptr), badCFG(false), BuildOpts(buildOpts), - switchExclusivelyCovered(false), switchCond(nullptr), - cachedEntry(nullptr), lastLookup(nullptr) {} + const CFG::BuildOptions &buildOpts) + : Context(astContext), cfg(new CFG()), // crew a new CFG + BuildOpts(buildOpts) {} // buildCFG - Used by external clients to construct the CFG. std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement); @@ -501,6 +550,10 @@ private: CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E); CFGBlock *VisitReturnStmt(ReturnStmt *R); + CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S); + CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S); + CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S); + CFGBlock *VisitSEHTryStmt(SEHTryStmt *S); CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, @@ -542,13 +595,9 @@ private: /// if the CXXBindTemporaryExpr was marked executed, and otherwise /// branches to the stored successor. struct TempDtorContext { - TempDtorContext() - : IsConditional(false), KnownExecuted(true), Succ(nullptr), - TerminatorExpr(nullptr) {} - + TempDtorContext() = default; TempDtorContext(TryResult KnownExecuted) - : IsConditional(true), KnownExecuted(KnownExecuted), Succ(nullptr), - TerminatorExpr(nullptr) {} + : IsConditional(true), KnownExecuted(KnownExecuted) {} /// Returns whether we need to start a new branch for a temporary destructor /// call. This is the case when the temporary destructor is @@ -567,10 +616,10 @@ private: TerminatorExpr = E; } - const bool IsConditional; - const TryResult KnownExecuted; - CFGBlock *Succ; - CXXBindTemporaryExpr *TerminatorExpr; + const bool IsConditional = false; + const TryResult KnownExecuted = true; + CFGBlock *Succ = nullptr; + CXXBindTemporaryExpr *TerminatorExpr = nullptr; }; // Visitors to walk an AST and generate destructors of temporaries in @@ -601,7 +650,9 @@ private: CFGBlock *addStmt(Stmt *S) { return Visit(S, AddStmtChoice::AlwaysAdd); } + CFGBlock *addInitializer(CXXCtorInitializer *I); + void addLoopExit(const Stmt *LoopStmt); void addAutomaticObjDtors(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S); void addLifetimeEnds(LocalScope::const_iterator B, @@ -621,6 +672,7 @@ private: void addLocalScopeAndDtors(Stmt *S); // Interface to CFGBlock - adding CFGElements. + void appendStmt(CFGBlock *B, const Stmt *S) { if (alwaysAdd(S) && cachedEntry) cachedEntry->second = B; @@ -629,21 +681,27 @@ private: assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S); B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext()); } + void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) { B->appendInitializer(I, cfg->getBumpVectorContext()); } + void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) { B->appendNewAllocator(NE, cfg->getBumpVectorContext()); } + void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) { B->appendBaseDtor(BS, cfg->getBumpVectorContext()); } + void appendMemberDtor(CFGBlock *B, FieldDecl *FD) { B->appendMemberDtor(FD, cfg->getBumpVectorContext()); } + void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) { B->appendTemporaryDtor(E, cfg->getBumpVectorContext()); } + void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) { B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext()); } @@ -652,6 +710,10 @@ private: B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext()); } + void appendLoopExit(CFGBlock *B, const Stmt *LoopStmt) { + B->appendLoopExit(LoopStmt, cfg->getBumpVectorContext()); + } + void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) { B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext()); } @@ -799,10 +861,10 @@ private: const BinaryOperator *RHS = dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens()); if (!LHS || !RHS) - return TryResult(); + return {}; if (!LHS->isComparisonOp() || !RHS->isComparisonOp()) - return TryResult(); + return {}; const DeclRefExpr *Decl1; const Expr *Expr1; @@ -810,7 +872,7 @@ private: std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS); if (!Decl1 || !Expr1) - return TryResult(); + return {}; const DeclRefExpr *Decl2; const Expr *Expr2; @@ -818,26 +880,26 @@ private: std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS); if (!Decl2 || !Expr2) - return TryResult(); + return {}; // Check that it is the same variable on both sides. if (Decl1->getDecl() != Decl2->getDecl()) - return TryResult(); + return {}; // Make sure the user's intent is clear (e.g. they're comparing against two // int literals, or two things from the same enum) if (!areExprTypesCompatible(Expr1, Expr2)) - return TryResult(); + return {}; llvm::APSInt L1, L2; if (!Expr1->EvaluateAsInt(L1, *Context) || !Expr2->EvaluateAsInt(L2, *Context)) - return TryResult(); + return {}; // Can't compare signed with unsigned or with different bit width. if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth()) - return TryResult(); + return {}; // Values that will be used to determine if result of logical // operator is always true/false @@ -868,7 +930,7 @@ private: Res2 = analyzeLogicOperatorCondition(BO2, Value, L2); if (!Res1.isKnown() || !Res2.isKnown()) - return TryResult(); + return {}; if (B->getOpcode() == BO_LAnd) { AlwaysTrue &= (Res1.isTrue() && Res2.isTrue()); @@ -884,7 +946,7 @@ private: BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); return TryResult(AlwaysTrue); } - return TryResult(); + return {}; } /// Try and evaluate an expression to an integer constant. @@ -901,7 +963,7 @@ private: TryResult tryEvaluateBool(Expr *S) { if (!BuildOpts.PruneTriviallyFalseEdges || S->isTypeDependent() || S->isValueDependent()) - return TryResult(); + return {}; if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) { if (Bop->isLogicalOp()) { @@ -976,7 +1038,7 @@ private: } } - return TryResult(); + return {}; } else if (Bop->isEqualityOp()) { TryResult BopRes = checkIncorrectEqualityOperator(Bop); if (BopRes.isKnown()) @@ -992,12 +1054,14 @@ private: if (E->EvaluateAsBooleanCondition(Result, *Context)) return Result; - return TryResult(); + return {}; } bool hasTrivialDestructor(VarDecl *VD); }; +} // namespace + inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, const Stmt *stmt) const { return builder.alwaysAdd(stmt) || kind == AlwaysAdd; @@ -1119,7 +1183,6 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { if (CFGBlock *B = cfg->getIndirectGotoBlock()) for (LabelSetTy::iterator I = AddressTakenLabels.begin(), E = AddressTakenLabels.end(); I != E; ++I ) { - // Lookup the target block. LabelMapTy::iterator LI = LabelMap.find(*I); @@ -1253,6 +1316,15 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context, return Init->getType(); } +// TODO: Support adding LoopExit element to the CFG in case where the loop is +// ended by ReturnStmt, GotoStmt or ThrowExpr. +void CFGBuilder::addLoopExit(const Stmt *LoopStmt){ + if(!BuildOpts.AddLoopExit) + return; + autoCreateBlock(); + appendLoopExit(Block, LoopStmt); +} + void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S) { @@ -1351,8 +1423,8 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, /// addImplicitDtorsForDestructor - Add implicit destructors generated for /// base and member objects in destructor. void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) { - assert (BuildOpts.AddImplicitDtors - && "Can be called only when dtors should be added"); + assert(BuildOpts.AddImplicitDtors && + "Can be called only when dtors should be added"); const CXXRecordDecl *RD = DD->getParent(); // At the end destroy virtual base objects. @@ -1555,6 +1627,7 @@ void CFGBuilder::prependAutomaticObjLifetimeWithTerminator( for (LocalScope::const_iterator I = B; I != E; ++I) InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator()); } + /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). @@ -1716,6 +1789,18 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::ReturnStmtClass: return VisitReturnStmt(cast<ReturnStmt>(S)); + case Stmt::SEHExceptStmtClass: + return VisitSEHExceptStmt(cast<SEHExceptStmt>(S)); + + case Stmt::SEHFinallyStmtClass: + return VisitSEHFinallyStmt(cast<SEHFinallyStmt>(S)); + + case Stmt::SEHLeaveStmtClass: + return VisitSEHLeaveStmt(cast<SEHLeaveStmt>(S)); + + case Stmt::SEHTryStmtClass: + return VisitSEHTryStmt(cast<SEHTryStmt>(S)); + case Stmt::UnaryExprOrTypeTraitExprClass: return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), asc); @@ -1797,7 +1882,6 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B, Stmt *Term, CFGBlock *TrueBlock, CFGBlock *FalseBlock) { - // Introspect the RHS. If it is a nested logical operation, we recursively // build the CFG using this function. Otherwise, resort to default // CFG construction behavior. @@ -1886,7 +1970,6 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B, return std::make_pair(EntryLHSBlock, ExitBlock); } - CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc) { // && or || @@ -1948,7 +2031,6 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { } else badCFG = true; - return Block; } @@ -2072,7 +2154,6 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, return addStmt(C->getCond()); } - CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { LocalScope::const_iterator scopeBeginPos = ScopePos; addLocalScopeForStmt(C); @@ -2423,7 +2504,6 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { return LastBlock; } - CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { // If we were in the middle of a block we stop processing that block. // @@ -2447,6 +2527,117 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { return VisitStmt(R, AddStmtChoice::AlwaysAdd); } +CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) { + // SEHExceptStmt are treated like labels, so they are the first statement in a + // block. + + // Save local scope position because in case of exception variable ScopePos + // won't be restored when traversing AST. + SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + + addStmt(ES->getBlock()); + CFGBlock *SEHExceptBlock = Block; + if (!SEHExceptBlock) + SEHExceptBlock = createBlock(); + + appendStmt(SEHExceptBlock, ES); + + // Also add the SEHExceptBlock as a label, like with regular labels. + SEHExceptBlock->setLabel(ES); + + // Bail out if the CFG is bad. + if (badCFG) + return nullptr; + + // We set Block to NULL to allow lazy creation of a new block (if necessary). + Block = nullptr; + + return SEHExceptBlock; +} + +CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) { + return VisitCompoundStmt(FS->getBlock()); +} + +CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) { + // "__leave" is a control-flow statement. Thus we stop processing the current + // block. + if (badCFG) + return nullptr; + + // Now create a new block that ends with the __leave statement. + Block = createBlock(false); + Block->setTerminator(LS); + + // If there is no target for the __leave, then we are looking at an incomplete + // AST. This means that the CFG cannot be constructed. + if (SEHLeaveJumpTarget.block) { + addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS); + addSuccessor(Block, SEHLeaveJumpTarget.block); + } else + badCFG = true; + + return Block; +} + +CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) { + // "__try"/"__except"/"__finally" is a control-flow statement. Thus we stop + // processing the current block. + CFGBlock *SEHTrySuccessor = nullptr; + + if (Block) { + if (badCFG) + return nullptr; + SEHTrySuccessor = Block; + } else SEHTrySuccessor = Succ; + + // FIXME: Implement __finally support. + if (Terminator->getFinallyHandler()) + return NYS(); + + CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock; + + // Create a new block that will contain the __try statement. + CFGBlock *NewTryTerminatedBlock = createBlock(false); + + // Add the terminator in the __try block. + NewTryTerminatedBlock->setTerminator(Terminator); + + if (SEHExceptStmt *Except = Terminator->getExceptHandler()) { + // The code after the try is the implicit successor if there's an __except. + Succ = SEHTrySuccessor; + Block = nullptr; + CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except); + if (!ExceptBlock) + return nullptr; + // Add this block to the list of successors for the block with the try + // statement. + addSuccessor(NewTryTerminatedBlock, ExceptBlock); + } + if (PrevSEHTryTerminatedBlock) + addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock); + else + addSuccessor(NewTryTerminatedBlock, &cfg->getExit()); + + // The code after the try is the implicit successor. + Succ = SEHTrySuccessor; + + // Save the current "__try" context. + SaveAndRestore<CFGBlock *> save_try(TryTerminatedBlock, + NewTryTerminatedBlock); + cfg->addTryDispatchBlock(TryTerminatedBlock); + + // Save the current value for the __leave target. + // All __leaves should go to the code following the __try + // (FIXME: or if the __try has a __finally, to the __finally.) + SaveAndRestore<JumpTarget> save_break(SEHLeaveJumpTarget); + SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos); + + assert(Terminator->getTryBlock() && "__try must contain a non-NULL body"); + Block = nullptr; + return addStmt(Terminator->getTryBlock()); +} + CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) { // Get the block of the labeled statement. Add it to our map. addStmt(L->getSubStmt()); @@ -2543,6 +2734,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F); + addLoopExit(F); + // "for" is a control-flow statement. Thus we stop processing the current // block. if (Block) { @@ -2668,7 +2861,6 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { // false branch). addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor); - } while (false); // Link up the loop-back block to the entry condition block. @@ -2730,7 +2922,6 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { // the same with newVariable replaced with existingItem; the binding works // the same except that for one ObjCForCollectionStmt::getElement() returns // a DeclStmt and the other returns a DeclRefExpr. - // CFGBlock *LoopSuccessor = nullptr; @@ -2882,6 +3073,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { addLocalScopeForVarDecl(VD); addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W); } + addLoopExit(W); // "while" is a control-flow statement. Thus we stop processing the current // block. @@ -2981,7 +3173,6 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { // false branch). addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor); - } while(false); // Link up the loop-back block to the entry condition block. @@ -2996,7 +3187,6 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { return EntryConditionBlock; } - CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { // FIXME: For now we pretend that @catch and the code it contains does not // exit. @@ -3045,6 +3235,8 @@ CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) { CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) { CFGBlock *LoopSuccessor = nullptr; + addLoopExit(D); + // "do...while" is a control-flow statement. Thus we stop processing the // current block. if (Block) { @@ -3167,7 +3359,6 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, AddStmtChoice asc) { - if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); appendStmt(Block, E); @@ -3688,7 +3879,6 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C, CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE, AddStmtChoice asc) { - autoCreateBlock(); appendStmt(Block, NE); @@ -3991,8 +4181,6 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( return Block; } -} // end anonymous namespace - /// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has /// no successors or predecessors. If this is the first block created in the /// CFG, it is automatically set to be the Entry and Exit of the CFG. @@ -4025,6 +4213,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { case CFGElement::Statement: case CFGElement::Initializer: case CFGElement::NewAllocator: + case CFGElement::LoopExit: case CFGElement::LifetimeEnds: llvm_unreachable("getDestructorDecl should only be used with " "ImplicitDtors"); @@ -4066,7 +4255,6 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { } case CFGElement::BaseDtor: case CFGElement::MemberDtor: - // Not yet supported. return nullptr; } @@ -4084,14 +4272,14 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { //===----------------------------------------------------------------------===// CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable) - : ReachableBlock(IsReachable ? B : nullptr), - UnreachableBlock(!IsReachable ? B : nullptr, - B && IsReachable ? AB_Normal : AB_Unreachable) {} + : ReachableBlock(IsReachable ? B : nullptr), + UnreachableBlock(!IsReachable ? B : nullptr, + B && IsReachable ? AB_Normal : AB_Unreachable) {} CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock) - : ReachableBlock(B), - UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock, - B == AlternateBlock ? AB_Alternate : AB_Normal) {} + : ReachableBlock(B), + UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock, + B == AlternateBlock ? AB_Alternate : AB_Normal) {} void CFGBlock::addSuccessor(AdjacentBlock Succ, BumpVectorContext &C) { @@ -4106,7 +4294,6 @@ void CFGBlock::addSuccessor(AdjacentBlock Succ, bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F, const CFGBlock *From, const CFGBlock *To) { - if (F.IgnoreNullPredecessors && !From) return true; @@ -4133,18 +4320,18 @@ bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F, namespace { class StmtPrinterHelper : public PrinterHelper { - typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; - typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy; + using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>; + using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>; + StmtMapTy StmtMap; DeclMapTy DeclMap; - signed currentBlock; - unsigned currStmt; + signed currentBlock = 0; + unsigned currStmt = 0; const LangOptions &LangOpts; -public: +public: StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) - : currentBlock(0), currStmt(0), LangOpts(LO) - { + : LangOpts(LO) { for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { unsigned j = 1; for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ; @@ -4199,7 +4386,7 @@ public: } } - ~StmtPrinterHelper() override {} + ~StmtPrinterHelper() override = default; const LangOptions &getLangOpts() const { return LangOpts; } void setBlockID(signed i) { currentBlock = i; } @@ -4235,20 +4422,17 @@ public: return true; } }; -} // end anonymous namespace - -namespace { class CFGBlockTerminatorPrint - : public StmtVisitor<CFGBlockTerminatorPrint,void> { - + : public StmtVisitor<CFGBlockTerminatorPrint,void> { raw_ostream &OS; StmtPrinterHelper* Helper; PrintingPolicy Policy; + public: CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper, const PrintingPolicy &Policy) - : OS(os), Helper(helper), Policy(Policy) { + : OS(os), Helper(helper), Policy(Policy) { this->Policy.IncludeNewlines = false; } @@ -4302,6 +4486,10 @@ public: OS << "try ..."; } + void VisitSEHTryStmt(SEHTryStmt *CS) { + OS << "__try ..."; + } + void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { if (Stmt *Cond = C->getCond()) Cond->printPretty(OS, Helper, Policy); @@ -4353,7 +4541,8 @@ public: Visit(T.getStmt()); } }; -} // end anonymous namespace + +} // namespace static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E) { @@ -4403,7 +4592,6 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, // Expressions need a newline. if (isa<Expr>(S)) OS << '\n'; - } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) { const CXXCtorInitializer *I = IE->getInitializer(); if (I->isBaseInitializer()) @@ -4422,7 +4610,6 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, else if (I->isDelegatingInitializer()) OS << " (Delegating initializer)\n"; else OS << " (Member initializer)\n"; - } else if (Optional<CFGAutomaticObjDtor> DE = E.getAs<CFGAutomaticObjDtor>()) { const VarDecl *VD = DE->getVarDecl(); @@ -4435,13 +4622,14 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; - } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) { const VarDecl *VD = DE->getVarDecl(); Helper.handleDecl(VD, OS); OS << " (Lifetime ends)\n"; - + } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) { + const Stmt *LoopStmt = LE->getLoopStmt(); + OS << LoopStmt->getStmtClassName() << " (LoopExit)\n"; } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) { OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) @@ -4460,14 +4648,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CXXBaseSpecifier *BS = BE->getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; OS << " (Base object destructor)\n"; - } else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) { const FieldDecl *FD = ME->getFieldDecl(); const Type *T = FD->getType()->getBaseElementTypeUnsafe(); OS << "this->" << FD->getName(); OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; OS << " (Member object destructor)\n"; - } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) { const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr(); OS << "~"; @@ -4480,7 +4666,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, const CFGBlock &B, StmtPrinterHelper &Helper, bool print_edges, bool ShowColors) { - Helper.setBlockID(B.getBlockID()); // Print the header. @@ -4505,7 +4690,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, // Print the label of this block. if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) { - if (print_edges) OS << " "; @@ -4531,7 +4715,11 @@ static void print_block(raw_ostream &OS, const CFG* cfg, else OS << "..."; OS << ")"; - + } else if (SEHExceptStmt *ES = dyn_cast<SEHExceptStmt>(Label)) { + OS << "__except ("; + ES->getFilterExpr()->printPretty(OS, &Helper, + PrintingPolicy(Helper.getLangOpts()), 0); + OS << ")"; } else llvm_unreachable("Invalid label statement in CFGBlock."); @@ -4543,7 +4731,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; I != E ; ++I, ++j ) { - // Print the statement # in the basic block and the statement itself. if (print_edges) OS << " "; @@ -4590,7 +4777,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); I != E; ++I, ++i) { - if (i % 10 == 8) OS << "\n "; @@ -4628,7 +4814,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); I != E; ++I, ++i) { - if (i % 10 == 8) OS << "\n "; @@ -4657,7 +4842,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg, } } - /// dump - A simple pretty printer of a CFG that outputs to stderr. void CFG::dump(const LangOptions &LO, bool ShowColors) const { print(llvm::errs(), LO, ShowColors); @@ -4780,7 +4964,6 @@ Stmt *CFGBlock::getTerminatorCondition(bool StripParens) { // CFG Graphviz Visualization //===----------------------------------------------------------------------===// - #ifndef NDEBUG static StmtPrinterHelper* GraphHelper; #endif @@ -4795,13 +4978,12 @@ void CFG::viewCFG(const LangOptions &LO) const { } namespace llvm { + template<> struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { - - DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) { - #ifndef NDEBUG std::string OutSStr; llvm::raw_string_ostream Out(OutSStr); @@ -4819,8 +5001,9 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { return OutStr; #else - return ""; + return {}; #endif } }; -} // end namespace llvm + +} // namespace llvm diff --git a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp index 6d9530bf0c68d..fb6d7e87a9a31 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp @@ -1,4 +1,4 @@ -//== CallGraph.cpp - AST-based Call graph ----------------------*- C++ -*--==// +//===- CallGraph.cpp - AST-based Call graph -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,28 @@ // This file defines the AST-based CallGraph. // //===----------------------------------------------------------------------===// + #include "clang/Analysis/CallGraph.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <memory> +#include <string> using namespace clang; @@ -26,6 +41,7 @@ STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges"); STATISTIC(NumBlockCallEdges, "Number of block call edges"); namespace { + /// A helper class, which walks the AST and locates all the call sites in the /// given function body. class CGBuilder : public StmtVisitor<CGBuilder> { @@ -33,8 +49,7 @@ class CGBuilder : public StmtVisitor<CGBuilder> { CallGraphNode *CallerNode; public: - CGBuilder(CallGraph *g, CallGraphNode *N) - : G(g), CallerNode(N) {} + CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {} void VisitStmt(Stmt *S) { VisitChildren(S); } @@ -90,7 +105,7 @@ public: } }; -} // end anonymous namespace +} // namespace void CallGraph::addNodesForBlocks(DeclContext *D) { if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) @@ -105,7 +120,7 @@ CallGraph::CallGraph() { Root = getOrInsertNode(nullptr); } -CallGraph::~CallGraph() {} +CallGraph::~CallGraph() = default; bool CallGraph::includeInGraph(const Decl *D) { assert(D); @@ -164,8 +179,8 @@ void CallGraph::print(raw_ostream &OS) const { // We are going to print the graph in reverse post order, partially, to make // sure the output is deterministic. - llvm::ReversePostOrderTraversal<const clang::CallGraph*> RPOT(this); - for (llvm::ReversePostOrderTraversal<const clang::CallGraph*>::rpo_iterator + llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this); + for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator I = RPOT.begin(), E = RPOT.end(); I != E; ++I) { const CallGraphNode *N = *I; @@ -209,8 +224,7 @@ namespace llvm { template <> struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits { - - DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} static std::string getNodeLabel(const CallGraphNode *Node, const CallGraph *CG) { @@ -222,6 +236,6 @@ struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits { else return "< >"; } - }; -} + +} // namespace llvm diff --git a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp index 5ea74989a7ec9..098803f9a417d 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp @@ -13,16 +13,12 @@ #include "clang/Analysis/CloneDetection.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/AST/Stmt.h" -#include "clang/Lex/Lexer.h" +#include "clang/AST/DataCollection.h" +#include "clang/AST/DeclTemplate.h" #include "llvm/Support/MD5.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" using namespace clang; -using namespace clang::clone_detection; StmtSequence::StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex, unsigned EndIndex) @@ -91,34 +87,6 @@ SourceRange StmtSequence::getSourceRange() const { return SourceRange(getStartLoc(), getEndLoc()); } -/// Prints the macro name that contains the given SourceLocation into the given -/// raw_string_ostream. -static void printMacroName(llvm::raw_string_ostream &MacroStack, - ASTContext &Context, SourceLocation Loc) { - MacroStack << Lexer::getImmediateMacroName(Loc, Context.getSourceManager(), - Context.getLangOpts()); - - // Add an empty space at the end as a padding to prevent - // that macro names concatenate to the names of other macros. - MacroStack << " "; -} - -std::string clone_detection::getMacroStack(SourceLocation Loc, - ASTContext &Context) { - std::string MacroStack; - llvm::raw_string_ostream MacroStackStream(MacroStack); - SourceManager &SM = Context.getSourceManager(); - - // Iterate over all macros that expanded into the given SourceLocation. - while (Loc.isMacroID()) { - // Add the macro name to the stream. - printMacroName(MacroStackStream, Context, Loc); - Loc = SM.getImmediateMacroCallerLoc(Loc); - } - MacroStackStream.flush(); - return MacroStack; -} - void CloneDetector::analyzeCodeBody(const Decl *D) { assert(D); assert(D->hasBody()); @@ -184,16 +152,17 @@ void OnlyLargestCloneConstraint::constrain( } } -bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) { +bool FilenamePatternConstraint::isAutoGenerated( + const CloneDetector::CloneGroup &Group) { std::string Error; - if (IgnoredFilesPattern.empty() || Group.empty() || + if (IgnoredFilesPattern.empty() || Group.empty() || !IgnoredFilesRegex->isValid(Error)) return false; for (const StmtSequence &S : Group) { const SourceManager &SM = S.getASTContext().getSourceManager(); - StringRef Filename = llvm::sys::path::filename(SM.getFilename( - S.getContainingDecl()->getLocation())); + StringRef Filename = llvm::sys::path::filename( + SM.getFilename(S.getContainingDecl()->getLocation())); if (IgnoredFilesRegex->match(Filename)) return true; } @@ -201,6 +170,59 @@ bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup return false; } +/// This class defines what a type II code clone is: If it collects for two +/// statements the same data, then those two statements are considered to be +/// clones of each other. +/// +/// All collected data is forwarded to the given data consumer of the type T. +/// The data consumer class needs to provide a member method with the signature: +/// update(StringRef Str) +namespace { +template <class T> +class CloneTypeIIStmtDataCollector + : public ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>> { + ASTContext &Context; + /// The data sink to which all data is forwarded. + T &DataConsumer; + + template <class Ty> void addData(const Ty &Data) { + data_collection::addDataToConsumer(DataConsumer, Data); + } + +public: + CloneTypeIIStmtDataCollector(const Stmt *S, ASTContext &Context, + T &DataConsumer) + : Context(Context), DataConsumer(DataConsumer) { + this->Visit(S); + } + +// Define a visit method for each class to collect data and subsequently visit +// all parent classes. This uses a template so that custom visit methods by us +// take precedence. +#define DEF_ADD_DATA(CLASS, CODE) \ + template <class = void> void Visit##CLASS(const CLASS *S) { \ + CODE; \ + ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \ + } + +#include "clang/AST/StmtDataCollectors.inc" + +// Type II clones ignore variable names and literals, so let's skip them. +#define SKIP(CLASS) \ + void Visit##CLASS(const CLASS *S) { \ + ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \ + } + SKIP(DeclRefExpr) + SKIP(MemberExpr) + SKIP(IntegerLiteral) + SKIP(FloatingLiteral) + SKIP(StringLiteral) + SKIP(CXXBoolLiteralExpr) + SKIP(CharacterLiteral) +#undef SKIP +}; +} // end anonymous namespace + static size_t createHash(llvm::MD5 &Hash) { size_t HashCode; @@ -216,13 +238,22 @@ static size_t createHash(llvm::MD5 &Hash) { return HashCode; } -size_t RecursiveCloneTypeIIConstraint::saveHash( - const Stmt *S, const Decl *D, - std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash) { +/// Generates and saves a hash code for the given Stmt. +/// \param S The given Stmt. +/// \param D The Decl containing S. +/// \param StmtsByHash Output parameter that will contain the hash codes for +/// each StmtSequence in the given Stmt. +/// \return The hash code of the given Stmt. +/// +/// If the given Stmt is a CompoundStmt, this method will also generate +/// hashes for all possible StmtSequences in the children of this Stmt. +static size_t +saveHash(const Stmt *S, const Decl *D, + std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash) { llvm::MD5 Hash; ASTContext &Context = D->getASTContext(); - StmtDataCollector<llvm::MD5>(S, Context, Hash); + CloneTypeIIStmtDataCollector<llvm::MD5>(S, Context, Hash); auto CS = dyn_cast<CompoundStmt>(S); SmallVector<size_t, 8> ChildHashes; @@ -288,8 +319,8 @@ public: static void CollectStmtSequenceData(const StmtSequence &Sequence, FoldingSetNodeIDWrapper &OutputData) { for (const Stmt *S : Sequence) { - StmtDataCollector<FoldingSetNodeIDWrapper>(S, Sequence.getASTContext(), - OutputData); + CloneTypeIIStmtDataCollector<FoldingSetNodeIDWrapper>( + S, Sequence.getASTContext(), OutputData); for (const Stmt *Child : S->children()) { if (!Child) @@ -318,7 +349,7 @@ static bool areSequencesClones(const StmtSequence &LHS, return DataLHS == DataRHS; } -void RecursiveCloneTypeIIConstraint::constrain( +void RecursiveCloneTypeIIHashConstraint::constrain( std::vector<CloneDetector::CloneGroup> &Sequences) { // FIXME: Maybe we can do this in-place and don't need this additional vector. std::vector<CloneDetector::CloneGroup> Result; @@ -339,7 +370,7 @@ void RecursiveCloneTypeIIConstraint::constrain( // Sort hash_codes in StmtsByHash. std::stable_sort(StmtsByHash.begin(), StmtsByHash.end(), [](std::pair<size_t, StmtSequence> LHS, - std::pair<size_t, StmtSequence> RHS) { + std::pair<size_t, StmtSequence> RHS) { return LHS.first < RHS.first; }); @@ -359,8 +390,7 @@ void RecursiveCloneTypeIIConstraint::constrain( for (; i < StmtsByHash.size(); ++i) { // A different hash value means we have reached the end of the sequence. - if (PrototypeHash != StmtsByHash[i].first || - !areSequencesClones(StmtsByHash[i].second, Current.second)) { + if (PrototypeHash != StmtsByHash[i].first) { // The current sequence could be the start of a new CloneGroup. So we // decrement i so that we visit it again in the outer loop. // Note: i can never be 0 at this point because we are just comparing @@ -383,8 +413,17 @@ void RecursiveCloneTypeIIConstraint::constrain( Sequences = Result; } +void RecursiveCloneTypeIIVerifyConstraint::constrain( + std::vector<CloneDetector::CloneGroup> &Sequences) { + CloneConstraint::splitCloneGroups( + Sequences, [](const StmtSequence &A, const StmtSequence &B) { + return areSequencesClones(A, B); + }); +} + size_t MinComplexityConstraint::calculateStmtComplexity( - const StmtSequence &Seq, const std::string &ParentMacroStack) { + const StmtSequence &Seq, std::size_t Limit, + const std::string &ParentMacroStack) { if (Seq.empty()) return 0; @@ -393,8 +432,8 @@ size_t MinComplexityConstraint::calculateStmtComplexity( ASTContext &Context = Seq.getASTContext(); // Look up what macros expanded into the current statement. - std::string StartMacroStack = getMacroStack(Seq.getStartLoc(), Context); - std::string EndMacroStack = getMacroStack(Seq.getEndLoc(), Context); + std::string MacroStack = + data_collection::getMacroStack(Seq.getStartLoc(), Context); // First, check if ParentMacroStack is not empty which means we are currently // dealing with a parent statement which was expanded from a macro. @@ -404,8 +443,7 @@ size_t MinComplexityConstraint::calculateStmtComplexity( // macro expansion will only increase the total complexity by one. // Note: This is not the final complexity of this statement as we still // add the complexity of the child statements to the complexity value. - if (!ParentMacroStack.empty() && (StartMacroStack == ParentMacroStack && - EndMacroStack == ParentMacroStack)) { + if (!ParentMacroStack.empty() && MacroStack == ParentMacroStack) { Complexity = 0; } @@ -414,12 +452,16 @@ size_t MinComplexityConstraint::calculateStmtComplexity( if (Seq.holdsSequence()) { for (const Stmt *S : Seq) { Complexity += calculateStmtComplexity( - StmtSequence(S, Seq.getContainingDecl()), StartMacroStack); + StmtSequence(S, Seq.getContainingDecl()), Limit, MacroStack); + if (Complexity >= Limit) + return Limit; } } else { for (const Stmt *S : Seq.front()->children()) { Complexity += calculateStmtComplexity( - StmtSequence(S, Seq.getContainingDecl()), StartMacroStack); + StmtSequence(S, Seq.getContainingDecl()), Limit, MacroStack); + if (Complexity >= Limit) + return Limit; } } return Complexity; @@ -437,7 +479,8 @@ void MatchingVariablePatternConstraint::constrain( void CloneConstraint::splitCloneGroups( std::vector<CloneDetector::CloneGroup> &CloneGroups, - std::function<bool(const StmtSequence &, const StmtSequence &)> Compare) { + llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)> + Compare) { std::vector<CloneDetector::CloneGroup> Result; for (auto &HashGroup : CloneGroups) { // Contains all indexes in HashGroup that were already added to a diff --git a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp index be1262dc99108..4d57623e21611 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp @@ -47,12 +47,19 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix, return Name.startswith(Prefix); } +/// Returns true when the passed-in type is a CF-style reference-counted +/// type from the DiskArbitration framework. +static bool isDiskArbitrationAPIRefType(QualType T) { + return cocoa::isRefType(T, "DADisk") || + cocoa::isRefType(T, "DADissenter") || + cocoa::isRefType(T, "DASessionRef"); +} + bool coreFoundation::isCFObjectRef(QualType T) { return cocoa::isRefType(T, "CF") || // Core Foundation. cocoa::isRefType(T, "CG") || // Core Graphics. - cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. - cocoa::isRefType(T, "DADissenter") || - cocoa::isRefType(T, "DASessionRef"); + cocoa::isRefType(T, "CM") || // Core Media. + isDiskArbitrationAPIRefType(T); } diff --git a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp index f6fe78ac4619c..96edad0c3019f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp @@ -22,7 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" @@ -749,8 +749,7 @@ void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { // Special case for the std::move function. // TODO: Make this more specific. (Deferred) - if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" && - FunDecl->isInStdNamespace()) { + if (Call->isCallToStdMove()) { copyInfo(Call->getArg(0), Call, CS_Consumed); return; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp index cd73a62e6918c..4752c2b020aea 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp @@ -15,7 +15,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PostOrderIterator.h" diff --git a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp index 50a3aa20bd195..dfaed26564e6f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp @@ -505,9 +505,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); case LengthModifier::AsPtrDiff: - // FIXME: How to get the corresponding unsigned - // version of ptrdiff_t? - return ArgType(); + return ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: case LengthModifier::AsWide: @@ -654,6 +652,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: + case BuiltinType::Float16: case BuiltinType::Float128: // Various types which are non-trivial to correct. return false; diff --git a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp index 60724ea60b25a..7e72795a47f69 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp @@ -18,7 +18,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" diff --git a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp index 534225985460b..8398a4b82d5a3 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp @@ -251,8 +251,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); case LengthModifier::AsSizeT: - // FIXME: ssize_t. - return ArgType(); + return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); case LengthModifier::AsPtrDiff: return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); case LengthModifier::AsLongDouble: @@ -292,8 +291,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsSizeT: return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t")); case LengthModifier::AsPtrDiff: - // FIXME: Unsigned version of ptrdiff_t? - return ArgType(); + return ArgType::PtrTo( + ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); case LengthModifier::AsLongDouble: // GNU extension. return ArgType::PtrTo(Ctx.UnsignedLongLongTy); @@ -386,7 +385,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); case LengthModifier::AsSizeT: - return ArgType(); // FIXME: ssize_t + return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); case LengthModifier::AsPtrDiff: return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); case LengthModifier::AsLongDouble: diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp index 879a15c9c2a8e..6a9c9a04c55d1 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp @@ -26,7 +26,7 @@ #include "clang/Analysis/Analyses/ThreadSafetyLogical.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Basic/OperatorKinds.h" @@ -1735,8 +1735,23 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { CapExprSet AssertLocks; Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD); for (const auto &AssertLock : AssertLocks) - Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>( - AssertLock, LK_Shared, Loc, false, true), + Analyzer->addLock(FSet, + llvm::make_unique<LockableFactEntry>( + AssertLock, LK_Shared, Loc, false, true), + ClassifyDiagnostic(A)); + break; + } + + case attr::AssertCapability: { + AssertCapabilityAttr *A = cast<AssertCapabilityAttr>(At); + CapExprSet AssertLocks; + Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD); + for (const auto &AssertLock : AssertLocks) + Analyzer->addLock(FSet, + llvm::make_unique<LockableFactEntry>( + AssertLock, + A->isShared() ? LK_Shared : LK_Exclusive, Loc, + false, true), ClassifyDiagnostic(A)); break; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp index cbd5464c34d7c..99284f07b45b3 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -19,7 +19,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" @@ -319,11 +319,11 @@ static bool hasCppPointerType(const til::SExpr *E) { static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) { while (true) { D = D->getCanonicalDecl(); - CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), - E = D->end_overridden_methods(); - if (I == E) + auto OverriddenMethods = D->overridden_methods(); + if (OverriddenMethods.begin() == OverriddenMethods.end()) return D; // Method does not override anything - D = *I; // FIXME: this does not work with multiple inheritance. + // FIXME: this does not work with multiple inheritance. + D = *OverriddenMethods.begin(); } return nullptr; } @@ -505,6 +505,7 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO, case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true); case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx); case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx); + case BO_Cmp: return translateBinOp(til::BOP_Cmp, BO, Ctx); case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx); case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx); case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx); diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp index 83aa90435e2a5..cd7cdc69ab73a 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp @@ -38,6 +38,7 @@ StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { case BOP_Neq: return "!="; case BOP_Lt: return "<"; case BOP_Leq: return "<="; + case BOP_Cmp: return "<=>"; case BOP_LogicAnd: return "&&"; case BOP_LogicOr: return "||"; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index d5289fb9d4271..5f11d8a2a36b5 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -18,7 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/UninitializedValues.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" #include "llvm/ADT/DenseMap.h" @@ -440,16 +440,11 @@ static bool isPointerToConst(const QualType &QT) { void ClassifyRefs::VisitCallExpr(CallExpr *CE) { // Classify arguments to std::move as used. - if (CE->getNumArgs() == 1) { - if (FunctionDecl *FD = CE->getDirectCallee()) { - if (FD->isInStdNamespace() && FD->getIdentifier() && - FD->getIdentifier()->isStr("move")) { - // RecordTypes are handled in SemaDeclCXX.cpp. - if (!CE->getArg(0)->getType()->isRecordType()) - classify(CE->getArg(0), Use); - return; - } - } + if (CE->isCallToStdMove()) { + // RecordTypes are handled in SemaDeclCXX.cpp. + if (!CE->getArg(0)->getType()->isRecordType()) + classify(CE->getArg(0), Use); + return; } // If a value is passed by const pointer or by const reference to a function, diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp index 28695d649a867..ed7f87c9b95c7 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp @@ -69,9 +69,15 @@ bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, bool MSModeUnsupported = !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG; - bool OclCUnsupported = LangOpts.OpenCLVersion != 200 && - BuiltinInfo.Langs == OCLC20_LANG; + bool OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG; + bool OclC2Unsupported = LangOpts.OpenCLVersion != 200 && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES) == OCLC20_LANG; + bool OclCUnsupported = !LangOpts.OpenCL && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES); + bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && + !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported && !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported; } diff --git a/contrib/llvm/tools/clang/lib/Basic/Cuda.cpp b/contrib/llvm/tools/clang/lib/Basic/Cuda.cpp index 3264078b98f5f..58b99a3b58cbe 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Cuda.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Cuda.cpp @@ -16,6 +16,8 @@ const char *CudaVersionToString(CudaVersion V) { return "7.5"; case CudaVersion::CUDA_80: return "8.0"; + case CudaVersion::CUDA_90: + return "9.0"; } llvm_unreachable("invalid enum"); } @@ -48,6 +50,8 @@ const char *CudaArchToString(CudaArch A) { return "sm_61"; case CudaArch::SM_62: return "sm_62"; + case CudaArch::SM_70: + return "sm_70"; } llvm_unreachable("invalid enum"); } @@ -66,6 +70,7 @@ CudaArch StringToCudaArch(llvm::StringRef S) { .Case("sm_60", CudaArch::SM_60) .Case("sm_61", CudaArch::SM_61) .Case("sm_62", CudaArch::SM_62) + .Case("sm_70", CudaArch::SM_70) .Default(CudaArch::UNKNOWN); } @@ -95,6 +100,8 @@ const char *CudaVirtualArchToString(CudaVirtualArch A) { return "compute_61"; case CudaVirtualArch::COMPUTE_62: return "compute_62"; + case CudaVirtualArch::COMPUTE_70: + return "compute_70"; } llvm_unreachable("invalid enum"); } @@ -112,6 +119,7 @@ CudaVirtualArch StringToCudaVirtualArch(llvm::StringRef S) { .Case("compute_60", CudaVirtualArch::COMPUTE_60) .Case("compute_61", CudaVirtualArch::COMPUTE_61) .Case("compute_62", CudaVirtualArch::COMPUTE_62) + .Case("compute_70", CudaVirtualArch::COMPUTE_70) .Default(CudaVirtualArch::UNKNOWN); } @@ -142,6 +150,8 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A) { return CudaVirtualArch::COMPUTE_61; case CudaArch::SM_62: return CudaVirtualArch::COMPUTE_62; + case CudaArch::SM_70: + return CudaVirtualArch::COMPUTE_70; } llvm_unreachable("invalid enum"); } @@ -164,8 +174,22 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { case CudaArch::SM_61: case CudaArch::SM_62: return CudaVersion::CUDA_80; + case CudaArch::SM_70: + return CudaVersion::CUDA_90; } llvm_unreachable("invalid enum"); } +CudaVersion MaxVersionForCudaArch(CudaArch A) { + switch (A) { + case CudaArch::UNKNOWN: + return CudaVersion::UNKNOWN; + case CudaArch::SM_20: + case CudaArch::SM_21: + return CudaVersion::CUDA_80; + default: + return CudaVersion::LATEST; + } +} + } // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index c355445dc1e71..640b42c1ca2e6 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/PartialDiagnostic.h" @@ -363,7 +364,7 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor, SourceLocation Loc) { // Get all the diagnostics. SmallVector<diag::kind, 64> AllDiags; - Diags->getAllDiagnostics(Flavor, AllDiags); + DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags); // Set the mapping. for (diag::kind Diag : AllDiags) @@ -1050,3 +1051,5 @@ PartialDiagnostic::StorageAllocator::~StorageAllocator() { llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lam"); } + +char DiagnosticError::ID; diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index 0cdaf8e03643f..5c53f35aa68f0 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -43,7 +43,7 @@ struct StaticDiagInfoRec { unsigned SFINAE : 2; unsigned WarnNoWerror : 1; unsigned WarnShowInSystemHeader : 1; - unsigned Category : 5; + unsigned Category : 6; uint16_t OptionGroupIndex; @@ -68,6 +68,30 @@ struct StaticDiagInfoRec { } }; +#define STRINGIFY_NAME(NAME) #NAME +#define VALIDATE_DIAG_SIZE(NAME) \ + static_assert( \ + static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \ + static_cast<unsigned>(diag::DIAG_START_##NAME) + \ + static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \ + STRINGIFY_NAME( \ + DIAG_SIZE_##NAME) " is insufficient to contain all " \ + "diagnostics, it may need to be made larger in " \ + "DiagnosticIDs.h."); +VALIDATE_DIAG_SIZE(COMMON) +VALIDATE_DIAG_SIZE(DRIVER) +VALIDATE_DIAG_SIZE(FRONTEND) +VALIDATE_DIAG_SIZE(SERIALIZATION) +VALIDATE_DIAG_SIZE(LEX) +VALIDATE_DIAG_SIZE(PARSE) +VALIDATE_DIAG_SIZE(AST) +VALIDATE_DIAG_SIZE(COMMENT) +VALIDATE_DIAG_SIZE(SEMA) +VALIDATE_DIAG_SIZE(ANALYSIS) +VALIDATE_DIAG_SIZE(REFACTORING) +#undef VALIDATE_DIAG_SIZE +#undef STRINGIFY_NAME + } // namespace anonymous static const StaticDiagInfoRec StaticDiagInfo[] = { @@ -86,8 +110,10 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticParseKinds.inc" #include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" #undef DIAG }; @@ -96,18 +122,6 @@ static const unsigned StaticDiagInfoSize = llvm::array_lengthof(StaticDiagInfo); /// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, /// or null if the ID is invalid. static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { - // If assertions are enabled, verify that the StaticDiagInfo array is sorted. -#ifndef NDEBUG - static bool IsFirst = true; // So the check is only performed on first call. - if (IsFirst) { - assert(std::is_sorted(std::begin(StaticDiagInfo), - std::end(StaticDiagInfo)) && - "Diag ID conflict, the enums at the start of clang::diag (in " - "DiagnosticIDs.h) probably need to be increased"); - IsFirst = false; - } -#endif - // Out of bounds diag. Can't be in the table. using namespace diag; if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON) @@ -135,8 +149,10 @@ CATEGORY(LEX, SERIALIZATION) CATEGORY(PARSE, LEX) CATEGORY(AST, PARSE) CATEGORY(COMMENT, AST) -CATEGORY(SEMA, COMMENT) +CATEGORY(CROSSTU, COMMENT) +CATEGORY(SEMA, CROSSTU) CATEGORY(ANALYSIS, SEMA) +CATEGORY(REFACTORING, ANALYSIS) #undef CATEGORY // Avoid out of bounds reads. @@ -567,7 +583,7 @@ DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, } void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor, - SmallVectorImpl<diag::kind> &Diags) const { + SmallVectorImpl<diag::kind> &Diags) { for (unsigned i = 0; i != StaticDiagInfoSize; ++i) if (StaticDiagInfo[i].getFlavor() == Flavor) Diags.push_back(StaticDiagInfo[i].DiagID); diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp index 0c10b5f4d14cb..a3e226d6cc964 100644 --- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -408,7 +408,7 @@ bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { bool Changed = FixupRelativePath(Path); if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { - llvm::sys::fs::make_absolute(Path); + FS->makeAbsolute(Path); Changed = true; } diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp index 372e0c417fd44..2bed531ae3d79 100644 --- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -1,4 +1,4 @@ -//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===// +//===- IdentifierTable.cpp - Hash table for identifier lookup -------------===// // // The LLVM Compiler Infrastructure // @@ -12,17 +12,24 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/CharInfo.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" -#include "llvm/ADT/DenseMap.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> #include <cstdio> +#include <cstring> +#include <string> using namespace clang; @@ -46,27 +53,27 @@ IdentifierInfo::IdentifierInfo() { RevertedTokenID = false; OutOfDate = false; IsModulesImport = false; - FETokenInfo = nullptr; - Entry = nullptr; } //===----------------------------------------------------------------------===// // IdentifierTable Implementation //===----------------------------------------------------------------------===// -IdentifierIterator::~IdentifierIterator() { } +IdentifierIterator::~IdentifierIterator() = default; -IdentifierInfoLookup::~IdentifierInfoLookup() {} +IdentifierInfoLookup::~IdentifierInfoLookup() = default; namespace { - /// \brief A simple identifier lookup iterator that represents an - /// empty sequence of identifiers. - class EmptyLookupIterator : public IdentifierIterator - { - public: - StringRef Next() override { return StringRef(); } - }; -} + +/// \brief A simple identifier lookup iterator that represents an +/// empty sequence of identifiers. +class EmptyLookupIterator : public IdentifierIterator +{ +public: + StringRef Next() override { return StringRef(); } +}; + +} // namespace IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { return new EmptyLookupIterator(); @@ -76,11 +83,9 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, IdentifierInfoLookup* externalLookup) : HashTable(8192), // Start with space for 8K identifiers. ExternalLookup(externalLookup) { - // Populate the identifier table with info about keywords for the current // language. AddKeywords(LangOpts); - // Add the '_experimental_modules_import' contextual keyword. get("import").setModulesImport(true); @@ -92,6 +97,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { + enum { KEYC99 = 0x1, KEYCXX = 0x2, @@ -114,7 +120,9 @@ namespace { KEYZVECTOR = 0x40000, KEYCOROUTINES = 0x80000, KEYMODULES = 0x100000, - KEYALL = (0x1fffff & ~KEYNOMS18 & + KEYCXX2A = 0x200000, + KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX2A, + KEYALL = (0x3fffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. }; @@ -125,7 +133,8 @@ namespace { KS_Enabled, // Enabled KS_Future // Is a keyword in future standard }; -} + +} // namespace /// \brief Translates flags as specified in TokenKinds.def into keyword status /// in the given language standard. @@ -134,6 +143,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (Flags == KEYALL) return KS_Enabled; if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled; if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled; + if (LangOpts.CPlusPlus2a && (Flags & KEYCXX2A)) return KS_Enabled; if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled; if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension; if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension; @@ -152,7 +162,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; if (LangOpts.CoroutinesTS && (Flags & KEYCOROUTINES)) return KS_Enabled; if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled; - if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future; + if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future; return KS_Disabled; } @@ -264,6 +274,7 @@ bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const { LangOptions LangOptsNoCPP = LangOpts; LangOptsNoCPP.CPlusPlus = false; LangOptsNoCPP.CPlusPlus11 = false; + LangOptsNoCPP.CPlusPlus2a = false; return !isKeyword(LangOptsNoCPP); } @@ -362,6 +373,7 @@ unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) { } namespace clang { + /// MultiKeywordSelector - One of these variable length records is kept for each /// selector containing more than one keyword. We use a folding set /// to unique aggregate names (keyword selectors in ObjC parlance). Access to @@ -371,6 +383,7 @@ class MultiKeywordSelector MultiKeywordSelector(unsigned nKeys) { ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; } + public: // Constructor for keyword selectors. MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { @@ -388,28 +401,34 @@ public: unsigned getNumArgs() const { return ExtraKindOrNumArgs - NUM_EXTRA_KINDS; } - typedef IdentifierInfo *const *keyword_iterator; + using keyword_iterator = IdentifierInfo *const *; + keyword_iterator keyword_begin() const { return reinterpret_cast<keyword_iterator>(this+1); } + keyword_iterator keyword_end() const { return keyword_begin()+getNumArgs(); } + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); return keyword_begin()[i]; } + static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, unsigned NumArgs) { ID.AddInteger(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i]); } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, keyword_begin(), getNumArgs()); } }; -} // end namespace clang. + +} // namespace clang. unsigned Selector::getNumArgs() const { unsigned IIF = getIdentifierInfoFlag(); @@ -427,6 +446,7 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { assert(argIndex == 0 && "illegal keyword index"); return getAsIdentifierInfo(); } + // We point to a MultiKeywordSelector. MultiKeywordSelector *SI = getMultiKeywordSelector(); return SI->getIdentifierInfoForSlot(argIndex); @@ -588,11 +608,13 @@ ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) { } namespace { - struct SelectorTableImpl { - llvm::FoldingSet<MultiKeywordSelector> Table; - llvm::BumpPtrAllocator Allocator; - }; -} // end anonymous namespace. + +struct SelectorTableImpl { + llvm::FoldingSet<MultiKeywordSelector> Table; + llvm::BumpPtrAllocator Allocator; +}; + +} // namespace static SelectorTableImpl &getSelectorTableImpl(void *P) { return *static_cast<SelectorTableImpl*>(P); diff --git a/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp index 1d96afd476ef4..7124184865c66 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Module.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Module.cpp @@ -1,4 +1,4 @@ -//===--- Module.cpp - Describe a module -----------------------------------===// +//===- Module.cpp - Describe a module -------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -16,23 +16,33 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <functional> +#include <string> +#include <utility> +#include <vector> using namespace clang; Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, bool IsFramework, bool IsExplicit, unsigned VisibilityID) - : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(), - Umbrella(), ASTFile(nullptr), VisibilityID(VisibilityID), - IsMissingRequirement(false), HasIncompatibleModuleFile(false), - IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), - IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), - IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), + VisibilityID(VisibilityID), IsMissingRequirement(false), + HasIncompatibleModuleFile(false), IsAvailable(true), + IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), + IsSystem(false), IsExternC(false), IsInferred(false), + InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), ConfigMacrosExhaustive(false), NoUndeclaredIncludes(false), NameVisibility(Hidden) { if (Parent) { @@ -130,6 +140,7 @@ static StringRef getModuleNameFromComponent( const std::pair<std::string, SourceLocation> &IdComponent) { return IdComponent.first; } + static StringRef getModuleNameFromComponent(StringRef R) { return R; } template<typename InputIter> @@ -440,6 +451,11 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { } } + if (!ExportAsModule.empty()) { + OS.indent(Indent + 2); + OS << "export_as" << ExportAsModule << "\n"; + } + for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end(); MI != MIEnd; ++MI) // Print inferred subframework modules so that we don't need to re-infer diff --git a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp index 050c0cc466db8..09c919e2b0725 100644 --- a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp @@ -139,6 +139,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: @@ -279,6 +280,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: @@ -791,7 +793,7 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_target || DKind == OMPD_target_parallel || - DKind == OMPD_target_parallel_for || + DKind == OMPD_target_parallel_for || DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd || DKind == OMPD_target_teams || DKind == OMPD_target_teams_distribute || DKind == OMPD_target_teams_distribute_parallel_for || @@ -827,7 +829,8 @@ bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) { DKind == OMPD_teams_distribute_simd || DKind == OMPD_teams_distribute_parallel_for_simd || DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd; + DKind == OMPD_target_teams_distribute_simd || + DKind == OMPD_target_parallel_for_simd; } bool clang::isOpenMPNestingDistributeDirective(OpenMPDirectiveKind Kind) { @@ -851,8 +854,8 @@ bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) { bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { return Kind == OMPC_private || Kind == OMPC_firstprivate || Kind == OMPC_lastprivate || Kind == OMPC_linear || - Kind == OMPC_reduction || - Kind == OMPC_task_reduction; // TODO add next clauses like 'reduction'. + Kind == OMPC_reduction || Kind == OMPC_task_reduction || + Kind == OMPC_in_reduction; // TODO add next clauses like 'reduction'. } bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) { @@ -882,13 +885,45 @@ void clang::getOpenMPCaptureRegions( case OMPD_parallel_for_simd: case OMPD_parallel_sections: case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: CaptureRegions.push_back(OMPD_parallel); break; case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: CaptureRegions.push_back(OMPD_target); CaptureRegions.push_back(OMPD_teams); break; case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + CaptureRegions.push_back(OMPD_teams); + break; + case OMPD_target: + case OMPD_target_simd: + CaptureRegions.push_back(OMPD_target); + break; + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + CaptureRegions.push_back(OMPD_teams); + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + CaptureRegions.push_back(OMPD_target); + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_task: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + CaptureRegions.push_back(OMPD_task); + break; + case OMPD_taskloop: + case OMPD_taskloop_simd: + CaptureRegions.push_back(OMPD_taskloop); + break; case OMPD_simd: case OMPD_for: case OMPD_for_simd: @@ -902,28 +937,10 @@ void clang::getOpenMPCaptureRegions( case OMPD_ordered: case OMPD_atomic: case OMPD_target_data: - case OMPD_target: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: - case OMPD_target_simd: - case OMPD_task: - case OMPD_taskloop: - case OMPD_taskloop_simd: - case OMPD_distribute_parallel_for_simd: case OMPD_distribute_simd: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: - CaptureRegions.push_back(DKind); - break; - case OMPD_target_parallel: - CaptureRegions.push_back(OMPD_target); - CaptureRegions.push_back(OMPD_parallel); + CaptureRegions.push_back(OMPD_unknown); break; case OMPD_threadprivate: case OMPD_taskyield: @@ -932,13 +949,10 @@ void clang::getOpenMPCaptureRegions( case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: - case OMPD_target_enter_data: - case OMPD_target_exit_data: case OMPD_declare_reduction: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: - case OMPD_target_update: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); diff --git a/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp b/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp index 384d23c38af5c..3743b6ad5fefc 100644 --- a/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp @@ -63,6 +63,7 @@ prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, case tok::lessequal: case tok::less: case tok::greaterequal: return prec::Relational; + case tok::spaceship: return prec::Spaceship; case tok::lessless: return prec::Shift; case tok::plus: case tok::minus: return prec::Additive; diff --git a/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp index de78c94bc1956..199ded1f317a4 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp @@ -17,30 +17,35 @@ using namespace clang; SanitizerBlacklist::SanitizerBlacklist( const std::vector<std::string> &BlacklistPaths, SourceManager &SM) - : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} + : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} -bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName, +bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask, + StringRef GlobalName, StringRef Category) const { - return SCL->inSection("global", GlobalName, Category); + return SSCL->inSection(Mask, "global", GlobalName, Category); } -bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName, +bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask, + StringRef MangledTypeName, StringRef Category) const { - return SCL->inSection("type", MangledTypeName, Category); + return SSCL->inSection(Mask, "type", MangledTypeName, Category); } -bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const { - return SCL->inSection("fun", FunctionName); +bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask, + StringRef FunctionName) const { + return SSCL->inSection(Mask, "fun", FunctionName); } -bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName, +bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask, + StringRef FileName, StringRef Category) const { - return SCL->inSection("src", FileName, Category); + return SSCL->inSection(Mask, "src", FileName, Category); } -bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc, +bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask, + SourceLocation Loc, StringRef Category) const { return Loc.isValid() && - isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category); + isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category); } diff --git a/contrib/llvm/tools/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/contrib/llvm/tools/clang/lib/Basic/SanitizerSpecialCaseList.cpp new file mode 100644 index 0000000000000..ee8feecbce655 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -0,0 +1,64 @@ +//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/SanitizerSpecialCaseList.h" + +using namespace clang; + +std::unique_ptr<SanitizerSpecialCaseList> +SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, + std::string &Error) { + std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL( + new SanitizerSpecialCaseList()); + if (SSCL->createInternal(Paths, Error)) { + SSCL->createSanitizerSections(); + return SSCL; + } + return nullptr; +} + +std::unique_ptr<SanitizerSpecialCaseList> +SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) { + std::string Error; + if (auto SSCL = create(Paths, Error)) + return SSCL; + llvm::report_fatal_error(Error); +} + +void SanitizerSpecialCaseList::createSanitizerSections() { + for (auto &S : Sections) { + SanitizerMask Mask = 0; + +#define SANITIZER(NAME, ID) \ + if (S.SectionMatcher->match(NAME)) \ + Mask |= SanitizerKind::ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID) + +#include "clang/Basic/Sanitizers.def" +#undef SANITIZER +#undef SANITIZER_GROUP + + SanitizerSections.emplace_back(Mask, S.Entries); + } +} + +bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix, + StringRef Query, + StringRef Category) const { + for (auto &S : SanitizerSections) + if ((S.Mask & Mask) && + SpecialCaseList::inSectionBlame(S.Entries, Prefix, Query, Category)) + return true; + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index f0b53b4e48a54..e664879639f3c 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -1,4 +1,4 @@ -//===--- SourceManager.cpp - Track and cache source files -----------------===// +//===- SourceManager.cpp - Track and cache source files -------------------===// // // The LLVM Compiler Infrastructure // @@ -14,17 +14,33 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManagerInternals.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> -#include <cstring> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <tuple> +#include <utility> +#include <vector> using namespace clang; using namespace SrcMgr; @@ -222,7 +238,6 @@ void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, IncludeOffset)); } - /// FindNearestLineEntry - Find the line entry nearest to FID that is before /// it. If there is no line entry before Offset in FID, return null. const LineEntry *LineTableInfo::FindNearestLineEntry(FileID FID, @@ -250,7 +265,6 @@ void LineTableInfo::AddEntry(FileID FID, } /// getLineTableFilenameID - Return the uniqued ID for the specified filename. -/// unsigned SourceManager::getLineTableFilenameID(StringRef Name) { return getLineTable().getLineTableFilenameID(Name); } @@ -298,10 +312,7 @@ LineTableInfo &SourceManager::getLineTable() { SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, bool UserFilesAreVolatile) - : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), - UserFilesAreVolatile(UserFilesAreVolatile), FilesAreTransient(false), - ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0), - NumBinaryProbes(0) { + : Diag(Diag), FileMgr(FileMgr), UserFilesAreVolatile(UserFilesAreVolatile) { clearIDTables(); Diag.setSourceManager(this); } @@ -342,7 +353,7 @@ void SourceManager::clearIDTables() { // Use up FileID #0 as an invalid expansion. NextLocalOffset = 0; CurrentLoadedOffset = MaxLoadedOffset; - createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1); + createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1); } void SourceManager::initializeForReplay(const SourceManager &Old) { @@ -408,16 +419,16 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt, return Entry; } - -/// createMemBufferContentCache - Create a new ContentCache for the specified -/// memory buffer. This does no caching. -const ContentCache *SourceManager::createMemBufferContentCache( - std::unique_ptr<llvm::MemoryBuffer> Buffer) { +/// Create a new ContentCache for the specified memory buffer. +/// This does no caching. +const ContentCache * +SourceManager::createMemBufferContentCache(llvm::MemoryBuffer *Buffer, + bool DoNotFree) { // Add a new ContentCache to the MemBufferInfos list and return it. ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(); new (Entry) ContentCache(); MemBufferInfos.push_back(Entry); - Entry->setBuffer(std::move(Buffer)); + Entry->replaceBuffer(Buffer, DoNotFree); return Entry; } @@ -715,7 +726,7 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const { // Find the FileID that contains this. "I" is an iterator that points to a // FileID whose offset is known to be larger than SLocOffset. unsigned NumProbes = 0; - while (1) { + while (true) { --I; if (I->getOffset() <= SLocOffset) { FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin())); @@ -739,7 +750,7 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const { // SLocOffset. unsigned LessIndex = 0; NumProbes = 0; - while (1) { + while (true) { bool Invalid = false; unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; unsigned MidOffset = getLocalSLocEntry(MiddleIndex, &Invalid).getOffset(); @@ -816,7 +827,7 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const { unsigned GreaterIndex = I; unsigned LessIndex = LoadedSLocEntryTable.size(); NumProbes = 0; - while (1) { + while (true) { ++NumProbes; unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex; const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex); @@ -934,7 +945,6 @@ SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{ return Loc.getLocWithOffset(LocInfo.second); } - /// getImmediateExpansionRange - Loc is required to be an expansion location. /// Return the start/end of the expansion information. std::pair<SourceLocation,SourceLocation> @@ -1054,7 +1064,6 @@ bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc, return true; } - //===----------------------------------------------------------------------===// // Queries about the code at a SourceLocation. //===----------------------------------------------------------------------===// @@ -1083,7 +1092,6 @@ const char *SourceManager::getCharacterData(SourceLocation SL, return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); } - /// getColumnNumber - Return the column # for the specified file position. /// this is significantly cheaper to compute than the line number. unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, @@ -1188,7 +1196,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); unsigned Offs = 0; - while (1) { + while (true) { // Skip over the contents of the line. const unsigned char *NextBuf = (const unsigned char *)Buf; @@ -1418,7 +1426,6 @@ StringRef SourceManager::getBufferName(SourceLocation Loc, return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier(); } - /// getPresumedLoc - This method returns the "presumed" location of a /// SourceLocation specifies. A "presumed location" can be modified by \#line /// or GNU line marker directives. This provides a view on the data that a @@ -1766,7 +1773,7 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache, MacroArgsCache.insert(std::make_pair(0, SourceLocation())); int ID = FID.ID; - while (1) { + while (true) { ++ID; // Stop if there are no more FileIDs to check. if (ID > 0) { @@ -1829,7 +1836,7 @@ void SourceManager::associateFileChunkWithMacroArgExp( FileID SpellFID; // Current FileID in the spelling range. unsigned SpellRelativeOffs; std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc); - while (1) { + while (true) { const SLocEntry &Entry = getSLocEntry(SpellFID); unsigned SpellFIDBeginOffs = Entry.getOffset(); unsigned SpellFIDSize = getFileIDSize(SpellFID); @@ -1856,7 +1863,6 @@ void SourceManager::associateFileChunkWithMacroArgExp( ++SpellFID.ID; SpellRelativeOffs = 0; } - } assert(SpellLoc.isFileID()); @@ -1936,8 +1942,8 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const { // Uses IncludedLocMap to retrieve/cache the decomposed loc. - typedef std::pair<FileID, unsigned> DecompTy; - typedef llvm::DenseMap<FileID, DecompTy> MapTy; + using DecompTy = std::pair<FileID, unsigned>; + using MapTy = llvm::DenseMap<FileID, DecompTy>; std::pair<MapTy::iterator, bool> InsertOp = IncludedLocMap.insert(std::make_pair(FID, DecompTy())); DecompTy &DecompLoc = InsertOp.first->second; @@ -2084,7 +2090,7 @@ std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit( // of the other looking for a match. // We use a map from FileID to Offset to store the chain. Easier than writing // a custom set hash info that only depends on the first part of a pair. - typedef llvm::SmallDenseMap<FileID, unsigned, 16> LocSet; + using LocSet = llvm::SmallDenseMap<FileID, unsigned, 16>; LocSet LChain; do { LChain.insert(LOffs); @@ -2196,7 +2202,7 @@ LLVM_DUMP_METHOD void SourceManager::dump() const { } } -ExternalSLocEntrySource::~ExternalSLocEntrySource() { } +ExternalSLocEntrySource::~ExternalSLocEntrySource() = default; /// Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp index 4bcebadf458f6..ddd292c1b7435 100644 --- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -18,10 +18,11 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetParser.h" #include <cstdlib> using namespace clang; -static const LangAS::Map DefaultAddrSpaceMap = { 0 }; +static const LangASMap DefaultAddrSpaceMap = {0}; // TargetInfo Constructor. TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { @@ -29,6 +30,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { // SPARC. These should be overridden by concrete targets as needed. BigEndian = !T.isLittleEndian(); TLSSupported = true; + VLASupported = true; NoAsmVariants = false; HasFloat128 = false; PointerWidth = PointerAlign = 32; @@ -42,7 +44,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { // From the glibc documentation, on GNU systems, malloc guarantees 16-byte // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html - if (T.isGNUEnvironment()) + if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment()) NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0; else NewAlign = 0; // Infer from basic type alignment. @@ -289,8 +291,15 @@ bool TargetInfo::isTypeSigned(IntType T) { void TargetInfo::adjust(LangOptions &Opts) { if (Opts.NoBitFieldTypeAlign) UseBitFieldTypeAlignment = false; - if (Opts.ShortWChar) - WCharType = UnsignedShort; + + switch (Opts.WCharSize) { + default: llvm_unreachable("invalid wchar_t width"); + case 0: break; + case 1: WCharType = Opts.WCharIsSigned ? SignedChar : UnsignedChar; break; + case 2: WCharType = Opts.WCharIsSigned ? SignedShort : UnsignedShort; break; + case 4: WCharType = Opts.WCharIsSigned ? SignedInt : UnsignedInt; break; + } + if (Opts.AlignDouble) { DoubleAlign = LongLongAlign = 64; LongDoubleAlign = 64; @@ -347,6 +356,20 @@ bool TargetInfo::initFeatureMap( return true; } +LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const { + switch (TK) { + case OCLTK_Image: + case OCLTK_Pipe: + return LangAS::opencl_global; + + case OCLTK_Sampler: + return LangAS::opencl_constant; + + default: + return LangAS::Default; + } +} + //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index b33ab135816d3..7deebc06c3efa 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -12,30 +12,37 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Builtins.h" -#include "clang/Basic/Cuda.h" +#include "Targets.h" + +#include "Targets/AArch64.h" +#include "Targets/AMDGPU.h" +#include "Targets/ARM.h" +#include "Targets/AVR.h" +#include "Targets/BPF.h" +#include "Targets/Hexagon.h" +#include "Targets/Lanai.h" +#include "Targets/Le64.h" +#include "Targets/MSP430.h" +#include "Targets/Mips.h" +#include "Targets/NVPTX.h" +#include "Targets/Nios2.h" +#include "Targets/OSTargets.h" +#include "Targets/PNaCl.h" +#include "Targets/PPC.h" +#include "Targets/SPIR.h" +#include "Targets/Sparc.h" +#include "Targets/SystemZ.h" +#include "Targets/TCE.h" +#include "Targets/WebAssembly.h" +#include "Targets/X86.h" +#include "Targets/XCore.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/MacroBuilder.h" -#include "clang/Basic/TargetBuiltins.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/Basic/Version.h" -#include "clang/Frontend/CodeGenOptions.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/TargetParser.h" -#include <algorithm> -#include <memory> using namespace clang; +namespace clang { +namespace targets { //===----------------------------------------------------------------------===// // Common code shared among targets. //===----------------------------------------------------------------------===// @@ -43,8 +50,8 @@ using namespace clang; /// DefineStd - Define a macro name and standard variants. For example if /// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" /// when in GNU mode. -static void DefineStd(MacroBuilder &Builder, StringRef MacroName, - const LangOptions &Opts) { +void DefineStd(MacroBuilder &Builder, StringRef MacroName, + const LangOptions &Opts) { assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier @@ -59,4636 +66,14 @@ static void DefineStd(MacroBuilder &Builder, StringRef MacroName, Builder.defineMacro("__" + MacroName + "__"); } -static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, - bool Tuning = true) { +void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning) { Builder.defineMacro("__" + CPUName); Builder.defineMacro("__" + CPUName + "__"); if (Tuning) Builder.defineMacro("__tune_" + CPUName + "__"); } -static TargetInfo *AllocateTarget(const llvm::Triple &Triple, - const TargetOptions &Opts); - -//===----------------------------------------------------------------------===// -// Defines specific to certain operating systems. -//===----------------------------------------------------------------------===// - -namespace { -template<typename TgtInfo> -class OSTargetInfo : public TgtInfo { -protected: - virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const=0; -public: - OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TgtInfo(Triple, Opts) {} - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - TgtInfo::getTargetDefines(Opts, Builder); - getOSDefines(Opts, TgtInfo::getTriple(), Builder); - } - -}; - -// CloudABI Target -template <typename Target> -class CloudABITargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - Builder.defineMacro("__CloudABI__"); - Builder.defineMacro("__ELF__"); - - // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. - Builder.defineMacro("__STDC_ISO_10646__", "201206L"); - Builder.defineMacro("__STDC_UTF_16__"); - Builder.defineMacro("__STDC_UTF_32__"); - } - -public: - CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) {} -}; - -// Ananas target -template<typename Target> -class AnanasTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // Ananas defines - Builder.defineMacro("__Ananas__"); - Builder.defineMacro("__ELF__"); - } -public: - AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) {} -}; - -static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, - const llvm::Triple &Triple, - StringRef &PlatformName, - VersionTuple &PlatformMinVersion) { - Builder.defineMacro("__APPLE_CC__", "6000"); - Builder.defineMacro("__APPLE__"); - Builder.defineMacro("__STDC_NO_THREADS__"); - Builder.defineMacro("OBJC_NEW_PROPERTIES"); - // AddressSanitizer doesn't play well with source fortification, which is on - // by default on Darwin. - if (Opts.Sanitize.has(SanitizerKind::Address)) - Builder.defineMacro("_FORTIFY_SOURCE", "0"); - - // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. - if (!Opts.ObjC1) { - // __weak is always defined, for use in blocks and with objc pointers. - Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); - Builder.defineMacro("__strong", ""); - Builder.defineMacro("__unsafe_unretained", ""); - } - - if (Opts.Static) - Builder.defineMacro("__STATIC__"); - else - Builder.defineMacro("__DYNAMIC__"); - - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - - // Get the platform type and version number from the triple. - unsigned Maj, Min, Rev; - if (Triple.isMacOSX()) { - Triple.getMacOSXVersion(Maj, Min, Rev); - PlatformName = "macos"; - } else { - Triple.getOSVersion(Maj, Min, Rev); - PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); - } - - // If -target arch-pc-win32-macho option specified, we're - // generating code for Win32 ABI. No need to emit - // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. - if (PlatformName == "win32") { - PlatformMinVersion = VersionTuple(Maj, Min, Rev); - return; - } - - // Set the appropriate OS version define. - if (Triple.isiOS()) { - assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); - char Str[7]; - if (Maj < 10) { - Str[0] = '0' + Maj; - Str[1] = '0' + (Min / 10); - Str[2] = '0' + (Min % 10); - Str[3] = '0' + (Rev / 10); - Str[4] = '0' + (Rev % 10); - Str[5] = '\0'; - } else { - // Handle versions >= 10. - Str[0] = '0' + (Maj / 10); - Str[1] = '0' + (Maj % 10); - Str[2] = '0' + (Min / 10); - Str[3] = '0' + (Min % 10); - Str[4] = '0' + (Rev / 10); - Str[5] = '0' + (Rev % 10); - Str[6] = '\0'; - } - if (Triple.isTvOS()) - Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); - else - Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", - Str); - - } else if (Triple.isWatchOS()) { - assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); - char Str[6]; - Str[0] = '0' + Maj; - Str[1] = '0' + (Min / 10); - Str[2] = '0' + (Min % 10); - Str[3] = '0' + (Rev / 10); - Str[4] = '0' + (Rev % 10); - Str[5] = '\0'; - Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); - } else if (Triple.isMacOSX()) { - // Note that the Driver allows versions which aren't representable in the - // define (because we only get a single digit for the minor and micro - // revision numbers). So, we limit them to the maximum representable - // version. - assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); - char Str[7]; - if (Maj < 10 || (Maj == 10 && Min < 10)) { - Str[0] = '0' + (Maj / 10); - Str[1] = '0' + (Maj % 10); - Str[2] = '0' + std::min(Min, 9U); - Str[3] = '0' + std::min(Rev, 9U); - Str[4] = '\0'; - } else { - // Handle versions > 10.9. - Str[0] = '0' + (Maj / 10); - Str[1] = '0' + (Maj % 10); - Str[2] = '0' + (Min / 10); - Str[3] = '0' + (Min % 10); - Str[4] = '0' + (Rev / 10); - Str[5] = '0' + (Rev % 10); - Str[6] = '\0'; - } - Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); - } - - // Tell users about the kernel if there is one. - if (Triple.isOSDarwin()) - Builder.defineMacro("__MACH__"); - - // The Watch ABI uses Dwarf EH. - if(Triple.isWatchABI()) - Builder.defineMacro("__ARM_DWARF_EH__"); - - PlatformMinVersion = VersionTuple(Maj, Min, Rev); -} - -template<typename Target> -class DarwinTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - getDarwinDefines(Builder, Opts, Triple, this->PlatformName, - this->PlatformMinVersion); - } - -public: - DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - // By default, no TLS, and we whitelist permitted architecture/OS - // combinations. - this->TLSSupported = false; - - if (Triple.isMacOSX()) - this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7); - else if (Triple.isiOS()) { - // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards. - if (Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::aarch64) - this->TLSSupported = !Triple.isOSVersionLT(8); - else if (Triple.getArch() == llvm::Triple::x86 || - Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb) - this->TLSSupported = !Triple.isOSVersionLT(9); - } else if (Triple.isWatchOS()) - this->TLSSupported = !Triple.isOSVersionLT(2); - - this->MCountName = "\01mcount"; - } - - std::string isValidSectionSpecifier(StringRef SR) const override { - // Let MCSectionMachO validate this. - StringRef Segment, Section; - unsigned TAA, StubSize; - bool HasTAA; - return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, - TAA, HasTAA, StubSize); - } - - const char *getStaticInitSectionSpecifier() const override { - // FIXME: We should return 0 when building kexts. - return "__TEXT,__StaticInit,regular,pure_instructions"; - } - - /// Darwin does not support protected visibility. Darwin's "default" - /// is very similar to ELF's "protected"; Darwin requires a "weak" - /// attribute on declarations that can be dynamically replaced. - bool hasProtectedVisibility() const override { - return false; - } - - unsigned getExnObjectAlignment() const override { - // The alignment of an exception object is 8-bytes for darwin since - // libc++abi doesn't declare _Unwind_Exception with __attribute__((aligned)) - // and therefore doesn't guarantee 16-byte alignment. - return 64; - } -}; - - -// DragonFlyBSD Target -template<typename Target> -class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // DragonFly defines; list based off of gcc output - Builder.defineMacro("__DragonFly__"); - Builder.defineMacro("__DragonFly_cc_version", "100001"); - Builder.defineMacro("__ELF__"); - Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); - Builder.defineMacro("__tune_i386__"); - DefineStd(Builder, "unix", Opts); - } -public: - DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - switch (Triple.getArch()) { - default: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - this->MCountName = ".mcount"; - break; - } - } -}; - -#ifndef FREEBSD_CC_VERSION -#define FREEBSD_CC_VERSION 0U -#endif - -// FreeBSD Target -template<typename Target> -class FreeBSDTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // FreeBSD defines; list based off of gcc output - - unsigned Release = Triple.getOSMajorVersion(); - if (Release == 0U) - Release = 8U; - unsigned CCVersion = FREEBSD_CC_VERSION; - if (CCVersion == 0U) - CCVersion = Release * 100000U + 1U; - - Builder.defineMacro("__FreeBSD__", Twine(Release)); - Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion)); - Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - - // On FreeBSD, wchar_t contains the number of the code point as - // used by the character set of the locale. These character sets are - // not necessarily a superset of ASCII. - // - // FIXME: This is wrong; the macro refers to the numerical values - // of wchar_t *literals*, which are not locale-dependent. However, - // FreeBSD systems apparently depend on us getting this wrong, and - // setting this to 1 is conforming even if all the basic source - // character literals have the same encoding as char and wchar_t. - Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1"); - } -public: - FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - switch (Triple.getArch()) { - default: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - this->MCountName = ".mcount"; - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - this->MCountName = "_mcount"; - break; - case llvm::Triple::arm: - this->MCountName = "__mcount"; - break; - } - } -}; - -// GNU/kFreeBSD Target -template<typename Target> -class KFreeBSDTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // GNU/kFreeBSD defines; list based off of gcc output - - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__FreeBSD_kernel__"); - Builder.defineMacro("__GLIBC__"); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - } -public: - KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) {} -}; - -// Haiku Target -template<typename Target> -class HaikuTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // Haiku defines; list based off of gcc output - Builder.defineMacro("__HAIKU__"); - Builder.defineMacro("__ELF__"); - DefineStd(Builder, "unix", Opts); - } -public: - HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->SizeType = TargetInfo::UnsignedLong; - this->IntPtrType = TargetInfo::SignedLong; - this->PtrDiffType = TargetInfo::SignedLong; - this->ProcessIDType = TargetInfo::SignedLong; - this->TLSSupported = false; - - } -}; - -// Minix Target -template<typename Target> -class MinixTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // Minix defines - - Builder.defineMacro("__minix", "3"); - Builder.defineMacro("_EM_WSIZE", "4"); - Builder.defineMacro("_EM_PSIZE", "4"); - Builder.defineMacro("_EM_SSIZE", "2"); - Builder.defineMacro("_EM_LSIZE", "4"); - Builder.defineMacro("_EM_FSIZE", "4"); - Builder.defineMacro("_EM_DSIZE", "8"); - Builder.defineMacro("__ELF__"); - DefineStd(Builder, "unix", Opts); - } -public: - MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) {} -}; - -// Linux target -template<typename Target> -class LinuxTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // Linux defines; list based off of gcc output - DefineStd(Builder, "unix", Opts); - DefineStd(Builder, "linux", Opts); - Builder.defineMacro("__gnu_linux__"); - Builder.defineMacro("__ELF__"); - if (Triple.isAndroid()) { - Builder.defineMacro("__ANDROID__", "1"); - unsigned Maj, Min, Rev; - Triple.getEnvironmentVersion(Maj, Min, Rev); - this->PlatformName = "android"; - this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); - if (Maj) - Builder.defineMacro("__ANDROID_API__", Twine(Maj)); - } - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - if (this->HasFloat128) - Builder.defineMacro("__FLOAT128__"); - } -public: - LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->WIntType = TargetInfo::UnsignedInt; - - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - this->MCountName = "_mcount"; - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - case llvm::Triple::systemz: - this->HasFloat128 = true; - break; - } - } - - const char *getStaticInitSectionSpecifier() const override { - return ".text.startup"; - } -}; - -// NetBSD Target -template<typename Target> -class NetBSDTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // NetBSD defines; list based off of gcc output - Builder.defineMacro("__NetBSD__"); - Builder.defineMacro("__unix__"); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - Builder.defineMacro("__ARM_DWARF_EH__"); - break; - } - } -public: - NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->MCountName = "_mcount"; - } -}; - -// OpenBSD Target -template<typename Target> -class OpenBSDTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // OpenBSD defines; list based off of gcc output - - Builder.defineMacro("__OpenBSD__"); - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - if (this->HasFloat128) - Builder.defineMacro("__FLOAT128__"); - } -public: - OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - switch (Triple.getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - this->HasFloat128 = true; - // FALLTHROUGH - default: - this->MCountName = "__mcount"; - break; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::ppc: - case llvm::Triple::sparcv9: - this->MCountName = "_mcount"; - break; - } - } -}; - -// Bitrig Target -template<typename Target> -class BitrigTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // Bitrig defines; list based off of gcc output - - Builder.defineMacro("__Bitrig__"); - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - Builder.defineMacro("__ARM_DWARF_EH__"); - break; - } - } -public: - BitrigTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->MCountName = "__mcount"; - } -}; - -// PSP Target -template<typename Target> -class PSPTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // PSP defines; list based on the output of the pspdev gcc toolchain. - Builder.defineMacro("PSP"); - Builder.defineMacro("_PSP"); - Builder.defineMacro("__psp__"); - Builder.defineMacro("__ELF__"); - } -public: - PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {} -}; - -// PS3 PPU Target -template<typename Target> -class PS3PPUTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // PS3 PPU defines. - Builder.defineMacro("__PPC__"); - Builder.defineMacro("__PPU__"); - Builder.defineMacro("__CELLOS_LV2__"); - Builder.defineMacro("__ELF__"); - Builder.defineMacro("__LP32__"); - Builder.defineMacro("_ARCH_PPC64"); - Builder.defineMacro("__powerpc64__"); - } -public: - PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->LongWidth = this->LongAlign = 32; - this->PointerWidth = this->PointerAlign = 32; - this->IntMaxType = TargetInfo::SignedLongLong; - this->Int64Type = TargetInfo::SignedLongLong; - this->SizeType = TargetInfo::UnsignedInt; - this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64"); - } -}; - -template <typename Target> -class PS4OSTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - Builder.defineMacro("__FreeBSD__", "9"); - Builder.defineMacro("__FreeBSD_cc_version", "900001"); - Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - Builder.defineMacro("__ORBIS__"); - } -public: - PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->WCharType = this->UnsignedShort; - - // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). - this->MaxTLSAlign = 256; - - // On PS4, do not honor explicit bit field alignment, - // as in "__attribute__((aligned(2))) int b : 1;". - this->UseExplicitBitFieldAlignment = false; - - switch (Triple.getArch()) { - default: - case llvm::Triple::x86_64: - this->MCountName = ".mcount"; - break; - } - } -}; - -// Solaris target -template<typename Target> -class SolarisTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - DefineStd(Builder, "sun", Opts); - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - Builder.defineMacro("__svr4__"); - Builder.defineMacro("__SVR4"); - // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and - // newer, but to 500 for everything else. feature_test.h has a check to - // ensure that you are not using C99 with an old version of X/Open or C89 - // with a new version. - if (Opts.C99) - Builder.defineMacro("_XOPEN_SOURCE", "600"); - else - Builder.defineMacro("_XOPEN_SOURCE", "500"); - if (Opts.CPlusPlus) - Builder.defineMacro("__C99FEATURES__"); - Builder.defineMacro("_LARGEFILE_SOURCE"); - Builder.defineMacro("_LARGEFILE64_SOURCE"); - Builder.defineMacro("__EXTENSIONS__"); - Builder.defineMacro("_REENTRANT"); - } -public: - SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->WCharType = this->SignedInt; - // FIXME: WIntType should be SignedLong - } -}; - -// Windows target -template<typename Target> -class WindowsTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - Builder.defineMacro("_WIN32"); - } - void getVisualStudioDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - if (Opts.CPlusPlus) { - if (Opts.RTTIData) - Builder.defineMacro("_CPPRTTI"); - - if (Opts.CXXExceptions) - Builder.defineMacro("_CPPUNWIND"); - } - - if (Opts.Bool) - Builder.defineMacro("__BOOL_DEFINED"); - - if (!Opts.CharIsSigned) - Builder.defineMacro("_CHAR_UNSIGNED"); - - // FIXME: POSIXThreads isn't exactly the option this should be defined for, - // but it works for now. - if (Opts.POSIXThreads) - Builder.defineMacro("_MT"); - - if (Opts.MSCompatibilityVersion) { - Builder.defineMacro("_MSC_VER", - Twine(Opts.MSCompatibilityVersion / 100000)); - Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); - // FIXME We cannot encode the revision information into 32-bits - Builder.defineMacro("_MSC_BUILD", Twine(1)); - - if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) - Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); - - if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { - if (Opts.CPlusPlus1z) - Builder.defineMacro("_MSVC_LANG", "201403L"); - else if (Opts.CPlusPlus14) - Builder.defineMacro("_MSVC_LANG", "201402L"); - } - } - - if (Opts.MicrosoftExt) { - Builder.defineMacro("_MSC_EXTENSIONS"); - - if (Opts.CPlusPlus11) { - Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED"); - Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED"); - Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED"); - } - } - - Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); - } - -public: - WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) {} -}; - -template <typename Target> -class NaClTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - Builder.defineMacro("__native_client__"); - } - -public: - NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->LongAlign = 32; - this->LongWidth = 32; - this->PointerAlign = 32; - this->PointerWidth = 32; - this->IntMaxType = TargetInfo::SignedLongLong; - this->Int64Type = TargetInfo::SignedLongLong; - this->DoubleAlign = 64; - this->LongDoubleWidth = 64; - this->LongDoubleAlign = 64; - this->LongLongWidth = 64; - this->LongLongAlign = 64; - this->SizeType = TargetInfo::UnsignedInt; - this->PtrDiffType = TargetInfo::SignedInt; - this->IntPtrType = TargetInfo::SignedInt; - // RegParmMax is inherited from the underlying architecture. - this->LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - if (Triple.getArch() == llvm::Triple::arm) { - // Handled in ARM's setABI(). - } else if (Triple.getArch() == llvm::Triple::x86) { - this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128"); - } else if (Triple.getArch() == llvm::Triple::x86_64) { - this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128"); - } else if (Triple.getArch() == llvm::Triple::mipsel) { - // Handled on mips' setDataLayout. - } else { - assert(Triple.getArch() == llvm::Triple::le32); - this->resetDataLayout("e-p:32:32-i64:64"); - } - } -}; - -// Fuchsia Target -template<typename Target> -class FuchsiaTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - Builder.defineMacro("__Fuchsia__"); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - // Required by the libc++ locale support. - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - } -public: - FuchsiaTargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->MCountName = "__mcount"; - } -}; - -// WebAssembly target -template <typename Target> -class WebAssemblyOSTargetInfo : public OSTargetInfo<Target> { - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const final { - // A common platform macro. - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - // Follow g++ convention and predefine _GNU_SOURCE for C++. - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - } - - // As an optimization, group static init code together in a section. - const char *getStaticInitSectionSpecifier() const final { - return ".text.__startup"; - } - -public: - explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - this->MCountName = "__mcount"; - this->TheCXXABI.set(TargetCXXABI::WebAssembly); - } -}; - -//===----------------------------------------------------------------------===// -// Specific target implementations. -//===----------------------------------------------------------------------===// - -// PPC abstract base class -class PPCTargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - static const char * const GCCRegNames[]; - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - std::string CPU; - - // Target cpu features. - bool HasAltivec; - bool HasVSX; - bool HasP8Vector; - bool HasP8Crypto; - bool HasDirectMove; - bool HasQPX; - bool HasHTM; - bool HasBPERMD; - bool HasExtDiv; - bool HasP9Vector; - -protected: - std::string ABI; - -public: - PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), HasAltivec(false), HasVSX(false), HasP8Vector(false), - HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), - HasBPERMD(false), HasExtDiv(false), HasP9Vector(false) { - SuitableAlign = 128; - SimdDefaultAlign = 128; - LongDoubleWidth = LongDoubleAlign = 128; - LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); - } - - /// \brief Flags for architecture specific defines. - typedef enum { - ArchDefineNone = 0, - ArchDefineName = 1 << 0, // <name> is substituted for arch name. - ArchDefinePpcgr = 1 << 1, - ArchDefinePpcsq = 1 << 2, - ArchDefine440 = 1 << 3, - ArchDefine603 = 1 << 4, - ArchDefine604 = 1 << 5, - ArchDefinePwr4 = 1 << 6, - ArchDefinePwr5 = 1 << 7, - ArchDefinePwr5x = 1 << 8, - ArchDefinePwr6 = 1 << 9, - ArchDefinePwr6x = 1 << 10, - ArchDefinePwr7 = 1 << 11, - ArchDefinePwr8 = 1 << 12, - ArchDefinePwr9 = 1 << 13, - ArchDefineA2 = 1 << 14, - ArchDefineA2q = 1 << 15 - } ArchDefineTypes; - - // Set the language option for altivec based on our value. - void adjust(LangOptions &Opts) override { - if (HasAltivec) - Opts.AltiVec = 1; - TargetInfo::adjust(Opts); - } - - // Note: GCC recognizes the following additional cpus: - // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, - // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, - // titan, rs64. - bool setCPU(const std::string &Name) override { - bool CPUKnown = llvm::StringSwitch<bool>(Name) - .Case("generic", true) - .Case("440", true) - .Case("450", true) - .Case("601", true) - .Case("602", true) - .Case("603", true) - .Case("603e", true) - .Case("603ev", true) - .Case("604", true) - .Case("604e", true) - .Case("620", true) - .Case("630", true) - .Case("g3", true) - .Case("7400", true) - .Case("g4", true) - .Case("7450", true) - .Case("g4+", true) - .Case("750", true) - .Case("970", true) - .Case("g5", true) - .Case("a2", true) - .Case("a2q", true) - .Case("e500mc", true) - .Case("e5500", true) - .Case("power3", true) - .Case("pwr3", true) - .Case("power4", true) - .Case("pwr4", true) - .Case("power5", true) - .Case("pwr5", true) - .Case("power5x", true) - .Case("pwr5x", true) - .Case("power6", true) - .Case("pwr6", true) - .Case("power6x", true) - .Case("pwr6x", true) - .Case("power7", true) - .Case("pwr7", true) - .Case("power8", true) - .Case("pwr8", true) - .Case("power9", true) - .Case("pwr9", true) - .Case("powerpc", true) - .Case("ppc", true) - .Case("powerpc64", true) - .Case("ppc64", true) - .Case("powerpc64le", true) - .Case("ppc64le", true) - .Default(false); - - if (CPUKnown) - CPU = Name; - - return CPUKnown; - } - - - StringRef getABI() const override { return ABI; } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin); - } - - bool isCLZForZeroUndef() const override { return false; } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; - - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override; - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override; - bool hasFeature(StringRef Feature) const override; - void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, - bool Enabled) const override; - - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: return false; - case 'O': // Zero - break; - case 'b': // Base register - case 'f': // Floating point register - Info.setAllowsRegister(); - break; - // FIXME: The following are added to allow parsing. - // I just took a guess at what the actions should be. - // Also, is more specific checking needed? I.e. specific registers? - case 'd': // Floating point register (containing 64-bit value) - case 'v': // Altivec vector register - Info.setAllowsRegister(); - break; - case 'w': - switch (Name[1]) { - case 'd':// VSX vector register to hold vector double data - case 'f':// VSX vector register to hold vector float data - case 's':// VSX vector register to hold scalar float data - case 'a':// Any VSX register - case 'c':// An individual CR bit - break; - default: - return false; - } - Info.setAllowsRegister(); - Name++; // Skip over 'w'. - break; - case 'h': // `MQ', `CTR', or `LINK' register - case 'q': // `MQ' register - case 'c': // `CTR' register - case 'l': // `LINK' register - case 'x': // `CR' register (condition register) number 0 - case 'y': // `CR' register (condition register) - case 'z': // `XER[CA]' carry bit (part of the XER register) - Info.setAllowsRegister(); - break; - case 'I': // Signed 16-bit constant - case 'J': // Unsigned 16-bit constant shifted left 16 bits - // (use `L' instead for SImode constants) - case 'K': // Unsigned 16-bit constant - case 'L': // Signed 16-bit constant shifted left 16 bits - case 'M': // Constant larger than 31 - case 'N': // Exact power of 2 - case 'P': // Constant whose negation is a signed 16-bit constant - case 'G': // Floating point constant that can be loaded into a - // register with one instruction per word - case 'H': // Integer/Floating point constant that can be loaded - // into a register using three instructions - break; - case 'm': // Memory operand. Note that on PowerPC targets, m can - // include addresses that update the base register. It - // is therefore only safe to use `m' in an asm statement - // if that asm statement accesses the operand exactly once. - // The asm statement must also use `%U<opno>' as a - // placeholder for the "update" flag in the corresponding - // load or store instruction. For example: - // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); - // is correct but: - // asm ("st %1,%0" : "=m" (mem) : "r" (val)); - // is not. Use es rather than m if you don't want the base - // register to be updated. - case 'e': - if (Name[1] != 's') - return false; - // es: A "stable" memory operand; that is, one which does not - // include any automodification of the base register. Unlike - // `m', this constraint can be used in asm statements that - // might access the operand several times, or that might not - // access it at all. - Info.setAllowsMemory(); - Name++; // Skip over 'e'. - break; - case 'Q': // Memory operand that is an offset from a register (it is - // usually better to use `m' or `es' in asm statements) - case 'Z': // Memory operand that is an indexed or indirect from a - // register (it is usually better to use `m' or `es' in - // asm statements) - Info.setAllowsMemory(); - Info.setAllowsRegister(); - break; - case 'R': // AIX TOC entry - case 'a': // Address operand that is an indexed or indirect from a - // register (`p' is preferable for asm statements) - case 'S': // Constant suitable as a 64-bit mask operand - case 'T': // Constant suitable as a 32-bit mask operand - case 'U': // System V Release 4 small data area reference - case 't': // AND masks that can be performed by two rldic{l, r} - // instructions - case 'W': // Vector constant that does not require memory - case 'j': // Vector constant that is all zeros. - break; - // End FIXME. - } - return true; - } - std::string convertConstraint(const char *&Constraint) const override { - std::string R; - switch (*Constraint) { - case 'e': - case 'w': - // Two-character constraint; add "^" hint for later parsing. - R = std::string("^") + std::string(Constraint, 2); - Constraint++; - break; - default: - return TargetInfo::convertConstraint(Constraint); - } - return R; - } - const char *getClobbers() const override { - return ""; - } - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 3; - if (RegNo == 1) return 4; - return -1; - } - - bool hasSjLjLowering() const override { - return true; - } - - bool useFloat128ManglingForLongDouble() const override { - return LongDoubleWidth == 128 && - LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() && - getTriple().isOSBinFormatELF(); - } -}; - -const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsPPC.def" -}; - -/// handleTargetFeatures - Perform initialization based on the user -/// configured set of features. -bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) { - for (const auto &Feature : Features) { - if (Feature == "+altivec") { - HasAltivec = true; - } else if (Feature == "+vsx") { - HasVSX = true; - } else if (Feature == "+bpermd") { - HasBPERMD = true; - } else if (Feature == "+extdiv") { - HasExtDiv = true; - } else if (Feature == "+power8-vector") { - HasP8Vector = true; - } else if (Feature == "+crypto") { - HasP8Crypto = true; - } else if (Feature == "+direct-move") { - HasDirectMove = true; - } else if (Feature == "+qpx") { - HasQPX = true; - } else if (Feature == "+htm") { - HasHTM = true; - } else if (Feature == "+float128") { - HasFloat128 = true; - } else if (Feature == "+power9-vector") { - HasP9Vector = true; - } - // TODO: Finish this list and add an assert that we've handled them - // all. - } - - return true; -} - -/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific -/// #defines that are not tied to a specific subtarget. -void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - // Target identification. - Builder.defineMacro("__ppc__"); - Builder.defineMacro("__PPC__"); - Builder.defineMacro("_ARCH_PPC"); - Builder.defineMacro("__powerpc__"); - Builder.defineMacro("__POWERPC__"); - if (PointerWidth == 64) { - Builder.defineMacro("_ARCH_PPC64"); - Builder.defineMacro("__powerpc64__"); - Builder.defineMacro("__ppc64__"); - Builder.defineMacro("__PPC64__"); - } - - // Target properties. - if (getTriple().getArch() == llvm::Triple::ppc64le) { - Builder.defineMacro("_LITTLE_ENDIAN"); - } else { - if (getTriple().getOS() != llvm::Triple::NetBSD && - getTriple().getOS() != llvm::Triple::OpenBSD) - Builder.defineMacro("_BIG_ENDIAN"); - } - - // ABI options. - if (ABI == "elfv1" || ABI == "elfv1-qpx") - Builder.defineMacro("_CALL_ELF", "1"); - if (ABI == "elfv2") - Builder.defineMacro("_CALL_ELF", "2"); - - // This typically is only for a new enough linker (bfd >= 2.16.2 or gold), but - // our suppport post-dates this and it should work on all 64-bit ppc linux - // platforms. It is guaranteed to work on all elfv2 platforms. - if (getTriple().getOS() == llvm::Triple::Linux && PointerWidth == 64) - Builder.defineMacro("_CALL_LINUX", "1"); - - // Subtarget options. - Builder.defineMacro("__NATURAL_ALIGNMENT__"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - - // FIXME: Should be controlled by command line option. - if (LongDoubleWidth == 128) { - Builder.defineMacro("__LONG_DOUBLE_128__"); - Builder.defineMacro("__LONGDOUBLE128"); - } - - // Define this for elfv2 (64-bit only) or 64-bit darwin. - if (ABI == "elfv2" || - (getTriple().getOS() == llvm::Triple::Darwin && PointerWidth == 64)) - Builder.defineMacro("__STRUCT_PARM_ALIGN__", "16"); - - // CPU identification. - ArchDefineTypes defs = - (ArchDefineTypes)llvm::StringSwitch<int>(CPU) - .Case("440", ArchDefineName) - .Case("450", ArchDefineName | ArchDefine440) - .Case("601", ArchDefineName) - .Case("602", ArchDefineName | ArchDefinePpcgr) - .Case("603", ArchDefineName | ArchDefinePpcgr) - .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) - .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) - .Case("604", ArchDefineName | ArchDefinePpcgr) - .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) - .Case("620", ArchDefineName | ArchDefinePpcgr) - .Case("630", ArchDefineName | ArchDefinePpcgr) - .Case("7400", ArchDefineName | ArchDefinePpcgr) - .Case("7450", ArchDefineName | ArchDefinePpcgr) - .Case("750", ArchDefineName | ArchDefinePpcgr) - .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("a2", ArchDefineA2) - .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) - .Case("pwr3", ArchDefinePpcgr) - .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq) - .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 | - ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) - .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x | - ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 | - ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x | - ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | - ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) - .Case("pwr9", ArchDefineName | ArchDefinePwr8 | ArchDefinePwr7 | - ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | - ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("power3", ArchDefinePpcgr) - .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) - .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | - ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | - ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | - ArchDefinePwr5x | ArchDefinePwr5 | - ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | - ArchDefinePwr6 | ArchDefinePwr5x | - ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Case("power9", ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | - ArchDefinePwr6x | ArchDefinePwr6 | - ArchDefinePwr5x | ArchDefinePwr5 | - ArchDefinePwr4 | ArchDefinePpcgr | - ArchDefinePpcsq) - // powerpc64le automatically defaults to at least power8. - .Case("ppc64le", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | - ArchDefinePwr6 | ArchDefinePwr5x | - ArchDefinePwr5 | ArchDefinePwr4 | - ArchDefinePpcgr | ArchDefinePpcsq) - .Default(ArchDefineNone); - - if (defs & ArchDefineName) - Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); - if (defs & ArchDefinePpcgr) - Builder.defineMacro("_ARCH_PPCGR"); - if (defs & ArchDefinePpcsq) - Builder.defineMacro("_ARCH_PPCSQ"); - if (defs & ArchDefine440) - Builder.defineMacro("_ARCH_440"); - if (defs & ArchDefine603) - Builder.defineMacro("_ARCH_603"); - if (defs & ArchDefine604) - Builder.defineMacro("_ARCH_604"); - if (defs & ArchDefinePwr4) - Builder.defineMacro("_ARCH_PWR4"); - if (defs & ArchDefinePwr5) - Builder.defineMacro("_ARCH_PWR5"); - if (defs & ArchDefinePwr5x) - Builder.defineMacro("_ARCH_PWR5X"); - if (defs & ArchDefinePwr6) - Builder.defineMacro("_ARCH_PWR6"); - if (defs & ArchDefinePwr6x) - Builder.defineMacro("_ARCH_PWR6X"); - if (defs & ArchDefinePwr7) - Builder.defineMacro("_ARCH_PWR7"); - if (defs & ArchDefinePwr8) - Builder.defineMacro("_ARCH_PWR8"); - if (defs & ArchDefinePwr9) - Builder.defineMacro("_ARCH_PWR9"); - if (defs & ArchDefineA2) - Builder.defineMacro("_ARCH_A2"); - if (defs & ArchDefineA2q) { - Builder.defineMacro("_ARCH_A2Q"); - Builder.defineMacro("_ARCH_QP"); - } - - if (getTriple().getVendor() == llvm::Triple::BGQ) { - Builder.defineMacro("__bg__"); - Builder.defineMacro("__THW_BLUEGENE__"); - Builder.defineMacro("__bgq__"); - Builder.defineMacro("__TOS_BGQ__"); - } - - if (HasAltivec) { - Builder.defineMacro("__VEC__", "10206"); - Builder.defineMacro("__ALTIVEC__"); - } - if (HasVSX) - Builder.defineMacro("__VSX__"); - if (HasP8Vector) - Builder.defineMacro("__POWER8_VECTOR__"); - if (HasP8Crypto) - Builder.defineMacro("__CRYPTO__"); - if (HasHTM) - Builder.defineMacro("__HTM__"); - if (HasFloat128) - Builder.defineMacro("__FLOAT128__"); - if (HasP9Vector) - Builder.defineMacro("__POWER9_VECTOR__"); - - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - if (PointerWidth == 64) - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - - // We have support for the bswap intrinsics so we can define this. - Builder.defineMacro("__HAVE_BSWAP__", "1"); - - // FIXME: The following are not yet generated here by Clang, but are - // generated by GCC: - // - // _SOFT_FLOAT_ - // __RECIP_PRECISION__ - // __APPLE_ALTIVEC__ - // __RECIP__ - // __RECIPF__ - // __RSQRTE__ - // __RSQRTEF__ - // _SOFT_DOUBLE_ - // __NO_LWSYNC__ - // __CMODEL_MEDIUM__ - // __CMODEL_LARGE__ - // _CALL_SYSV - // _CALL_DARWIN - // __NO_FPRS__ -} - -// Handle explicit options being passed to the compiler here: if we've -// explicitly turned off vsx and turned on any of: -// - power8-vector -// - direct-move -// - float128 -// - power9-vector -// then go ahead and error since the customer has expressed an incompatible -// set of options. -static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, - const std::vector<std::string> &FeaturesVec) { - - if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") != - FeaturesVec.end()) { - if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") != - FeaturesVec.end()) { - Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" - << "-mno-vsx"; - return false; - } - - if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") != - FeaturesVec.end()) { - Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" - << "-mno-vsx"; - return false; - } - - if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") != - FeaturesVec.end()) { - Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" - << "-mno-vsx"; - return false; - } - - if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power9-vector") != - FeaturesVec.end()) { - Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector" - << "-mno-vsx"; - return false; - } - } - - return true; -} - -bool PPCTargetInfo::initFeatureMap( - llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeaturesVec) const { - Features["altivec"] = llvm::StringSwitch<bool>(CPU) - .Case("7400", true) - .Case("g4", true) - .Case("7450", true) - .Case("g4+", true) - .Case("970", true) - .Case("g5", true) - .Case("pwr6", true) - .Case("pwr7", true) - .Case("pwr8", true) - .Case("pwr9", true) - .Case("ppc64", true) - .Case("ppc64le", true) - .Default(false); - - Features["qpx"] = (CPU == "a2q"); - Features["power9-vector"] = (CPU == "pwr9"); - Features["crypto"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["power8-vector"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["bpermd"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["extdiv"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["direct-move"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - Features["vsx"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Case("pwr7", true) - .Default(false); - Features["htm"] = llvm::StringSwitch<bool>(CPU) - .Case("ppc64le", true) - .Case("pwr9", true) - .Case("pwr8", true) - .Default(false); - - if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) - return false; - - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); -} - -bool PPCTargetInfo::hasFeature(StringRef Feature) const { - return llvm::StringSwitch<bool>(Feature) - .Case("powerpc", true) - .Case("altivec", HasAltivec) - .Case("vsx", HasVSX) - .Case("power8-vector", HasP8Vector) - .Case("crypto", HasP8Crypto) - .Case("direct-move", HasDirectMove) - .Case("qpx", HasQPX) - .Case("htm", HasHTM) - .Case("bpermd", HasBPERMD) - .Case("extdiv", HasExtDiv) - .Case("float128", HasFloat128) - .Case("power9-vector", HasP9Vector) - .Default(false); -} - -void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, - StringRef Name, bool Enabled) const { - if (Enabled) { - // If we're enabling any of the vsx based features then enable vsx and - // altivec. We'll diagnose any problems later. - bool FeatureHasVSX = llvm::StringSwitch<bool>(Name) - .Case("vsx", true) - .Case("direct-move", true) - .Case("power8-vector", true) - .Case("power9-vector", true) - .Case("float128", true) - .Default(false); - if (FeatureHasVSX) - Features["vsx"] = Features["altivec"] = true; - if (Name == "power9-vector") - Features["power8-vector"] = true; - Features[Name] = true; - } else { - // If we're disabling altivec or vsx go ahead and disable all of the vsx - // features. - if ((Name == "altivec") || (Name == "vsx")) - Features["vsx"] = Features["direct-move"] = Features["power8-vector"] = - Features["float128"] = Features["power9-vector"] = false; - if (Name == "power8-vector") - Features["power9-vector"] = false; - Features[Name] = false; - } -} - -const char * const PPCTargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", - "mq", "lr", "ctr", "ap", - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", - "xer", - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", - "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", - "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", - "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", - "vrsave", "vscr", - "spe_acc", "spefscr", - "sfp" -}; - -ArrayRef<const char*> PPCTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { - // While some of these aliases do map to different registers - // they still share the same register name. - { { "0" }, "r0" }, - { { "1"}, "r1" }, - { { "2" }, "r2" }, - { { "3" }, "r3" }, - { { "4" }, "r4" }, - { { "5" }, "r5" }, - { { "6" }, "r6" }, - { { "7" }, "r7" }, - { { "8" }, "r8" }, - { { "9" }, "r9" }, - { { "10" }, "r10" }, - { { "11" }, "r11" }, - { { "12" }, "r12" }, - { { "13" }, "r13" }, - { { "14" }, "r14" }, - { { "15" }, "r15" }, - { { "16" }, "r16" }, - { { "17" }, "r17" }, - { { "18" }, "r18" }, - { { "19" }, "r19" }, - { { "20" }, "r20" }, - { { "21" }, "r21" }, - { { "22" }, "r22" }, - { { "23" }, "r23" }, - { { "24" }, "r24" }, - { { "25" }, "r25" }, - { { "26" }, "r26" }, - { { "27" }, "r27" }, - { { "28" }, "r28" }, - { { "29" }, "r29" }, - { { "30" }, "r30" }, - { { "31" }, "r31" }, - { { "fr0" }, "f0" }, - { { "fr1" }, "f1" }, - { { "fr2" }, "f2" }, - { { "fr3" }, "f3" }, - { { "fr4" }, "f4" }, - { { "fr5" }, "f5" }, - { { "fr6" }, "f6" }, - { { "fr7" }, "f7" }, - { { "fr8" }, "f8" }, - { { "fr9" }, "f9" }, - { { "fr10" }, "f10" }, - { { "fr11" }, "f11" }, - { { "fr12" }, "f12" }, - { { "fr13" }, "f13" }, - { { "fr14" }, "f14" }, - { { "fr15" }, "f15" }, - { { "fr16" }, "f16" }, - { { "fr17" }, "f17" }, - { { "fr18" }, "f18" }, - { { "fr19" }, "f19" }, - { { "fr20" }, "f20" }, - { { "fr21" }, "f21" }, - { { "fr22" }, "f22" }, - { { "fr23" }, "f23" }, - { { "fr24" }, "f24" }, - { { "fr25" }, "f25" }, - { { "fr26" }, "f26" }, - { { "fr27" }, "f27" }, - { { "fr28" }, "f28" }, - { { "fr29" }, "f29" }, - { { "fr30" }, "f30" }, - { { "fr31" }, "f31" }, - { { "cc" }, "cr0" }, -}; - -ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - -class PPC32TargetInfo : public PPCTargetInfo { -public: - PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : PPCTargetInfo(Triple, Opts) { - resetDataLayout("E-m:e-p:32:32-i64:64-n32"); - - switch (getTriple().getOS()) { - case llvm::Triple::Linux: - case llvm::Triple::FreeBSD: - case llvm::Triple::NetBSD: - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - break; - default: - break; - } - - if (getTriple().getOS() == llvm::Triple::FreeBSD) { - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - } - - // PPC32 supports atomics up to 4 bytes. - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - // This is the ELF definition, and is overridden by the Darwin sub-target - return TargetInfo::PowerABIBuiltinVaList; - } -}; - -// Note: ABI differences may eventually require us to have a separate -// TargetInfo for little endian. -class PPC64TargetInfo : public PPCTargetInfo { -public: - PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : PPCTargetInfo(Triple, Opts) { - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - IntMaxType = SignedLong; - Int64Type = SignedLong; - - if ((Triple.getArch() == llvm::Triple::ppc64le)) { - resetDataLayout("e-m:e-i64:64-n32:64"); - ABI = "elfv2"; - } else { - resetDataLayout("E-m:e-i64:64-n32:64"); - ABI = "elfv1"; - } - - switch (getTriple().getOS()) { - case llvm::Triple::FreeBSD: - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - break; - case llvm::Triple::NetBSD: - IntMaxType = SignedLongLong; - Int64Type = SignedLongLong; - break; - default: - break; - } - - // PPC64 supports atomics up to 8 bytes. - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - // PPC64 Linux-specific ABI options. - bool setABI(const std::string &Name) override { - if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { - ABI = Name; - return true; - } - return false; - } -}; - -class DarwinPPC32TargetInfo : public DarwinTargetInfo<PPC32TargetInfo> { -public: - DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) { - HasAlignMac68kSupport = true; - BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool? - PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 - LongLongAlign = 32; - resetDataLayout("E-m:o-p:32:32-f64:32:64-n32"); - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } -}; - -class DarwinPPC64TargetInfo : public DarwinTargetInfo<PPC64TargetInfo> { -public: - DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) { - HasAlignMac68kSupport = true; - resetDataLayout("E-m:o-i64:64-n32:64"); - } -}; - -static const unsigned NVPTXAddrSpaceMap[] = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 4, // opencl_constant - // FIXME: generic has to be added to the target - 0, // opencl_generic - 1, // cuda_device - 4, // cuda_constant - 3, // cuda_shared -}; - -class NVPTXTargetInfo : public TargetInfo { - static const char *const GCCRegNames[]; - static const Builtin::Info BuiltinInfo[]; - CudaArch GPU; - std::unique_ptr<TargetInfo> HostTarget; - -public: - NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts, - unsigned TargetPointerWidth) - : TargetInfo(Triple) { - assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) && - "NVPTX only supports 32- and 64-bit modes."); - - TLSSupported = false; - AddrSpaceMap = &NVPTXAddrSpaceMap; - UseAddrSpaceMapMangling = true; - - // Define available target features - // These must be defined in sorted order! - NoAsmVariants = true; - GPU = CudaArch::SM_20; - - if (TargetPointerWidth == 32) - resetDataLayout("e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"); - else - resetDataLayout("e-i64:64-v16:16-v32:32-n16:32:64"); - - // If possible, get a TargetInfo for our host triple, so we can match its - // types. - llvm::Triple HostTriple(Opts.HostTriple); - if (!HostTriple.isNVPTX()) - HostTarget.reset(AllocateTarget(llvm::Triple(Opts.HostTriple), Opts)); - - // If no host target, make some guesses about the data layout and return. - if (!HostTarget) { - LongWidth = LongAlign = TargetPointerWidth; - PointerWidth = PointerAlign = TargetPointerWidth; - switch (TargetPointerWidth) { - case 32: - SizeType = TargetInfo::UnsignedInt; - PtrDiffType = TargetInfo::SignedInt; - IntPtrType = TargetInfo::SignedInt; - break; - case 64: - SizeType = TargetInfo::UnsignedLong; - PtrDiffType = TargetInfo::SignedLong; - IntPtrType = TargetInfo::SignedLong; - break; - default: - llvm_unreachable("TargetPointerWidth must be 32 or 64"); - } - return; - } - - // Copy properties from host target. - PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0); - PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0); - BoolWidth = HostTarget->getBoolWidth(); - BoolAlign = HostTarget->getBoolAlign(); - IntWidth = HostTarget->getIntWidth(); - IntAlign = HostTarget->getIntAlign(); - HalfWidth = HostTarget->getHalfWidth(); - HalfAlign = HostTarget->getHalfAlign(); - FloatWidth = HostTarget->getFloatWidth(); - FloatAlign = HostTarget->getFloatAlign(); - DoubleWidth = HostTarget->getDoubleWidth(); - DoubleAlign = HostTarget->getDoubleAlign(); - LongWidth = HostTarget->getLongWidth(); - LongAlign = HostTarget->getLongAlign(); - LongLongWidth = HostTarget->getLongLongWidth(); - LongLongAlign = HostTarget->getLongLongAlign(); - MinGlobalAlign = HostTarget->getMinGlobalAlign(); - NewAlign = HostTarget->getNewAlign(); - DefaultAlignForAttributeAligned = - HostTarget->getDefaultAlignForAttributeAligned(); - SizeType = HostTarget->getSizeType(); - IntMaxType = HostTarget->getIntMaxType(); - PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0); - IntPtrType = HostTarget->getIntPtrType(); - WCharType = HostTarget->getWCharType(); - WIntType = HostTarget->getWIntType(); - Char16Type = HostTarget->getChar16Type(); - Char32Type = HostTarget->getChar32Type(); - Int64Type = HostTarget->getInt64Type(); - SigAtomicType = HostTarget->getSigAtomicType(); - ProcessIDType = HostTarget->getProcessIDType(); - - UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); - UseZeroLengthBitfieldAlignment = - HostTarget->useZeroLengthBitfieldAlignment(); - UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); - ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); - - // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and - // we need those macros to be identical on host and device, because (among - // other things) they affect which standard library classes are defined, and - // we need all classes to be defined on both the host and device. - MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); - - // Properties intentionally not copied from host: - // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the - // host/device boundary. - // - SuitableAlign: Not visible across the host/device boundary, and may - // correctly be different on host/device, e.g. if host has wider vector - // types than device. - // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same - // as its double type, but that's not necessarily true on the host. - // TODO: nvcc emits a warning when using long double on device; we should - // do the same. - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__PTX__"); - Builder.defineMacro("__NVPTX__"); - if (Opts.CUDAIsDevice) { - // Set __CUDA_ARCH__ for the GPU specified. - std::string CUDAArchCode = [this] { - switch (GPU) { - case CudaArch::UNKNOWN: - assert(false && "No GPU arch when compiling CUDA device code."); - return ""; - case CudaArch::SM_20: - return "200"; - case CudaArch::SM_21: - return "210"; - case CudaArch::SM_30: - return "300"; - case CudaArch::SM_32: - return "320"; - case CudaArch::SM_35: - return "350"; - case CudaArch::SM_37: - return "370"; - case CudaArch::SM_50: - return "500"; - case CudaArch::SM_52: - return "520"; - case CudaArch::SM_53: - return "530"; - case CudaArch::SM_60: - return "600"; - case CudaArch::SM_61: - return "610"; - case CudaArch::SM_62: - return "620"; - } - llvm_unreachable("unhandled CudaArch"); - }(); - Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); - } - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - Features["satom"] = GPU >= CudaArch::SM_60; - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); - } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Cases("ptx", "nvptx", true) - .Case("satom", GPU >= CudaArch::SM_60) // Atomics w/ scope. - .Default(false); - } - - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - // No aliases. - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: - return false; - case 'c': - case 'h': - case 'r': - case 'l': - case 'f': - case 'd': - Info.setAllowsRegister(); - return true; - } - } - const char *getClobbers() const override { - // FIXME: Is this really right? - return ""; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - // FIXME: implement - return TargetInfo::CharPtrBuiltinVaList; - } - bool setCPU(const std::string &Name) override { - GPU = StringToCudaArch(Name); - return GPU != CudaArch::UNKNOWN; - } - void setSupportedOpenCLOpts() override { - auto &Opts = getSupportedOpenCLOpts(); - Opts.support("cl_clang_storage_class_specifiers"); - Opts.support("cl_khr_gl_sharing"); - Opts.support("cl_khr_icd"); - - Opts.support("cl_khr_fp64"); - Opts.support("cl_khr_byte_addressable_store"); - Opts.support("cl_khr_global_int32_base_atomics"); - Opts.support("cl_khr_global_int32_extended_atomics"); - Opts.support("cl_khr_local_int32_base_atomics"); - Opts.support("cl_khr_local_int32_extended_atomics"); - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - // CUDA compilations support all of the host's calling conventions. - // - // TODO: We should warn if you apply a non-default CC to anything other than - // a host function. - if (HostTarget) - return HostTarget->checkCallingConvention(CC); - return CCCR_Warning; - } -}; - -const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, -#include "clang/Basic/BuiltinsNVPTX.def" -}; - -const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; - -ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = { - 4, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 4, // opencl_generic - 1, // cuda_device - 2, // cuda_constant - 3 // cuda_shared -}; -static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 0, // opencl_generic - 1, // cuda_device - 2, // cuda_constant - 3 // cuda_shared -}; -static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 4, // opencl_generic - 1, // cuda_device - 2, // cuda_constant - 3 // cuda_shared -}; -static const LangAS::Map AMDGPUGenIsZeroDefIsPrivMap = { - 5, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 0, // opencl_generic - 1, // cuda_device - 2, // cuda_constant - 3 // cuda_shared -}; - -// If you edit the description strings, make sure you update -// getPointerWidthV(). - -static const char *const DataLayoutStringR600 = - "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" - "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; - -static const char *const DataLayoutStringSIPrivateIsZero = - "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32" - "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" - "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; - -static const char *const DataLayoutStringSIGenericIsZero = - "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-p4:32:32-p5:32:32" - "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" - "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-A5"; - -class AMDGPUTargetInfo final : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - static const char * const GCCRegNames[]; - - struct AddrSpace { - unsigned Generic, Global, Local, Constant, Private; - AddrSpace(bool IsGenericZero_ = false){ - if (IsGenericZero_) { - Generic = 0; - Global = 1; - Local = 3; - Constant = 2; - Private = 5; - } else { - Generic = 4; - Global = 1; - Local = 3; - Constant = 2; - Private = 0; - } - } - }; - - /// \brief The GPU profiles supported by the AMDGPU target. - enum GPUKind { - GK_NONE, - GK_R600, - GK_R600_DOUBLE_OPS, - GK_R700, - GK_R700_DOUBLE_OPS, - GK_EVERGREEN, - GK_EVERGREEN_DOUBLE_OPS, - GK_NORTHERN_ISLANDS, - GK_CAYMAN, - GK_GFX6, - GK_GFX7, - GK_GFX8, - GK_GFX9 - } GPU; - - bool hasFP64:1; - bool hasFMAF:1; - bool hasLDEXPF:1; - const AddrSpace AS; - - static bool hasFullSpeedFMAF32(StringRef GPUName) { - return parseAMDGCNName(GPUName) >= GK_GFX9; - } - - static bool isAMDGCN(const llvm::Triple &TT) { - return TT.getArch() == llvm::Triple::amdgcn; - } - - static bool isGenericZero(const llvm::Triple &TT) { - return TT.getEnvironmentName() == "amdgiz" || - TT.getEnvironmentName() == "amdgizcl"; - } -public: - AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TargetInfo(Triple) , - GPU(isAMDGCN(Triple) ? GK_GFX6 : parseR600Name(Opts.CPU)), - hasFP64(false), - hasFMAF(false), - hasLDEXPF(false), - AS(isGenericZero(Triple)){ - if (getTriple().getArch() == llvm::Triple::amdgcn) { - hasFP64 = true; - hasFMAF = true; - hasLDEXPF = true; - } - if (getTriple().getArch() == llvm::Triple::r600) { - if (GPU == GK_EVERGREEN_DOUBLE_OPS || GPU == GK_CAYMAN) { - hasFMAF = true; - } - } - - auto IsGenericZero = isGenericZero(Triple); - resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn ? - (IsGenericZero ? DataLayoutStringSIGenericIsZero : - DataLayoutStringSIPrivateIsZero) - : DataLayoutStringR600); - assert(DataLayout->getAllocaAddrSpace() == AS.Private); - - setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || - Triple.getEnvironment() == llvm::Triple::OpenCL || - Triple.getEnvironmentName() == "amdgizcl" || - !isAMDGCN(Triple)); - UseAddrSpaceMapMangling = true; - - // Set pointer width and alignment for target address space 0. - PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits(); - if (getMaxPointerWidth() == 64) { - LongWidth = LongAlign = 64; - SizeType = UnsignedLong; - PtrDiffType = SignedLong; - IntPtrType = SignedLong; - } - } - - void setAddressSpaceMap(bool DefaultIsPrivate) { - if (isGenericZero(getTriple())) { - AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap - : &AMDGPUGenIsZeroDefIsGenMap; - } else { - AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap - : &AMDGPUPrivIsZeroDefIsGenMap; - } - } - - void adjust(LangOptions &Opts) override { - TargetInfo::adjust(Opts); - setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple())); - } - - uint64_t getPointerWidthV(unsigned AddrSpace) const override { - if (GPU <= GK_CAYMAN) - return 32; - - if (AddrSpace == AS.Private || AddrSpace == AS.Local) { - return 32; - } - return 64; - } - - uint64_t getPointerAlignV(unsigned AddrSpace) const override { - return getPointerWidthV(AddrSpace); - } - - uint64_t getMaxPointerWidth() const override { - return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; - } - - const char * getClobbers() const override { - return ""; - } - - ArrayRef<const char *> getGCCRegNames() const override; - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: break; - case 'v': // vgpr - case 's': // sgpr - Info.setAllowsRegister(); - return true; - } - return false; - } - - bool initFeatureMap(llvm::StringMap<bool> &Features, - DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeatureVec) const override; - - void adjustTargetOptions(const CodeGenOptions &CGOpts, - TargetOptions &TargetOpts) const override { - bool hasFP32Denormals = false; - bool hasFP64Denormals = false; - for (auto &I : TargetOpts.FeaturesAsWritten) { - if (I == "+fp32-denormals" || I == "-fp32-denormals") - hasFP32Denormals = true; - if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals") - hasFP64Denormals = true; - } - if (!hasFP32Denormals) - TargetOpts.Features.push_back( - (Twine(hasFullSpeedFMAF32(TargetOpts.CPU) && - !CGOpts.FlushDenorm ? '+' : '-') + Twine("fp32-denormals")).str()); - // Always do not flush fp64 or fp16 denorms. - if (!hasFP64Denormals && hasFP64) - TargetOpts.Features.push_back("+fp64-fp16-denormals"); - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - if (getTriple().getArch() == llvm::Triple::amdgcn) - Builder.defineMacro("__AMDGCN__"); - else - Builder.defineMacro("__R600__"); - - if (hasFMAF) - Builder.defineMacro("__HAS_FMAF__"); - if (hasLDEXPF) - Builder.defineMacro("__HAS_LDEXPF__"); - if (hasFP64) - Builder.defineMacro("__HAS_FP64__"); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - - static GPUKind parseR600Name(StringRef Name) { - return llvm::StringSwitch<GPUKind>(Name) - .Case("r600" , GK_R600) - .Case("rv610", GK_R600) - .Case("rv620", GK_R600) - .Case("rv630", GK_R600) - .Case("rv635", GK_R600) - .Case("rs780", GK_R600) - .Case("rs880", GK_R600) - .Case("rv670", GK_R600_DOUBLE_OPS) - .Case("rv710", GK_R700) - .Case("rv730", GK_R700) - .Case("rv740", GK_R700_DOUBLE_OPS) - .Case("rv770", GK_R700_DOUBLE_OPS) - .Case("palm", GK_EVERGREEN) - .Case("cedar", GK_EVERGREEN) - .Case("sumo", GK_EVERGREEN) - .Case("sumo2", GK_EVERGREEN) - .Case("redwood", GK_EVERGREEN) - .Case("juniper", GK_EVERGREEN) - .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS) - .Case("cypress", GK_EVERGREEN_DOUBLE_OPS) - .Case("barts", GK_NORTHERN_ISLANDS) - .Case("turks", GK_NORTHERN_ISLANDS) - .Case("caicos", GK_NORTHERN_ISLANDS) - .Case("cayman", GK_CAYMAN) - .Case("aruba", GK_CAYMAN) - .Default(GK_NONE); - } - - static GPUKind parseAMDGCNName(StringRef Name) { - return llvm::StringSwitch<GPUKind>(Name) - .Case("tahiti", GK_GFX6) - .Case("pitcairn", GK_GFX6) - .Case("verde", GK_GFX6) - .Case("oland", GK_GFX6) - .Case("hainan", GK_GFX6) - .Case("bonaire", GK_GFX7) - .Case("kabini", GK_GFX7) - .Case("kaveri", GK_GFX7) - .Case("hawaii", GK_GFX7) - .Case("mullins", GK_GFX7) - .Case("gfx700", GK_GFX7) - .Case("gfx701", GK_GFX7) - .Case("gfx702", GK_GFX7) - .Case("tonga", GK_GFX8) - .Case("iceland", GK_GFX8) - .Case("carrizo", GK_GFX8) - .Case("fiji", GK_GFX8) - .Case("stoney", GK_GFX8) - .Case("polaris10", GK_GFX8) - .Case("polaris11", GK_GFX8) - .Case("gfx800", GK_GFX8) - .Case("gfx801", GK_GFX8) - .Case("gfx802", GK_GFX8) - .Case("gfx803", GK_GFX8) - .Case("gfx804", GK_GFX8) - .Case("gfx810", GK_GFX8) - .Case("gfx900", GK_GFX9) - .Case("gfx901", GK_GFX9) - .Default(GK_NONE); - } - - bool setCPU(const std::string &Name) override { - if (getTriple().getArch() == llvm::Triple::amdgcn) - GPU = parseAMDGCNName(Name); - else - GPU = parseR600Name(Name); - - return GPU != GK_NONE; - } - - void setSupportedOpenCLOpts() override { - auto &Opts = getSupportedOpenCLOpts(); - Opts.support("cl_clang_storage_class_specifiers"); - Opts.support("cl_khr_icd"); - - if (hasFP64) - Opts.support("cl_khr_fp64"); - if (GPU >= GK_EVERGREEN) { - Opts.support("cl_khr_byte_addressable_store"); - Opts.support("cl_khr_global_int32_base_atomics"); - Opts.support("cl_khr_global_int32_extended_atomics"); - Opts.support("cl_khr_local_int32_base_atomics"); - Opts.support("cl_khr_local_int32_extended_atomics"); - } - if (GPU >= GK_GFX6) { - Opts.support("cl_khr_fp16"); - Opts.support("cl_khr_int64_base_atomics"); - Opts.support("cl_khr_int64_extended_atomics"); - Opts.support("cl_khr_mipmap_image"); - Opts.support("cl_khr_subgroups"); - Opts.support("cl_khr_3d_image_writes"); - Opts.support("cl_amd_media_ops"); - Opts.support("cl_amd_media_ops2"); - } - } - - LangAS::ID getOpenCLImageAddrSpace() const override { - return LangAS::opencl_constant; - } - - llvm::Optional<unsigned> getConstantAddressSpace() const override { - return LangAS::FirstTargetAddressSpace + AS.Constant; - } - - /// \returns Target specific vtbl ptr address space. - unsigned getVtblPtrAddressSpace() const override { return AS.Constant; } - - /// \returns If a target requires an address within a target specific address - /// space \p AddressSpace to be converted in order to be used, then return the - /// corresponding target specific DWARF address space. - /// - /// \returns Otherwise return None and no conversion will be emitted in the - /// DWARF. - Optional<unsigned> getDWARFAddressSpace( - unsigned AddressSpace) const override { - const unsigned DWARF_Private = 1; - const unsigned DWARF_Local = 2; - if (AddressSpace == AS.Private) { - return DWARF_Private; - } else if (AddressSpace == AS.Local) { - return DWARF_Local; - } else { - return None; - } - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - default: - return CCCR_Warning; - case CC_C: - case CC_OpenCLKernel: - return CCCR_OK; - } - } - - // In amdgcn target the null pointer in global, constant, and generic - // address space has value 0 but in private and local address space has - // value ~0. - uint64_t getNullPointerValue(unsigned AS) const override { - return AS == LangAS::opencl_local ? ~0 : 0; - } -}; - -const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, -#include "clang/Basic/BuiltinsAMDGPU.def" -}; -const char * const AMDGPUTargetInfo::GCCRegNames[] = { - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", - "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", - "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", - "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", - "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39", - "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47", - "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55", - "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63", - "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", - "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", - "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87", - "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95", - "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103", - "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111", - "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119", - "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127", - "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135", - "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", - "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", - "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159", - "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167", - "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175", - "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183", - "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191", - "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199", - "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207", - "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", - "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", - "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231", - "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239", - "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247", - "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", - "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", - "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", - "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", - "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", - "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55", - "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63", - "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71", - "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79", - "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87", - "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95", - "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", - "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", - "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119", - "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127", - "exec", "vcc", "scc", "m0", "flat_scratch", "exec_lo", "exec_hi", - "vcc_lo", "vcc_hi", "flat_scratch_lo", "flat_scratch_hi" -}; - -ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -bool AMDGPUTargetInfo::initFeatureMap( - llvm::StringMap<bool> &Features, - DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeatureVec) const { - - // XXX - What does the member GPU mean if device name string passed here? - if (getTriple().getArch() == llvm::Triple::amdgcn) { - if (CPU.empty()) - CPU = "tahiti"; - - switch (parseAMDGCNName(CPU)) { - case GK_GFX6: - case GK_GFX7: - break; - - case GK_GFX9: - Features["gfx9-insts"] = true; - LLVM_FALLTHROUGH; - case GK_GFX8: - Features["s-memrealtime"] = true; - Features["16-bit-insts"] = true; - Features["dpp"] = true; - break; - - case GK_NONE: - return false; - default: - llvm_unreachable("unhandled subtarget"); - } - } else { - if (CPU.empty()) - CPU = "r600"; - - switch (parseR600Name(CPU)) { - case GK_R600: - case GK_R700: - case GK_EVERGREEN: - case GK_NORTHERN_ISLANDS: - break; - case GK_R600_DOUBLE_OPS: - case GK_R700_DOUBLE_OPS: - case GK_EVERGREEN_DOUBLE_OPS: - case GK_CAYMAN: - Features["fp64"] = true; - break; - case GK_NONE: - return false; - default: - llvm_unreachable("unhandled subtarget"); - } - } - - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec); -} - -const Builtin::Info BuiltinInfoX86[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, -#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ - { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE }, -#include "clang/Basic/BuiltinsX86.def" - -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, -#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ - { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE }, -#include "clang/Basic/BuiltinsX86_64.def" -}; - - -static const char* const GCCRegNames[] = { - "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", - "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", - "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", - "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", - "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", - "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", - "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", - "xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", - "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", - "ymm16", "ymm17", "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", - "ymm24", "ymm25", "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", - "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", - "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", - "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", - "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", - "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", -}; - -const TargetInfo::AddlRegName AddlRegNames[] = { - { { "al", "ah", "eax", "rax" }, 0 }, - { { "bl", "bh", "ebx", "rbx" }, 3 }, - { { "cl", "ch", "ecx", "rcx" }, 2 }, - { { "dl", "dh", "edx", "rdx" }, 1 }, - { { "esi", "rsi" }, 4 }, - { { "edi", "rdi" }, 5 }, - { { "esp", "rsp" }, 7 }, - { { "ebp", "rbp" }, 6 }, - { { "r8d", "r8w", "r8b" }, 38 }, - { { "r9d", "r9w", "r9b" }, 39 }, - { { "r10d", "r10w", "r10b" }, 40 }, - { { "r11d", "r11w", "r11b" }, 41 }, - { { "r12d", "r12w", "r12b" }, 42 }, - { { "r13d", "r13w", "r13b" }, 43 }, - { { "r14d", "r14w", "r14b" }, 44 }, - { { "r15d", "r15w", "r15b" }, 45 }, -}; - -// X86 target abstract base class; x86-32 and x86-64 are very close, so -// most of the implementation can be shared. -class X86TargetInfo : public TargetInfo { - enum X86SSEEnum { - NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F - } SSELevel = NoSSE; - enum MMX3DNowEnum { - NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon - } MMX3DNowLevel = NoMMX3DNow; - enum XOPEnum { - NoXOP, - SSE4A, - FMA4, - XOP - } XOPLevel = NoXOP; - - bool HasAES = false; - bool HasPCLMUL = false; - bool HasLZCNT = false; - bool HasRDRND = false; - bool HasFSGSBASE = false; - bool HasBMI = false; - bool HasBMI2 = false; - bool HasPOPCNT = false; - bool HasRTM = false; - bool HasPRFCHW = false; - bool HasRDSEED = false; - bool HasADX = false; - bool HasTBM = false; - bool HasLWP = false; - bool HasFMA = false; - bool HasF16C = false; - bool HasAVX512CD = false; - bool HasAVX512VPOPCNTDQ = false; - bool HasAVX512ER = false; - bool HasAVX512PF = false; - bool HasAVX512DQ = false; - bool HasAVX512BW = false; - bool HasAVX512VL = false; - bool HasAVX512VBMI = false; - bool HasAVX512IFMA = false; - bool HasSHA = false; - bool HasMPX = false; - bool HasSGX = false; - bool HasCX16 = false; - bool HasFXSR = false; - bool HasXSAVE = false; - bool HasXSAVEOPT = false; - bool HasXSAVEC = false; - bool HasXSAVES = false; - bool HasMWAITX = false; - bool HasCLZERO = false; - bool HasPKU = false; - bool HasCLFLUSHOPT = false; - bool HasCLWB = false; - bool HasMOVBE = false; - bool HasPREFETCHWT1 = false; - - /// \brief Enumeration of all of the X86 CPUs supported by Clang. - /// - /// Each enumeration represents a particular CPU supported by Clang. These - /// loosely correspond to the options passed to '-march' or '-mtune' flags. - enum CPUKind { - CK_Generic, - - /// \name i386 - /// i386-generation processors. - //@{ - CK_i386, - //@} - - /// \name i486 - /// i486-generation processors. - //@{ - CK_i486, - CK_WinChipC6, - CK_WinChip2, - CK_C3, - //@} - - /// \name i586 - /// i586-generation processors, P5 microarchitecture based. - //@{ - CK_i586, - CK_Pentium, - CK_PentiumMMX, - //@} - - /// \name i686 - /// i686-generation processors, P6 / Pentium M microarchitecture based. - //@{ - CK_i686, - CK_PentiumPro, - CK_Pentium2, - CK_Pentium3, - CK_Pentium3M, - CK_PentiumM, - CK_C3_2, - - /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. - /// Clang however has some logic to support this. - // FIXME: Warn, deprecate, and potentially remove this. - CK_Yonah, - //@} - - /// \name Netburst - /// Netburst microarchitecture based processors. - //@{ - CK_Pentium4, - CK_Pentium4M, - CK_Prescott, - CK_Nocona, - //@} - - /// \name Core - /// Core microarchitecture based processors. - //@{ - CK_Core2, - - /// This enumerator, like \see CK_Yonah, is a bit odd. It is another - /// codename which GCC no longer accepts as an option to -march, but Clang - /// has some logic for recognizing it. - // FIXME: Warn, deprecate, and potentially remove this. - CK_Penryn, - //@} - - /// \name Atom - /// Atom processors - //@{ - CK_Bonnell, - CK_Silvermont, - CK_Goldmont, - //@} - - /// \name Nehalem - /// Nehalem microarchitecture based processors. - CK_Nehalem, - - /// \name Westmere - /// Westmere microarchitecture based processors. - CK_Westmere, - - /// \name Sandy Bridge - /// Sandy Bridge microarchitecture based processors. - CK_SandyBridge, - - /// \name Ivy Bridge - /// Ivy Bridge microarchitecture based processors. - CK_IvyBridge, - - /// \name Haswell - /// Haswell microarchitecture based processors. - CK_Haswell, - - /// \name Broadwell - /// Broadwell microarchitecture based processors. - CK_Broadwell, - - /// \name Skylake Client - /// Skylake client microarchitecture based processors. - CK_SkylakeClient, - - /// \name Skylake Server - /// Skylake server microarchitecture based processors. - CK_SkylakeServer, - - /// \name Cannonlake Client - /// Cannonlake client microarchitecture based processors. - CK_Cannonlake, - - /// \name Knights Landing - /// Knights Landing processor. - CK_KNL, - - /// \name Lakemont - /// Lakemont microarchitecture based processors. - CK_Lakemont, - - /// \name K6 - /// K6 architecture processors. - //@{ - CK_K6, - CK_K6_2, - CK_K6_3, - //@} - - /// \name K7 - /// K7 architecture processors. - //@{ - CK_Athlon, - CK_AthlonThunderbird, - CK_Athlon4, - CK_AthlonXP, - CK_AthlonMP, - //@} - - /// \name K8 - /// K8 architecture processors. - //@{ - CK_Athlon64, - CK_Athlon64SSE3, - CK_AthlonFX, - CK_K8, - CK_K8SSE3, - CK_Opteron, - CK_OpteronSSE3, - CK_AMDFAM10, - //@} - - /// \name Bobcat - /// Bobcat architecture processors. - //@{ - CK_BTVER1, - CK_BTVER2, - //@} - - /// \name Bulldozer - /// Bulldozer architecture processors. - //@{ - CK_BDVER1, - CK_BDVER2, - CK_BDVER3, - CK_BDVER4, - //@} - - /// \name zen - /// Zen architecture processors. - //@{ - CK_ZNVER1, - //@} - - /// This specification is deprecated and will be removed in the future. - /// Users should prefer \see CK_K8. - // FIXME: Warn on this when the CPU is set to it. - //@{ - CK_x86_64, - //@} - - /// \name Geode - /// Geode processors. - //@{ - CK_Geode - //@} - } CPU = CK_Generic; - - CPUKind getCPUKind(StringRef CPU) const { - return llvm::StringSwitch<CPUKind>(CPU) - .Case("i386", CK_i386) - .Case("i486", CK_i486) - .Case("winchip-c6", CK_WinChipC6) - .Case("winchip2", CK_WinChip2) - .Case("c3", CK_C3) - .Case("i586", CK_i586) - .Case("pentium", CK_Pentium) - .Case("pentium-mmx", CK_PentiumMMX) - .Case("i686", CK_i686) - .Case("pentiumpro", CK_PentiumPro) - .Case("pentium2", CK_Pentium2) - .Case("pentium3", CK_Pentium3) - .Case("pentium3m", CK_Pentium3M) - .Case("pentium-m", CK_PentiumM) - .Case("c3-2", CK_C3_2) - .Case("yonah", CK_Yonah) - .Case("pentium4", CK_Pentium4) - .Case("pentium4m", CK_Pentium4M) - .Case("prescott", CK_Prescott) - .Case("nocona", CK_Nocona) - .Case("core2", CK_Core2) - .Case("penryn", CK_Penryn) - .Case("bonnell", CK_Bonnell) - .Case("atom", CK_Bonnell) // Legacy name. - .Case("silvermont", CK_Silvermont) - .Case("slm", CK_Silvermont) // Legacy name. - .Case("goldmont", CK_Goldmont) - .Case("nehalem", CK_Nehalem) - .Case("corei7", CK_Nehalem) // Legacy name. - .Case("westmere", CK_Westmere) - .Case("sandybridge", CK_SandyBridge) - .Case("corei7-avx", CK_SandyBridge) // Legacy name. - .Case("ivybridge", CK_IvyBridge) - .Case("core-avx-i", CK_IvyBridge) // Legacy name. - .Case("haswell", CK_Haswell) - .Case("core-avx2", CK_Haswell) // Legacy name. - .Case("broadwell", CK_Broadwell) - .Case("skylake", CK_SkylakeClient) - .Case("skylake-avx512", CK_SkylakeServer) - .Case("skx", CK_SkylakeServer) // Legacy name. - .Case("cannonlake", CK_Cannonlake) - .Case("knl", CK_KNL) - .Case("lakemont", CK_Lakemont) - .Case("k6", CK_K6) - .Case("k6-2", CK_K6_2) - .Case("k6-3", CK_K6_3) - .Case("athlon", CK_Athlon) - .Case("athlon-tbird", CK_AthlonThunderbird) - .Case("athlon-4", CK_Athlon4) - .Case("athlon-xp", CK_AthlonXP) - .Case("athlon-mp", CK_AthlonMP) - .Case("athlon64", CK_Athlon64) - .Case("athlon64-sse3", CK_Athlon64SSE3) - .Case("athlon-fx", CK_AthlonFX) - .Case("k8", CK_K8) - .Case("k8-sse3", CK_K8SSE3) - .Case("opteron", CK_Opteron) - .Case("opteron-sse3", CK_OpteronSSE3) - .Case("barcelona", CK_AMDFAM10) - .Case("amdfam10", CK_AMDFAM10) - .Case("btver1", CK_BTVER1) - .Case("btver2", CK_BTVER2) - .Case("bdver1", CK_BDVER1) - .Case("bdver2", CK_BDVER2) - .Case("bdver3", CK_BDVER3) - .Case("bdver4", CK_BDVER4) - .Case("znver1", CK_ZNVER1) - .Case("x86-64", CK_x86_64) - .Case("geode", CK_Geode) - .Default(CK_Generic); - } - - enum FPMathKind { - FP_Default, - FP_SSE, - FP_387 - } FPMath = FP_Default; - -public: - X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); - } - unsigned getFloatEvalMethod() const override { - // X87 evaluates with 80 bits "long double" precision. - return SSELevel == NoSSE ? 2 : 0; - } - ArrayRef<const char *> getGCCRegNames() const override { - return llvm::makeArrayRef(GCCRegNames); - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override { - return llvm::makeArrayRef(AddlRegNames); - } - bool validateCpuSupports(StringRef Name) const override; - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; - - bool validateGlobalRegisterVariable(StringRef RegName, - unsigned RegSize, - bool &HasSizeMismatch) const override { - // esp and ebp are the only 32-bit registers the x86 backend can currently - // handle. - if (RegName.equals("esp") || RegName.equals("ebp")) { - // Check that the register size is 32-bit. - HasSizeMismatch = RegSize != 32; - return true; - } - - return false; - } - - bool validateOutputSize(StringRef Constraint, unsigned Size) const override; - - bool validateInputSize(StringRef Constraint, unsigned Size) const override; - - virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; - - std::string convertConstraint(const char *&Constraint) const override; - const char *getClobbers() const override { - return "~{dirflag},~{fpsr},~{flags}"; - } - - StringRef getConstraintRegister(const StringRef &Constraint, - const StringRef &Expression) const override { - StringRef::iterator I, E; - for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) { - if (isalpha(*I)) - break; - } - if (I == E) - return ""; - switch (*I) { - // For the register constraints, return the matching register name - case 'a': - return "ax"; - case 'b': - return "bx"; - case 'c': - return "cx"; - case 'd': - return "dx"; - case 'S': - return "si"; - case 'D': - return "di"; - // In case the constraint is 'r' we need to return Expression - case 'r': - return Expression; - default: - // Default value if there is no constraint for the register - return ""; - } - return ""; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; - static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level, - bool Enabled); - static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level, - bool Enabled); - static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, - bool Enabled); - void setFeatureEnabled(llvm::StringMap<bool> &Features, - StringRef Name, bool Enabled) const override { - setFeatureEnabledImpl(Features, Name, Enabled); - } - // This exists purely to cut down on the number of virtual calls in - // initFeatureMap which calls this repeatedly. - static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features, - StringRef Name, bool Enabled); - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override; - bool hasFeature(StringRef Feature) const override; - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override; - StringRef getABI() const override { - if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F) - return "avx512"; - if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) - return "avx"; - if (getTriple().getArch() == llvm::Triple::x86 && - MMX3DNowLevel == NoMMX3DNow) - return "no-mmx"; - return ""; - } - bool setCPU(const std::string &Name) override { - CPU = getCPUKind(Name); - - // Perform any per-CPU checks necessary to determine if this CPU is - // acceptable. - // FIXME: This results in terrible diagnostics. Clang just says the CPU is - // invalid without explaining *why*. - switch (CPU) { - case CK_Generic: - // No processor selected! - return false; - - case CK_i386: - case CK_i486: - case CK_WinChipC6: - case CK_WinChip2: - case CK_C3: - case CK_i586: - case CK_Pentium: - case CK_PentiumMMX: - case CK_i686: - case CK_PentiumPro: - case CK_Pentium2: - case CK_Pentium3: - case CK_Pentium3M: - case CK_PentiumM: - case CK_Yonah: - case CK_C3_2: - case CK_Pentium4: - case CK_Pentium4M: - case CK_Lakemont: - case CK_Prescott: - case CK_K6: - case CK_K6_2: - case CK_K6_3: - case CK_Athlon: - case CK_AthlonThunderbird: - case CK_Athlon4: - case CK_AthlonXP: - case CK_AthlonMP: - case CK_Geode: - // Only accept certain architectures when compiling in 32-bit mode. - if (getTriple().getArch() != llvm::Triple::x86) - return false; - - // Fallthrough - case CK_Nocona: - case CK_Core2: - case CK_Penryn: - case CK_Bonnell: - case CK_Silvermont: - case CK_Goldmont: - case CK_Nehalem: - case CK_Westmere: - case CK_SandyBridge: - case CK_IvyBridge: - case CK_Haswell: - case CK_Broadwell: - case CK_SkylakeClient: - case CK_SkylakeServer: - case CK_Cannonlake: - case CK_KNL: - case CK_Athlon64: - case CK_Athlon64SSE3: - case CK_AthlonFX: - case CK_K8: - case CK_K8SSE3: - case CK_Opteron: - case CK_OpteronSSE3: - case CK_AMDFAM10: - case CK_BTVER1: - case CK_BTVER2: - case CK_BDVER1: - case CK_BDVER2: - case CK_BDVER3: - case CK_BDVER4: - case CK_ZNVER1: - case CK_x86_64: - return true; - } - llvm_unreachable("Unhandled CPU kind"); - } - - bool setFPMath(StringRef Name) override; - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - // Most of the non-ARM calling conventions are i386 conventions. - switch (CC) { - case CC_X86ThisCall: - case CC_X86FastCall: - case CC_X86StdCall: - case CC_X86VectorCall: - case CC_X86RegCall: - case CC_C: - case CC_Swift: - case CC_X86Pascal: - case CC_IntelOclBicc: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } - - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { - return MT == CCMT_Member ? CC_X86ThisCall : CC_C; - } - - bool hasSjLjLowering() const override { - return true; - } - - void setSupportedOpenCLOpts() override { - getSupportedOpenCLOpts().supportAll(); - } -}; - -bool X86TargetInfo::setFPMath(StringRef Name) { - if (Name == "387") { - FPMath = FP_387; - return true; - } - if (Name == "sse") { - FPMath = FP_SSE; - return true; - } - return false; -} - -bool X86TargetInfo::initFeatureMap( - llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeaturesVec) const { - // FIXME: This *really* should not be here. - // X86_64 always has SSE2. - if (getTriple().getArch() == llvm::Triple::x86_64) - setFeatureEnabledImpl(Features, "sse2", true); - - const CPUKind Kind = getCPUKind(CPU); - - // Enable X87 for all X86 processors but Lakemont. - if (Kind != CK_Lakemont) - setFeatureEnabledImpl(Features, "x87", true); - - switch (Kind) { - case CK_Generic: - case CK_i386: - case CK_i486: - case CK_i586: - case CK_Pentium: - case CK_i686: - case CK_PentiumPro: - case CK_Lakemont: - break; - case CK_PentiumMMX: - case CK_Pentium2: - case CK_K6: - case CK_WinChipC6: - setFeatureEnabledImpl(Features, "mmx", true); - break; - case CK_Pentium3: - case CK_Pentium3M: - case CK_C3_2: - setFeatureEnabledImpl(Features, "sse", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_PentiumM: - case CK_Pentium4: - case CK_Pentium4M: - case CK_x86_64: - setFeatureEnabledImpl(Features, "sse2", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_Yonah: - case CK_Prescott: - case CK_Nocona: - setFeatureEnabledImpl(Features, "sse3", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "cx16", true); - break; - case CK_Core2: - setFeatureEnabledImpl(Features, "ssse3", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "cx16", true); - break; - case CK_Penryn: - setFeatureEnabledImpl(Features, "sse4.1", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "cx16", true); - break; - case CK_Cannonlake: - setFeatureEnabledImpl(Features, "avx512ifma", true); - setFeatureEnabledImpl(Features, "avx512vbmi", true); - setFeatureEnabledImpl(Features, "sha", true); - LLVM_FALLTHROUGH; - case CK_SkylakeServer: - setFeatureEnabledImpl(Features, "avx512f", true); - setFeatureEnabledImpl(Features, "avx512cd", true); - setFeatureEnabledImpl(Features, "avx512dq", true); - setFeatureEnabledImpl(Features, "avx512bw", true); - setFeatureEnabledImpl(Features, "avx512vl", true); - setFeatureEnabledImpl(Features, "pku", true); - setFeatureEnabledImpl(Features, "clwb", true); - LLVM_FALLTHROUGH; - case CK_SkylakeClient: - setFeatureEnabledImpl(Features, "xsavec", true); - setFeatureEnabledImpl(Features, "xsaves", true); - setFeatureEnabledImpl(Features, "mpx", true); - setFeatureEnabledImpl(Features, "sgx", true); - setFeatureEnabledImpl(Features, "clflushopt", true); - setFeatureEnabledImpl(Features, "rtm", true); - LLVM_FALLTHROUGH; - case CK_Broadwell: - setFeatureEnabledImpl(Features, "rdseed", true); - setFeatureEnabledImpl(Features, "adx", true); - LLVM_FALLTHROUGH; - case CK_Haswell: - setFeatureEnabledImpl(Features, "avx2", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "bmi", true); - setFeatureEnabledImpl(Features, "bmi2", true); - setFeatureEnabledImpl(Features, "fma", true); - setFeatureEnabledImpl(Features, "movbe", true); - LLVM_FALLTHROUGH; - case CK_IvyBridge: - setFeatureEnabledImpl(Features, "rdrnd", true); - setFeatureEnabledImpl(Features, "f16c", true); - setFeatureEnabledImpl(Features, "fsgsbase", true); - LLVM_FALLTHROUGH; - case CK_SandyBridge: - setFeatureEnabledImpl(Features, "avx", true); - setFeatureEnabledImpl(Features, "xsave", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - LLVM_FALLTHROUGH; - case CK_Westmere: - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "pclmul", true); - LLVM_FALLTHROUGH; - case CK_Nehalem: - setFeatureEnabledImpl(Features, "sse4.2", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "cx16", true); - break; - case CK_Goldmont: - setFeatureEnabledImpl(Features, "sha", true); - setFeatureEnabledImpl(Features, "rdrnd", true); - setFeatureEnabledImpl(Features, "rdseed", true); - setFeatureEnabledImpl(Features, "xsave", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - setFeatureEnabledImpl(Features, "xsavec", true); - setFeatureEnabledImpl(Features, "xsaves", true); - setFeatureEnabledImpl(Features, "clflushopt", true); - setFeatureEnabledImpl(Features, "mpx", true); - LLVM_FALLTHROUGH; - case CK_Silvermont: - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "pclmul", true); - setFeatureEnabledImpl(Features, "sse4.2", true); - LLVM_FALLTHROUGH; - case CK_Bonnell: - setFeatureEnabledImpl(Features, "movbe", true); - setFeatureEnabledImpl(Features, "ssse3", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "cx16", true); - break; - case CK_KNL: - setFeatureEnabledImpl(Features, "avx512f", true); - setFeatureEnabledImpl(Features, "avx512cd", true); - setFeatureEnabledImpl(Features, "avx512er", true); - setFeatureEnabledImpl(Features, "avx512pf", true); - setFeatureEnabledImpl(Features, "prefetchwt1", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "rdseed", true); - setFeatureEnabledImpl(Features, "adx", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "bmi", true); - setFeatureEnabledImpl(Features, "bmi2", true); - setFeatureEnabledImpl(Features, "rtm", true); - setFeatureEnabledImpl(Features, "fma", true); - setFeatureEnabledImpl(Features, "rdrnd", true); - setFeatureEnabledImpl(Features, "f16c", true); - setFeatureEnabledImpl(Features, "fsgsbase", true); - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "pclmul", true); - setFeatureEnabledImpl(Features, "cx16", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - setFeatureEnabledImpl(Features, "xsave", true); - setFeatureEnabledImpl(Features, "movbe", true); - break; - case CK_K6_2: - case CK_K6_3: - case CK_WinChip2: - case CK_C3: - setFeatureEnabledImpl(Features, "3dnow", true); - break; - case CK_Athlon: - case CK_AthlonThunderbird: - case CK_Geode: - setFeatureEnabledImpl(Features, "3dnowa", true); - break; - case CK_Athlon4: - case CK_AthlonXP: - case CK_AthlonMP: - setFeatureEnabledImpl(Features, "sse", true); - setFeatureEnabledImpl(Features, "3dnowa", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_K8: - case CK_Opteron: - case CK_Athlon64: - case CK_AthlonFX: - setFeatureEnabledImpl(Features, "sse2", true); - setFeatureEnabledImpl(Features, "3dnowa", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_AMDFAM10: - setFeatureEnabledImpl(Features, "sse4a", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "popcnt", true); - LLVM_FALLTHROUGH; - case CK_K8SSE3: - case CK_OpteronSSE3: - case CK_Athlon64SSE3: - setFeatureEnabledImpl(Features, "sse3", true); - setFeatureEnabledImpl(Features, "3dnowa", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_BTVER2: - setFeatureEnabledImpl(Features, "avx", true); - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "pclmul", true); - setFeatureEnabledImpl(Features, "bmi", true); - setFeatureEnabledImpl(Features, "f16c", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - setFeatureEnabledImpl(Features, "movbe", true); - LLVM_FALLTHROUGH; - case CK_BTVER1: - setFeatureEnabledImpl(Features, "ssse3", true); - setFeatureEnabledImpl(Features, "sse4a", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "popcnt", true); - setFeatureEnabledImpl(Features, "prfchw", true); - setFeatureEnabledImpl(Features, "cx16", true); - setFeatureEnabledImpl(Features, "fxsr", true); - break; - case CK_ZNVER1: - setFeatureEnabledImpl(Features, "adx", true); - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "avx2", true); - setFeatureEnabledImpl(Features, "bmi", true); - setFeatureEnabledImpl(Features, "bmi2", true); - setFeatureEnabledImpl(Features, "clflushopt", true); - setFeatureEnabledImpl(Features, "clzero", true); - setFeatureEnabledImpl(Features, "cx16", true); - setFeatureEnabledImpl(Features, "f16c", true); - setFeatureEnabledImpl(Features, "fma", true); - setFeatureEnabledImpl(Features, "fsgsbase", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "mwaitx", true); - setFeatureEnabledImpl(Features, "movbe", true); - setFeatureEnabledImpl(Features, "pclmul", true); - setFeatureEnabledImpl(Features, "popcnt", true); - setFeatureEnabledImpl(Features, "prfchw", true); - setFeatureEnabledImpl(Features, "rdrnd", true); - setFeatureEnabledImpl(Features, "rdseed", true); - setFeatureEnabledImpl(Features, "sha", true); - setFeatureEnabledImpl(Features, "sse4a", true); - setFeatureEnabledImpl(Features, "xsave", true); - setFeatureEnabledImpl(Features, "xsavec", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - setFeatureEnabledImpl(Features, "xsaves", true); - break; - case CK_BDVER4: - setFeatureEnabledImpl(Features, "avx2", true); - setFeatureEnabledImpl(Features, "bmi2", true); - setFeatureEnabledImpl(Features, "mwaitx", true); - LLVM_FALLTHROUGH; - case CK_BDVER3: - setFeatureEnabledImpl(Features, "fsgsbase", true); - setFeatureEnabledImpl(Features, "xsaveopt", true); - LLVM_FALLTHROUGH; - case CK_BDVER2: - setFeatureEnabledImpl(Features, "bmi", true); - setFeatureEnabledImpl(Features, "fma", true); - setFeatureEnabledImpl(Features, "f16c", true); - setFeatureEnabledImpl(Features, "tbm", true); - LLVM_FALLTHROUGH; - case CK_BDVER1: - // xop implies avx, sse4a and fma4. - setFeatureEnabledImpl(Features, "xop", true); - setFeatureEnabledImpl(Features, "lwp", true); - setFeatureEnabledImpl(Features, "lzcnt", true); - setFeatureEnabledImpl(Features, "aes", true); - setFeatureEnabledImpl(Features, "pclmul", true); - setFeatureEnabledImpl(Features, "prfchw", true); - setFeatureEnabledImpl(Features, "cx16", true); - setFeatureEnabledImpl(Features, "fxsr", true); - setFeatureEnabledImpl(Features, "xsave", true); - break; - } - if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) - return false; - - // Can't do this earlier because we need to be able to explicitly enable - // or disable these features and the things that they depend upon. - - // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. - auto I = Features.find("sse4.2"); - if (I != Features.end() && I->getValue() && - std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") == - FeaturesVec.end()) - Features["popcnt"] = true; - - // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. - I = Features.find("3dnow"); - if (I != Features.end() && I->getValue() && - std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") == - FeaturesVec.end()) - Features["prfchw"] = true; - - // Additionally, if SSE is enabled and mmx is not explicitly disabled, - // then enable MMX. - I = Features.find("sse"); - if (I != Features.end() && I->getValue() && - std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") == - FeaturesVec.end()) - Features["mmx"] = true; - - return true; -} - -void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, - X86SSEEnum Level, bool Enabled) { - if (Enabled) { - switch (Level) { - case AVX512F: - Features["avx512f"] = true; - LLVM_FALLTHROUGH; - case AVX2: - Features["avx2"] = true; - LLVM_FALLTHROUGH; - case AVX: - Features["avx"] = true; - Features["xsave"] = true; - LLVM_FALLTHROUGH; - case SSE42: - Features["sse4.2"] = true; - LLVM_FALLTHROUGH; - case SSE41: - Features["sse4.1"] = true; - LLVM_FALLTHROUGH; - case SSSE3: - Features["ssse3"] = true; - LLVM_FALLTHROUGH; - case SSE3: - Features["sse3"] = true; - LLVM_FALLTHROUGH; - case SSE2: - Features["sse2"] = true; - LLVM_FALLTHROUGH; - case SSE1: - Features["sse"] = true; - LLVM_FALLTHROUGH; - case NoSSE: - break; - } - return; - } - - switch (Level) { - case NoSSE: - case SSE1: - Features["sse"] = false; - LLVM_FALLTHROUGH; - case SSE2: - Features["sse2"] = Features["pclmul"] = Features["aes"] = - Features["sha"] = false; - LLVM_FALLTHROUGH; - case SSE3: - Features["sse3"] = false; - setXOPLevel(Features, NoXOP, false); - LLVM_FALLTHROUGH; - case SSSE3: - Features["ssse3"] = false; - LLVM_FALLTHROUGH; - case SSE41: - Features["sse4.1"] = false; - LLVM_FALLTHROUGH; - case SSE42: - Features["sse4.2"] = false; - LLVM_FALLTHROUGH; - case AVX: - Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = - Features["xsaveopt"] = false; - setXOPLevel(Features, FMA4, false); - LLVM_FALLTHROUGH; - case AVX2: - Features["avx2"] = false; - LLVM_FALLTHROUGH; - case AVX512F: - Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = - Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = - Features["avx512vl"] = Features["avx512vbmi"] = - Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; - break; - } -} - -void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, - MMX3DNowEnum Level, bool Enabled) { - if (Enabled) { - switch (Level) { - case AMD3DNowAthlon: - Features["3dnowa"] = true; - LLVM_FALLTHROUGH; - case AMD3DNow: - Features["3dnow"] = true; - LLVM_FALLTHROUGH; - case MMX: - Features["mmx"] = true; - LLVM_FALLTHROUGH; - case NoMMX3DNow: - break; - } - return; - } - - switch (Level) { - case NoMMX3DNow: - case MMX: - Features["mmx"] = false; - LLVM_FALLTHROUGH; - case AMD3DNow: - Features["3dnow"] = false; - LLVM_FALLTHROUGH; - case AMD3DNowAthlon: - Features["3dnowa"] = false; - break; - } -} - -void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, - bool Enabled) { - if (Enabled) { - switch (Level) { - case XOP: - Features["xop"] = true; - LLVM_FALLTHROUGH; - case FMA4: - Features["fma4"] = true; - setSSELevel(Features, AVX, true); - LLVM_FALLTHROUGH; - case SSE4A: - Features["sse4a"] = true; - setSSELevel(Features, SSE3, true); - LLVM_FALLTHROUGH; - case NoXOP: - break; - } - return; - } - - switch (Level) { - case NoXOP: - case SSE4A: - Features["sse4a"] = false; - LLVM_FALLTHROUGH; - case FMA4: - Features["fma4"] = false; - LLVM_FALLTHROUGH; - case XOP: - Features["xop"] = false; - break; - } -} - -void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, - StringRef Name, bool Enabled) { - // This is a bit of a hack to deal with the sse4 target feature when used - // as part of the target attribute. We handle sse4 correctly everywhere - // else. See below for more information on how we handle the sse4 options. - if (Name != "sse4") - Features[Name] = Enabled; - - if (Name == "mmx") { - setMMXLevel(Features, MMX, Enabled); - } else if (Name == "sse") { - setSSELevel(Features, SSE1, Enabled); - } else if (Name == "sse2") { - setSSELevel(Features, SSE2, Enabled); - } else if (Name == "sse3") { - setSSELevel(Features, SSE3, Enabled); - } else if (Name == "ssse3") { - setSSELevel(Features, SSSE3, Enabled); - } else if (Name == "sse4.2") { - setSSELevel(Features, SSE42, Enabled); - } else if (Name == "sse4.1") { - setSSELevel(Features, SSE41, Enabled); - } else if (Name == "3dnow") { - setMMXLevel(Features, AMD3DNow, Enabled); - } else if (Name == "3dnowa") { - setMMXLevel(Features, AMD3DNowAthlon, Enabled); - } else if (Name == "aes") { - if (Enabled) - setSSELevel(Features, SSE2, Enabled); - } else if (Name == "pclmul") { - if (Enabled) - setSSELevel(Features, SSE2, Enabled); - } else if (Name == "avx") { - setSSELevel(Features, AVX, Enabled); - } else if (Name == "avx2") { - setSSELevel(Features, AVX2, Enabled); - } else if (Name == "avx512f") { - setSSELevel(Features, AVX512F, Enabled); - } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" || - Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" || - Name == "avx512vbmi" || Name == "avx512ifma" || - Name == "avx512vpopcntdq") { - if (Enabled) - setSSELevel(Features, AVX512F, Enabled); - // Enable BWI instruction if VBMI is being enabled. - if (Name == "avx512vbmi" && Enabled) - Features["avx512bw"] = true; - // Also disable VBMI if BWI is being disabled. - if (Name == "avx512bw" && !Enabled) - Features["avx512vbmi"] = false; - } else if (Name == "fma") { - if (Enabled) - setSSELevel(Features, AVX, Enabled); - } else if (Name == "fma4") { - setXOPLevel(Features, FMA4, Enabled); - } else if (Name == "xop") { - setXOPLevel(Features, XOP, Enabled); - } else if (Name == "sse4a") { - setXOPLevel(Features, SSE4A, Enabled); - } else if (Name == "f16c") { - if (Enabled) - setSSELevel(Features, AVX, Enabled); - } else if (Name == "sha") { - if (Enabled) - setSSELevel(Features, SSE2, Enabled); - } else if (Name == "sse4") { - // We can get here via the __target__ attribute since that's not controlled - // via the -msse4/-mno-sse4 command line alias. Handle this the same way - // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if - // disabled. - if (Enabled) - setSSELevel(Features, SSE42, Enabled); - else - setSSELevel(Features, SSE41, Enabled); - } else if (Name == "xsave") { - if (!Enabled) - Features["xsaveopt"] = false; - } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { - if (Enabled) - Features["xsave"] = true; - } -} - -/// handleTargetFeatures - Perform initialization based on the user -/// configured set of features. -bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) { - for (const auto &Feature : Features) { - if (Feature[0] != '+') - continue; - - if (Feature == "+aes") { - HasAES = true; - } else if (Feature == "+pclmul") { - HasPCLMUL = true; - } else if (Feature == "+lzcnt") { - HasLZCNT = true; - } else if (Feature == "+rdrnd") { - HasRDRND = true; - } else if (Feature == "+fsgsbase") { - HasFSGSBASE = true; - } else if (Feature == "+bmi") { - HasBMI = true; - } else if (Feature == "+bmi2") { - HasBMI2 = true; - } else if (Feature == "+popcnt") { - HasPOPCNT = true; - } else if (Feature == "+rtm") { - HasRTM = true; - } else if (Feature == "+prfchw") { - HasPRFCHW = true; - } else if (Feature == "+rdseed") { - HasRDSEED = true; - } else if (Feature == "+adx") { - HasADX = true; - } else if (Feature == "+tbm") { - HasTBM = true; - } else if (Feature == "+lwp") { - HasLWP = true; - } else if (Feature == "+fma") { - HasFMA = true; - } else if (Feature == "+f16c") { - HasF16C = true; - } else if (Feature == "+avx512cd") { - HasAVX512CD = true; - } else if (Feature == "+avx512vpopcntdq") { - HasAVX512VPOPCNTDQ = true; - } else if (Feature == "+avx512er") { - HasAVX512ER = true; - } else if (Feature == "+avx512pf") { - HasAVX512PF = true; - } else if (Feature == "+avx512dq") { - HasAVX512DQ = true; - } else if (Feature == "+avx512bw") { - HasAVX512BW = true; - } else if (Feature == "+avx512vl") { - HasAVX512VL = true; - } else if (Feature == "+avx512vbmi") { - HasAVX512VBMI = true; - } else if (Feature == "+avx512ifma") { - HasAVX512IFMA = true; - } else if (Feature == "+sha") { - HasSHA = true; - } else if (Feature == "+mpx") { - HasMPX = true; - } else if (Feature == "+movbe") { - HasMOVBE = true; - } else if (Feature == "+sgx") { - HasSGX = true; - } else if (Feature == "+cx16") { - HasCX16 = true; - } else if (Feature == "+fxsr") { - HasFXSR = true; - } else if (Feature == "+xsave") { - HasXSAVE = true; - } else if (Feature == "+xsaveopt") { - HasXSAVEOPT = true; - } else if (Feature == "+xsavec") { - HasXSAVEC = true; - } else if (Feature == "+xsaves") { - HasXSAVES = true; - } else if (Feature == "+mwaitx") { - HasMWAITX = true; - } else if (Feature == "+pku") { - HasPKU = true; - } else if (Feature == "+clflushopt") { - HasCLFLUSHOPT = true; - } else if (Feature == "+clwb") { - HasCLWB = true; - } else if (Feature == "+prefetchwt1") { - HasPREFETCHWT1 = true; - } else if (Feature == "+clzero") { - HasCLZERO = true; - } - - X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature) - .Case("+avx512f", AVX512F) - .Case("+avx2", AVX2) - .Case("+avx", AVX) - .Case("+sse4.2", SSE42) - .Case("+sse4.1", SSE41) - .Case("+ssse3", SSSE3) - .Case("+sse3", SSE3) - .Case("+sse2", SSE2) - .Case("+sse", SSE1) - .Default(NoSSE); - SSELevel = std::max(SSELevel, Level); - - MMX3DNowEnum ThreeDNowLevel = - llvm::StringSwitch<MMX3DNowEnum>(Feature) - .Case("+3dnowa", AMD3DNowAthlon) - .Case("+3dnow", AMD3DNow) - .Case("+mmx", MMX) - .Default(NoMMX3DNow); - MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); - - XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature) - .Case("+xop", XOP) - .Case("+fma4", FMA4) - .Case("+sse4a", SSE4A) - .Default(NoXOP); - XOPLevel = std::max(XOPLevel, XLevel); - } - - // LLVM doesn't have a separate switch for fpmath, so only accept it if it - // matches the selected sse level. - if ((FPMath == FP_SSE && SSELevel < SSE1) || - (FPMath == FP_387 && SSELevel >= SSE1)) { - Diags.Report(diag::err_target_unsupported_fpmath) << - (FPMath == FP_SSE ? "sse" : "387"); - return false; - } - - SimdDefaultAlign = - hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; - return true; -} - -/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro -/// definitions for this particular subtarget. -void X86TargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - // Target identification. - if (getTriple().getArch() == llvm::Triple::x86_64) { - Builder.defineMacro("__amd64__"); - Builder.defineMacro("__amd64"); - Builder.defineMacro("__x86_64"); - Builder.defineMacro("__x86_64__"); - if (getTriple().getArchName() == "x86_64h") { - Builder.defineMacro("__x86_64h"); - Builder.defineMacro("__x86_64h__"); - } - } else { - DefineStd(Builder, "i386", Opts); - } - - // Subtarget options. - // FIXME: We are hard-coding the tune parameters based on the CPU, but they - // truly should be based on -mtune options. - switch (CPU) { - case CK_Generic: - break; - case CK_i386: - // The rest are coming from the i386 define above. - Builder.defineMacro("__tune_i386__"); - break; - case CK_i486: - case CK_WinChipC6: - case CK_WinChip2: - case CK_C3: - defineCPUMacros(Builder, "i486"); - break; - case CK_PentiumMMX: - Builder.defineMacro("__pentium_mmx__"); - Builder.defineMacro("__tune_pentium_mmx__"); - LLVM_FALLTHROUGH; - case CK_i586: - case CK_Pentium: - defineCPUMacros(Builder, "i586"); - defineCPUMacros(Builder, "pentium"); - break; - case CK_Pentium3: - case CK_Pentium3M: - case CK_PentiumM: - Builder.defineMacro("__tune_pentium3__"); - LLVM_FALLTHROUGH; - case CK_Pentium2: - case CK_C3_2: - Builder.defineMacro("__tune_pentium2__"); - LLVM_FALLTHROUGH; - case CK_PentiumPro: - Builder.defineMacro("__tune_i686__"); - Builder.defineMacro("__tune_pentiumpro__"); - LLVM_FALLTHROUGH; - case CK_i686: - Builder.defineMacro("__i686"); - Builder.defineMacro("__i686__"); - // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686. - Builder.defineMacro("__pentiumpro"); - Builder.defineMacro("__pentiumpro__"); - break; - case CK_Pentium4: - case CK_Pentium4M: - defineCPUMacros(Builder, "pentium4"); - break; - case CK_Yonah: - case CK_Prescott: - case CK_Nocona: - defineCPUMacros(Builder, "nocona"); - break; - case CK_Core2: - case CK_Penryn: - defineCPUMacros(Builder, "core2"); - break; - case CK_Bonnell: - defineCPUMacros(Builder, "atom"); - break; - case CK_Silvermont: - defineCPUMacros(Builder, "slm"); - break; - case CK_Goldmont: - defineCPUMacros(Builder, "goldmont"); - break; - case CK_Nehalem: - case CK_Westmere: - case CK_SandyBridge: - case CK_IvyBridge: - case CK_Haswell: - case CK_Broadwell: - case CK_SkylakeClient: - // FIXME: Historically, we defined this legacy name, it would be nice to - // remove it at some point. We've never exposed fine-grained names for - // recent primary x86 CPUs, and we should keep it that way. - defineCPUMacros(Builder, "corei7"); - break; - case CK_SkylakeServer: - defineCPUMacros(Builder, "skx"); - break; - case CK_Cannonlake: - break; - case CK_KNL: - defineCPUMacros(Builder, "knl"); - break; - case CK_Lakemont: - Builder.defineMacro("__tune_lakemont__"); - break; - case CK_K6_2: - Builder.defineMacro("__k6_2__"); - Builder.defineMacro("__tune_k6_2__"); - LLVM_FALLTHROUGH; - case CK_K6_3: - if (CPU != CK_K6_2) { // In case of fallthrough - // FIXME: GCC may be enabling these in cases where some other k6 - // architecture is specified but -m3dnow is explicitly provided. The - // exact semantics need to be determined and emulated here. - Builder.defineMacro("__k6_3__"); - Builder.defineMacro("__tune_k6_3__"); - } - LLVM_FALLTHROUGH; - case CK_K6: - defineCPUMacros(Builder, "k6"); - break; - case CK_Athlon: - case CK_AthlonThunderbird: - case CK_Athlon4: - case CK_AthlonXP: - case CK_AthlonMP: - defineCPUMacros(Builder, "athlon"); - if (SSELevel != NoSSE) { - Builder.defineMacro("__athlon_sse__"); - Builder.defineMacro("__tune_athlon_sse__"); - } - break; - case CK_K8: - case CK_K8SSE3: - case CK_x86_64: - case CK_Opteron: - case CK_OpteronSSE3: - case CK_Athlon64: - case CK_Athlon64SSE3: - case CK_AthlonFX: - defineCPUMacros(Builder, "k8"); - break; - case CK_AMDFAM10: - defineCPUMacros(Builder, "amdfam10"); - break; - case CK_BTVER1: - defineCPUMacros(Builder, "btver1"); - break; - case CK_BTVER2: - defineCPUMacros(Builder, "btver2"); - break; - case CK_BDVER1: - defineCPUMacros(Builder, "bdver1"); - break; - case CK_BDVER2: - defineCPUMacros(Builder, "bdver2"); - break; - case CK_BDVER3: - defineCPUMacros(Builder, "bdver3"); - break; - case CK_BDVER4: - defineCPUMacros(Builder, "bdver4"); - break; - case CK_ZNVER1: - defineCPUMacros(Builder, "znver1"); - break; - case CK_Geode: - defineCPUMacros(Builder, "geode"); - break; - } - - // Target properties. - Builder.defineMacro("__REGISTER_PREFIX__", ""); - - // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline - // functions in glibc header files that use FP Stack inline asm which the - // backend can't deal with (PR879). - Builder.defineMacro("__NO_MATH_INLINES"); - - if (HasAES) - Builder.defineMacro("__AES__"); - - if (HasPCLMUL) - Builder.defineMacro("__PCLMUL__"); - - if (HasLZCNT) - Builder.defineMacro("__LZCNT__"); - - if (HasRDRND) - Builder.defineMacro("__RDRND__"); - - if (HasFSGSBASE) - Builder.defineMacro("__FSGSBASE__"); - - if (HasBMI) - Builder.defineMacro("__BMI__"); - - if (HasBMI2) - Builder.defineMacro("__BMI2__"); - - if (HasPOPCNT) - Builder.defineMacro("__POPCNT__"); - - if (HasRTM) - Builder.defineMacro("__RTM__"); - - if (HasPRFCHW) - Builder.defineMacro("__PRFCHW__"); - - if (HasRDSEED) - Builder.defineMacro("__RDSEED__"); - - if (HasADX) - Builder.defineMacro("__ADX__"); - - if (HasTBM) - Builder.defineMacro("__TBM__"); - - if (HasLWP) - Builder.defineMacro("__LWP__"); - - if (HasMWAITX) - Builder.defineMacro("__MWAITX__"); - - switch (XOPLevel) { - case XOP: - Builder.defineMacro("__XOP__"); - LLVM_FALLTHROUGH; - case FMA4: - Builder.defineMacro("__FMA4__"); - LLVM_FALLTHROUGH; - case SSE4A: - Builder.defineMacro("__SSE4A__"); - LLVM_FALLTHROUGH; - case NoXOP: - break; - } - - if (HasFMA) - Builder.defineMacro("__FMA__"); - - if (HasF16C) - Builder.defineMacro("__F16C__"); - - if (HasAVX512CD) - Builder.defineMacro("__AVX512CD__"); - if (HasAVX512VPOPCNTDQ) - Builder.defineMacro("__AVX512VPOPCNTDQ__"); - if (HasAVX512ER) - Builder.defineMacro("__AVX512ER__"); - if (HasAVX512PF) - Builder.defineMacro("__AVX512PF__"); - if (HasAVX512DQ) - Builder.defineMacro("__AVX512DQ__"); - if (HasAVX512BW) - Builder.defineMacro("__AVX512BW__"); - if (HasAVX512VL) - Builder.defineMacro("__AVX512VL__"); - if (HasAVX512VBMI) - Builder.defineMacro("__AVX512VBMI__"); - if (HasAVX512IFMA) - Builder.defineMacro("__AVX512IFMA__"); - - if (HasSHA) - Builder.defineMacro("__SHA__"); - - if (HasFXSR) - Builder.defineMacro("__FXSR__"); - if (HasXSAVE) - Builder.defineMacro("__XSAVE__"); - if (HasXSAVEOPT) - Builder.defineMacro("__XSAVEOPT__"); - if (HasXSAVEC) - Builder.defineMacro("__XSAVEC__"); - if (HasXSAVES) - Builder.defineMacro("__XSAVES__"); - if (HasPKU) - Builder.defineMacro("__PKU__"); - if (HasCX16) - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); - if (HasCLFLUSHOPT) - Builder.defineMacro("__CLFLUSHOPT__"); - if (HasCLWB) - Builder.defineMacro("__CLWB__"); - if (HasMPX) - Builder.defineMacro("__MPX__"); - if (HasSGX) - Builder.defineMacro("__SGX__"); - if (HasPREFETCHWT1) - Builder.defineMacro("__PREFETCHWT1__"); - if (HasCLZERO) - Builder.defineMacro("__CLZERO__"); - - // Each case falls through to the previous one here. - switch (SSELevel) { - case AVX512F: - Builder.defineMacro("__AVX512F__"); - LLVM_FALLTHROUGH; - case AVX2: - Builder.defineMacro("__AVX2__"); - LLVM_FALLTHROUGH; - case AVX: - Builder.defineMacro("__AVX__"); - LLVM_FALLTHROUGH; - case SSE42: - Builder.defineMacro("__SSE4_2__"); - LLVM_FALLTHROUGH; - case SSE41: - Builder.defineMacro("__SSE4_1__"); - LLVM_FALLTHROUGH; - case SSSE3: - Builder.defineMacro("__SSSE3__"); - LLVM_FALLTHROUGH; - case SSE3: - Builder.defineMacro("__SSE3__"); - LLVM_FALLTHROUGH; - case SSE2: - Builder.defineMacro("__SSE2__"); - Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. - LLVM_FALLTHROUGH; - case SSE1: - Builder.defineMacro("__SSE__"); - Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. - LLVM_FALLTHROUGH; - case NoSSE: - break; - } - - if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { - switch (SSELevel) { - case AVX512F: - case AVX2: - case AVX: - case SSE42: - case SSE41: - case SSSE3: - case SSE3: - case SSE2: - Builder.defineMacro("_M_IX86_FP", Twine(2)); - break; - case SSE1: - Builder.defineMacro("_M_IX86_FP", Twine(1)); - break; - default: - Builder.defineMacro("_M_IX86_FP", Twine(0)); - break; - } - } - - // Each case falls through to the previous one here. - switch (MMX3DNowLevel) { - case AMD3DNowAthlon: - Builder.defineMacro("__3dNOW_A__"); - LLVM_FALLTHROUGH; - case AMD3DNow: - Builder.defineMacro("__3dNOW__"); - LLVM_FALLTHROUGH; - case MMX: - Builder.defineMacro("__MMX__"); - LLVM_FALLTHROUGH; - case NoMMX3DNow: - break; - } - - if (CPU >= CK_i486) { - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - } - if (CPU >= CK_i586) - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - - if (HasFloat128) - Builder.defineMacro("__SIZEOF_FLOAT128__", "16"); -} - -bool X86TargetInfo::hasFeature(StringRef Feature) const { - return llvm::StringSwitch<bool>(Feature) - .Case("aes", HasAES) - .Case("avx", SSELevel >= AVX) - .Case("avx2", SSELevel >= AVX2) - .Case("avx512f", SSELevel >= AVX512F) - .Case("avx512cd", HasAVX512CD) - .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) - .Case("avx512er", HasAVX512ER) - .Case("avx512pf", HasAVX512PF) - .Case("avx512dq", HasAVX512DQ) - .Case("avx512bw", HasAVX512BW) - .Case("avx512vl", HasAVX512VL) - .Case("avx512vbmi", HasAVX512VBMI) - .Case("avx512ifma", HasAVX512IFMA) - .Case("bmi", HasBMI) - .Case("bmi2", HasBMI2) - .Case("clflushopt", HasCLFLUSHOPT) - .Case("clwb", HasCLWB) - .Case("clzero", HasCLZERO) - .Case("cx16", HasCX16) - .Case("f16c", HasF16C) - .Case("fma", HasFMA) - .Case("fma4", XOPLevel >= FMA4) - .Case("fsgsbase", HasFSGSBASE) - .Case("fxsr", HasFXSR) - .Case("lzcnt", HasLZCNT) - .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) - .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) - .Case("mmx", MMX3DNowLevel >= MMX) - .Case("movbe", HasMOVBE) - .Case("mpx", HasMPX) - .Case("pclmul", HasPCLMUL) - .Case("pku", HasPKU) - .Case("popcnt", HasPOPCNT) - .Case("prefetchwt1", HasPREFETCHWT1) - .Case("prfchw", HasPRFCHW) - .Case("rdrnd", HasRDRND) - .Case("rdseed", HasRDSEED) - .Case("rtm", HasRTM) - .Case("sgx", HasSGX) - .Case("sha", HasSHA) - .Case("sse", SSELevel >= SSE1) - .Case("sse2", SSELevel >= SSE2) - .Case("sse3", SSELevel >= SSE3) - .Case("ssse3", SSELevel >= SSSE3) - .Case("sse4.1", SSELevel >= SSE41) - .Case("sse4.2", SSELevel >= SSE42) - .Case("sse4a", XOPLevel >= SSE4A) - .Case("tbm", HasTBM) - .Case("lwp", HasLWP) - .Case("x86", true) - .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) - .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) - .Case("xop", XOPLevel >= XOP) - .Case("xsave", HasXSAVE) - .Case("xsavec", HasXSAVEC) - .Case("xsaves", HasXSAVES) - .Case("xsaveopt", HasXSAVEOPT) - .Default(false); -} - -// We can't use a generic validation scheme for the features accepted here -// versus subtarget features accepted in the target attribute because the -// bitfield structure that's initialized in the runtime only supports the -// below currently rather than the full range of subtarget features. (See -// X86TargetInfo::hasFeature for a somewhat comprehensive list). -bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { - return llvm::StringSwitch<bool>(FeatureStr) - .Case("cmov", true) - .Case("mmx", true) - .Case("popcnt", true) - .Case("sse", true) - .Case("sse2", true) - .Case("sse3", true) - .Case("ssse3", true) - .Case("sse4.1", true) - .Case("sse4.2", true) - .Case("avx", true) - .Case("avx2", true) - .Case("sse4a", true) - .Case("fma4", true) - .Case("xop", true) - .Case("fma", true) - .Case("avx512f", true) - .Case("bmi", true) - .Case("bmi2", true) - .Case("aes", true) - .Case("pclmul", true) - .Case("avx512vl", true) - .Case("avx512bw", true) - .Case("avx512dq", true) - .Case("avx512cd", true) - .Case("avx512vpopcntdq", true) - .Case("avx512er", true) - .Case("avx512pf", true) - .Case("avx512vbmi", true) - .Case("avx512ifma", true) - .Default(false); -} - -bool -X86TargetInfo::validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const { - switch (*Name) { - default: return false; - // Constant constraints. - case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 - // instructions. - case 'Z': // 32-bit unsigned integer constant for use with zero-extending - // x86_64 instructions. - case 's': - Info.setRequiresImmediate(); - return true; - case 'I': - Info.setRequiresImmediate(0, 31); - return true; - case 'J': - Info.setRequiresImmediate(0, 63); - return true; - case 'K': - Info.setRequiresImmediate(-128, 127); - return true; - case 'L': - Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) }); - return true; - case 'M': - Info.setRequiresImmediate(0, 3); - return true; - case 'N': - Info.setRequiresImmediate(0, 255); - return true; - case 'O': - Info.setRequiresImmediate(0, 127); - return true; - // Register constraints. - case 'Y': // 'Y' is the first character for several 2-character constraints. - // Shift the pointer to the second character of the constraint. - Name++; - switch (*Name) { - default: - return false; - case '0': // First SSE register. - case 't': // Any SSE register, when SSE2 is enabled. - case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. - case 'm': // Any MMX register, when inter-unit moves enabled. - case 'k': // AVX512 arch mask registers: k1-k7. - Info.setAllowsRegister(); - return true; - } - case 'f': // Any x87 floating point stack register. - // Constraint 'f' cannot be used for output operands. - if (Info.ConstraintStr[0] == '=') - return false; - Info.setAllowsRegister(); - return true; - case 'a': // eax. - case 'b': // ebx. - case 'c': // ecx. - case 'd': // edx. - case 'S': // esi. - case 'D': // edi. - case 'A': // edx:eax. - case 't': // Top of floating point stack. - case 'u': // Second from top of floating point stack. - case 'q': // Any register accessible as [r]l: a, b, c, and d. - case 'y': // Any MMX register. - case 'v': // Any {X,Y,Z}MM register (Arch & context dependent) - case 'x': // Any SSE register. - case 'k': // Any AVX512 mask register (same as Yk, additionaly allows k0 - // for intermideate k reg operations). - case 'Q': // Any register accessible as [r]h: a, b, c, and d. - case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. - case 'l': // "Index" registers: any general register that can be used as an - // index in a base+index memory access. - Info.setAllowsRegister(); - return true; - // Floating point constant constraints. - case 'C': // SSE floating point constant. - case 'G': // x87 floating point constant. - return true; - } -} - -bool X86TargetInfo::validateOutputSize(StringRef Constraint, - unsigned Size) const { - // Strip off constraint modifiers. - while (Constraint[0] == '=' || - Constraint[0] == '+' || - Constraint[0] == '&') - Constraint = Constraint.substr(1); - - return validateOperandSize(Constraint, Size); -} - -bool X86TargetInfo::validateInputSize(StringRef Constraint, - unsigned Size) const { - return validateOperandSize(Constraint, Size); -} - -bool X86TargetInfo::validateOperandSize(StringRef Constraint, - unsigned Size) const { - switch (Constraint[0]) { - default: break; - case 'k': - // Registers k0-k7 (AVX512) size limit is 64 bit. - case 'y': - return Size <= 64; - case 'f': - case 't': - case 'u': - return Size <= 128; - case 'v': - case 'x': - if (SSELevel >= AVX512F) - // 512-bit zmm registers can be used if target supports AVX512F. - return Size <= 512U; - else if (SSELevel >= AVX) - // 256-bit ymm registers can be used if target supports AVX. - return Size <= 256U; - return Size <= 128U; - case 'Y': - // 'Y' is the first character for several 2-character constraints. - switch (Constraint[1]) { - default: break; - case 'm': - // 'Ym' is synonymous with 'y'. - case 'k': - return Size <= 64; - case 'i': - case 't': - // 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled. - if (SSELevel >= AVX512F) - return Size <= 512U; - else if (SSELevel >= AVX) - return Size <= 256U; - return SSELevel >= SSE2 && Size <= 128U; - } - - } - - return true; -} - -std::string -X86TargetInfo::convertConstraint(const char *&Constraint) const { - switch (*Constraint) { - case 'a': return std::string("{ax}"); - case 'b': return std::string("{bx}"); - case 'c': return std::string("{cx}"); - case 'd': return std::string("{dx}"); - case 'S': return std::string("{si}"); - case 'D': return std::string("{di}"); - case 'p': // address - return std::string("im"); - case 't': // top of floating point stack. - return std::string("{st}"); - case 'u': // second from top of floating point stack. - return std::string("{st(1)}"); // second from top of floating point stack. - case 'Y': - switch (Constraint[1]) { - default: - // Break from inner switch and fall through (copy single char), - // continue parsing after copying the current constraint into - // the return string. - break; - case 'k': - // "^" hints llvm that this is a 2 letter constraint. - // "Constraint++" is used to promote the string iterator - // to the next constraint. - return std::string("^") + std::string(Constraint++, 2); - } - LLVM_FALLTHROUGH; - default: - return std::string(1, *Constraint); - } -} - -// X86-32 generic target -class X86_32TargetInfo : public X86TargetInfo { -public: - X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86TargetInfo(Triple, Opts) { - DoubleAlign = LongLongAlign = 32; - LongDoubleWidth = 96; - LongDoubleAlign = 32; - SuitableAlign = 128; - resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"); - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - RegParmMax = 3; - - // Use fpret for all types. - RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) | - (1 << TargetInfo::Double) | - (1 << TargetInfo::LongDouble)); - - // x86-32 has atomics up to 8 bytes - // FIXME: Check that we actually have cmpxchg8b before setting - // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 0; - if (RegNo == 1) return 2; - return -1; - } - bool validateOperandSize(StringRef Constraint, - unsigned Size) const override { - switch (Constraint[0]) { - default: break; - case 'R': - case 'q': - case 'Q': - case 'a': - case 'b': - case 'c': - case 'd': - case 'S': - case 'D': - return Size <= 32; - case 'A': - return Size <= 64; - } - - return X86TargetInfo::validateOperandSize(Constraint, Size); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin - - Builtin::FirstTSBuiltin + 1); - } -}; - -class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> { -public: - NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {} - - unsigned getFloatEvalMethod() const override { - unsigned Major, Minor, Micro; - getTriple().getOSVersion(Major, Minor, Micro); - // New NetBSD uses the default rounding mode. - if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0) - return X86_32TargetInfo::getFloatEvalMethod(); - // NetBSD before 6.99.26 defaults to "double" rounding. - return 1; - } -}; - -class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> { -public: - OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) { - SizeType = UnsignedLong; - IntPtrType = SignedLong; - PtrDiffType = SignedLong; - } -}; - -class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> { -public: - BitrigI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : BitrigTargetInfo<X86_32TargetInfo>(Triple, Opts) { - SizeType = UnsignedLong; - IntPtrType = SignedLong; - PtrDiffType = SignedLong; - } -}; - -class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> { -public: - DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) { - LongDoubleWidth = 128; - LongDoubleAlign = 128; - SuitableAlign = 128; - MaxVectorAlign = 256; - // The watchOS simulator uses the builtin bool type for Objective-C. - llvm::Triple T = llvm::Triple(Triple); - if (T.isWatchOS()) - UseSignedCharForObjCBool = false; - SizeType = UnsignedLong; - IntPtrType = SignedLong; - resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"); - HasAlignMac68kSupport = true; - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features, - Diags)) - return false; - // We now know the features we have: we can decide how to align vectors. - MaxVectorAlign = - hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; - return true; - } -}; - -// x86-32 Windows target -class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> { -public: - WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) { - WCharType = UnsignedShort; - DoubleAlign = LongLongAlign = 64; - bool IsWinCOFF = - getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); - resetDataLayout(IsWinCOFF - ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" - : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder); - } -}; - -// x86-32 Windows Visual Studio target -class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo { -public: - MicrosoftX86_32TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : WindowsX86_32TargetInfo(Triple, Opts) { - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); - WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder); - // The value of the following reflects processor type. - // 300=386, 400=486, 500=Pentium, 600=Blend (default) - // We lost the original triple, so we use the default. - Builder.defineMacro("_M_IX86", "600"); - } -}; - -static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { +void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { // Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang // supports __declspec natively under -fms-extensions, but we define a no-op // __declspec macro anyway for pre-processor compatibility. @@ -4712,4819 +97,25 @@ static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { } } -static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { - Builder.defineMacro("__MSVCRT__"); - Builder.defineMacro("__MINGW32__"); - addCygMingDefines(Opts, Builder); -} - -// x86-32 MinGW target -class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { -public: - MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsX86_32TargetInfo(Triple, Opts) { - HasFloat128 = true; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); - DefineStd(Builder, "WIN32", Opts); - DefineStd(Builder, "WINNT", Opts); - Builder.defineMacro("_X86_"); - addMinGWDefines(Opts, Builder); - } -}; - -// x86-32 Cygwin target -class CygwinX86_32TargetInfo : public X86_32TargetInfo { -public: - CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86_32TargetInfo(Triple, Opts) { - WCharType = UnsignedShort; - DoubleAlign = LongLongAlign = 64; - resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - X86_32TargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("_X86_"); - Builder.defineMacro("__CYGWIN__"); - Builder.defineMacro("__CYGWIN32__"); - addCygMingDefines(Opts, Builder); - DefineStd(Builder, "unix", Opts); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - } -}; - -// x86-32 Haiku target -class HaikuX86_32TargetInfo : public HaikuTargetInfo<X86_32TargetInfo> { -public: - HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) { - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder); - Builder.defineMacro("__INTEL__"); - } -}; - -// X86-32 MCU target -class MCUX86_32TargetInfo : public X86_32TargetInfo { -public: - MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86_32TargetInfo(Triple, Opts) { - LongDoubleWidth = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32"); - WIntType = UnsignedInt; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - // On MCU we support only C calling convention. - return CC == CC_C ? CCCR_OK : CCCR_Warning; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - X86_32TargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("__iamcu"); - Builder.defineMacro("__iamcu__"); - } - - bool allowsLargerPreferedTypeAlignment() const override { - return false; - } -}; - -// RTEMS Target -template<typename Target> -class RTEMSTargetInfo : public OSTargetInfo<Target> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - // RTEMS defines; list based off of gcc output - - Builder.defineMacro("__rtems__"); - Builder.defineMacro("__ELF__"); - } - -public: - RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OSTargetInfo<Target>(Triple, Opts) { - switch (Triple.getArch()) { - default: - case llvm::Triple::x86: - // this->MCountName = ".mcount"; - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - // this->MCountName = "_mcount"; - break; - case llvm::Triple::arm: - // this->MCountName = "__mcount"; - break; - } - } -}; - -// x86-32 RTEMS target -class RTEMSX86_32TargetInfo : public X86_32TargetInfo { -public: - RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86_32TargetInfo(Triple, Opts) { - SizeType = UnsignedLong; - IntPtrType = SignedLong; - PtrDiffType = SignedLong; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - X86_32TargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("__INTEL__"); - Builder.defineMacro("__rtems__"); - } -}; - -// x86-64 generic target -class X86_64TargetInfo : public X86TargetInfo { -public: - X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86TargetInfo(Triple, Opts) { - const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32; - bool IsWinCOFF = - getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); - LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; - LongDoubleWidth = 128; - LongDoubleAlign = 128; - LargeArrayMinWidth = 128; - LargeArrayAlign = 128; - SuitableAlign = 128; - SizeType = IsX32 ? UnsignedInt : UnsignedLong; - PtrDiffType = IsX32 ? SignedInt : SignedLong; - IntPtrType = IsX32 ? SignedInt : SignedLong; - IntMaxType = IsX32 ? SignedLongLong : SignedLong; - Int64Type = IsX32 ? SignedLongLong : SignedLong; - RegParmMax = 6; - - // Pointers are 32-bit in x32. - resetDataLayout(IsX32 - ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" - : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" - : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"); - - // Use fpret only for long double. - RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); - - // Use fp2ret for _Complex long double. - ComplexLongDoubleUsesFP2Ret = true; - - // Make __builtin_ms_va_list available. - HasBuiltinMSVaList = true; - - // x86-64 has atomics up to 16 bytes. - MaxAtomicPromoteWidth = 128; - MaxAtomicInlineWidth = 128; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::X86_64ABIBuiltinVaList; - } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 0; - if (RegNo == 1) return 1; - return -1; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_C: - case CC_Swift: - case CC_X86VectorCall: - case CC_IntelOclBicc: - case CC_Win64: - case CC_PreserveMost: - case CC_PreserveAll: - case CC_X86RegCall: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } - - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { - return CC_C; - } - - // for x32 we need it here explicitly - bool hasInt128Type() const override { return true; } - unsigned getUnwindWordWidth() const override { return 64; } - unsigned getRegisterWidth() const override { return 64; } - - bool validateGlobalRegisterVariable(StringRef RegName, - unsigned RegSize, - bool &HasSizeMismatch) const override { - // rsp and rbp are the only 64-bit registers the x86 backend can currently - // handle. - if (RegName.equals("rsp") || RegName.equals("rbp")) { - // Check that the register size is 64-bit. - HasSizeMismatch = RegSize != 64; - return true; - } - - // Check if the register is a 32-bit register the backend can handle. - return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, - HasSizeMismatch); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfoX86, - X86::LastTSBuiltin - Builtin::FirstTSBuiltin); - } -}; - -// x86-64 Windows target -class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> { -public: - WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) { - WCharType = UnsignedShort; - LongWidth = LongAlign = 32; - DoubleAlign = LongLongAlign = 64; - IntMaxType = SignedLongLong; - Int64Type = SignedLongLong; - SizeType = UnsignedLongLong; - PtrDiffType = SignedLongLong; - IntPtrType = SignedLongLong; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder); - Builder.defineMacro("_WIN64"); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_X86StdCall: - case CC_X86ThisCall: - case CC_X86FastCall: - return CCCR_Ignore; - case CC_C: - case CC_X86VectorCall: - case CC_IntelOclBicc: - case CC_X86_64SysV: - case CC_Swift: - case CC_X86RegCall: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } -}; - -// x86-64 Windows Visual Studio target -class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo { -public: - MicrosoftX86_64TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : WindowsX86_64TargetInfo(Triple, Opts) { - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); - WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); - Builder.defineMacro("_M_X64", "100"); - Builder.defineMacro("_M_AMD64", "100"); - } -}; - -// x86-64 MinGW target -class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { -public: - MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsX86_64TargetInfo(Triple, Opts) { - // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks - // with x86 FP ops. Weird. - LongDoubleWidth = LongDoubleAlign = 128; - LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); - HasFloat128 = true; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); +void addMinGWDefines(const llvm::Triple &Triple, const LangOptions &Opts, + MacroBuilder &Builder) { + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + if (Triple.isArch64Bit()) { DefineStd(Builder, "WIN64", Opts); Builder.defineMacro("__MINGW64__"); - addMinGWDefines(Opts, Builder); - - // GCC defines this macro when it is using __gxx_personality_seh0. - if (!Opts.SjLjExceptions) - Builder.defineMacro("__SEH__"); - } -}; - -// x86-64 Cygwin target -class CygwinX86_64TargetInfo : public X86_64TargetInfo { -public: - CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : X86_64TargetInfo(Triple, Opts) { - TLSSupported = false; - WCharType = UnsignedShort; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - X86_64TargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("__x86_64__"); - Builder.defineMacro("__CYGWIN__"); - Builder.defineMacro("__CYGWIN64__"); - addCygMingDefines(Opts, Builder); - DefineStd(Builder, "unix", Opts); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - - // GCC defines this macro when it is using __gxx_personality_seh0. - if (!Opts.SjLjExceptions) - Builder.defineMacro("__SEH__"); - } -}; - -class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> { -public: - DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) { - Int64Type = SignedLongLong; - // The 64-bit iOS simulator uses the builtin bool type for Objective-C. - llvm::Triple T = llvm::Triple(Triple); - if (T.isiOS()) - UseSignedCharForObjCBool = false; - resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128"); } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features, - Diags)) - return false; - // We now know the features we have: we can decide how to align vectors. - MaxVectorAlign = - hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; - return true; - } -}; - -class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> { -public: - OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) { - IntMaxType = SignedLongLong; - Int64Type = SignedLongLong; - } -}; - -class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> { -public: - BitrigX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : BitrigTargetInfo<X86_64TargetInfo>(Triple, Opts) { - IntMaxType = SignedLongLong; - Int64Type = SignedLongLong; - } -}; - -class ARMTargetInfo : public TargetInfo { - // Possible FPU choices. - enum FPUMode { - VFP2FPU = (1 << 0), - VFP3FPU = (1 << 1), - VFP4FPU = (1 << 2), - NeonFPU = (1 << 3), - FPARMV8 = (1 << 4) - }; - - // Possible HWDiv features. - enum HWDivMode { - HWDivThumb = (1 << 0), - HWDivARM = (1 << 1) - }; - - static bool FPUModeIsVFP(FPUMode Mode) { - return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8); - } - - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char * const GCCRegNames[]; - - std::string ABI, CPU; - - StringRef CPUProfile; - StringRef CPUAttr; - - enum { - FP_Default, - FP_VFP, - FP_Neon - } FPMath; - - unsigned ArchISA; - unsigned ArchKind = llvm::ARM::AK_ARMV4T; - unsigned ArchProfile; - unsigned ArchVersion; - - unsigned FPU : 5; - - unsigned IsAAPCS : 1; - unsigned HWDiv : 2; - - // Initialized via features. - unsigned SoftFloat : 1; - unsigned SoftFloatABI : 1; - - unsigned CRC : 1; - unsigned Crypto : 1; - unsigned DSP : 1; - unsigned Unaligned : 1; - - enum { - LDREX_B = (1 << 0), /// byte (8-bit) - LDREX_H = (1 << 1), /// half (16-bit) - LDREX_W = (1 << 2), /// word (32-bit) - LDREX_D = (1 << 3), /// double (64-bit) - }; - - uint32_t LDREX; - - // ACLE 6.5.1 Hardware floating point - enum { - HW_FP_HP = (1 << 1), /// half (16-bit) - HW_FP_SP = (1 << 2), /// single (32-bit) - HW_FP_DP = (1 << 3), /// double (64-bit) - }; - uint32_t HW_FP; - - static const Builtin::Info BuiltinInfo[]; - - void setABIAAPCS() { - IsAAPCS = true; - - DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; - const llvm::Triple &T = getTriple(); - - // size_t is unsigned long on MachO-derived environments, NetBSD, - // OpenBSD and Bitrig. - if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD || - T.getOS() == llvm::Triple::OpenBSD || - T.getOS() == llvm::Triple::Bitrig) - SizeType = UnsignedLong; - else - SizeType = UnsignedInt; - - switch (T.getOS()) { - case llvm::Triple::NetBSD: - case llvm::Triple::OpenBSD: - WCharType = SignedInt; - break; - case llvm::Triple::Win32: - WCharType = UnsignedShort; - break; - case llvm::Triple::Linux: - default: - // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int. - WCharType = UnsignedInt; - break; - } - - UseBitFieldTypeAlignment = true; - - ZeroLengthBitfieldBoundary = 0; - - // Thumb1 add sp, #imm requires the immediate value be multiple of 4, - // so set preferred for small types to 32. - if (T.isOSBinFormatMachO()) { - resetDataLayout(BigEndian - ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" - : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); - } else if (T.isOSWindows()) { - assert(!BigEndian && "Windows on ARM does not support big endian"); - resetDataLayout("e" - "-m:w" - "-p:32:32" - "-i64:64" - "-v128:64:128" - "-a:0:32" - "-n32" - "-S64"); - } else if (T.isOSNaCl()) { - assert(!BigEndian && "NaCl on ARM does not support big endian"); - resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"); - } else { - resetDataLayout(BigEndian - ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" - : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); - } - - // FIXME: Enumerated types are variable width in straight AAPCS. - } - - void setABIAPCS(bool IsAAPCS16) { - const llvm::Triple &T = getTriple(); - - IsAAPCS = false; - - if (IsAAPCS16) - DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; - else - DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; - - // size_t is unsigned int on FreeBSD. - if (T.getOS() == llvm::Triple::FreeBSD) - SizeType = UnsignedInt; - else - SizeType = UnsignedLong; - - // Revert to using SignedInt on apcs-gnu to comply with existing behaviour. - WCharType = SignedInt; - - // Do not respect the alignment of bit-field types when laying out - // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. - UseBitFieldTypeAlignment = false; - - /// gcc forces the alignment to 4 bytes, regardless of the type of the - /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in - /// gcc. - ZeroLengthBitfieldBoundary = 32; - - if (T.isOSBinFormatMachO() && IsAAPCS16) { - assert(!BigEndian && "AAPCS16 does not support big-endian"); - resetDataLayout("e-m:o-p:32:32-i64:64-a:0:32-n32-S128"); - } else if (T.isOSBinFormatMachO()) - resetDataLayout( - BigEndian - ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" - : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); - else - resetDataLayout( - BigEndian - ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" - : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); - - // FIXME: Override "preferred align" for double and long long. - } - - void setArchInfo() { - StringRef ArchName = getTriple().getArchName(); - - ArchISA = llvm::ARM::parseArchISA(ArchName); - CPU = llvm::ARM::getDefaultCPU(ArchName); - unsigned AK = llvm::ARM::parseArch(ArchName); - if (AK != llvm::ARM::AK_INVALID) - ArchKind = AK; - setArchInfo(ArchKind); - } - - void setArchInfo(unsigned Kind) { - StringRef SubArch; - - // cache TargetParser info - ArchKind = Kind; - SubArch = llvm::ARM::getSubArch(ArchKind); - ArchProfile = llvm::ARM::parseArchProfile(SubArch); - ArchVersion = llvm::ARM::parseArchVersion(SubArch); - - // cache CPU related strings - CPUAttr = getCPUAttr(); - CPUProfile = getCPUProfile(); - } - - void setAtomic() { - // when triple does not specify a sub arch, - // then we are not using inline atomics - bool ShouldUseInlineAtomic = - (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || - (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); - // Cortex M does not support 8 byte atomics, while general Thumb2 does. - if (ArchProfile == llvm::ARM::PK_M) { - MaxAtomicPromoteWidth = 32; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 32; - } - else { - MaxAtomicPromoteWidth = 64; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 64; - } - } - - bool isThumb() const { - return (ArchISA == llvm::ARM::IK_THUMB); - } - - bool supportsThumb() const { - return CPUAttr.count('T') || ArchVersion >= 6; - } - - bool supportsThumb2() const { - return CPUAttr.equals("6T2") || - (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE")); - } - - StringRef getCPUAttr() const { - // For most sub-arches, the build attribute CPU name is enough. - // For Cortex variants, it's slightly different. - switch(ArchKind) { - default: - return llvm::ARM::getCPUAttr(ArchKind); - case llvm::ARM::AK_ARMV6M: - return "6M"; - case llvm::ARM::AK_ARMV7S: - return "7S"; - case llvm::ARM::AK_ARMV7A: - return "7A"; - case llvm::ARM::AK_ARMV7R: - return "7R"; - case llvm::ARM::AK_ARMV7M: - return "7M"; - case llvm::ARM::AK_ARMV7EM: - return "7EM"; - case llvm::ARM::AK_ARMV7VE: - return "7VE"; - case llvm::ARM::AK_ARMV8A: - return "8A"; - case llvm::ARM::AK_ARMV8_1A: - return "8_1A"; - case llvm::ARM::AK_ARMV8_2A: - return "8_2A"; - case llvm::ARM::AK_ARMV8MBaseline: - return "8M_BASE"; - case llvm::ARM::AK_ARMV8MMainline: - return "8M_MAIN"; - case llvm::ARM::AK_ARMV8R: - return "8R"; - } - } - - StringRef getCPUProfile() const { - switch(ArchProfile) { - case llvm::ARM::PK_A: - return "A"; - case llvm::ARM::PK_R: - return "R"; - case llvm::ARM::PK_M: - return "M"; - default: - return ""; - } - } - -public: - ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), - HW_FP(0) { - - switch (getTriple().getOS()) { - case llvm::Triple::NetBSD: - case llvm::Triple::OpenBSD: - PtrDiffType = SignedLong; - break; - default: - PtrDiffType = SignedInt; - break; - } - - // Cache arch related info. - setArchInfo(); - - // {} in inline assembly are neon specifiers, not assembly variant - // specifiers. - NoAsmVariants = true; - - // FIXME: This duplicates code from the driver that sets the -target-abi - // option - this code is used if -target-abi isn't passed and should - // be unified in some way. - if (Triple.isOSBinFormatMachO()) { - // The backend is hardwired to assume AAPCS for M-class processors, ensure - // the frontend matches that. - if (Triple.getEnvironment() == llvm::Triple::EABI || - Triple.getOS() == llvm::Triple::UnknownOS || - ArchProfile == llvm::ARM::PK_M) { - setABI("aapcs"); - } else if (Triple.isWatchABI()) { - setABI("aapcs16"); - } else { - setABI("apcs-gnu"); - } - } else if (Triple.isOSWindows()) { - // FIXME: this is invalid for WindowsCE - setABI("aapcs"); - } else { - // Select the default based on the platform. - switch (Triple.getEnvironment()) { - case llvm::Triple::Android: - case llvm::Triple::GNUEABI: - case llvm::Triple::GNUEABIHF: - case llvm::Triple::MuslEABI: - case llvm::Triple::MuslEABIHF: - setABI("aapcs-linux"); - break; - case llvm::Triple::EABIHF: - case llvm::Triple::EABI: - setABI("aapcs"); - break; - case llvm::Triple::GNU: - setABI("apcs-gnu"); - break; - default: - if (Triple.getOS() == llvm::Triple::NetBSD) - setABI("apcs-gnu"); - else if (Triple.getOS() == llvm::Triple::OpenBSD) - setABI("aapcs-linux"); - else - setABI("aapcs"); - break; - } - } - - // ARM targets default to using the ARM C++ ABI. - TheCXXABI.set(TargetCXXABI::GenericARM); - - // ARM has atomics up to 8 bytes - setAtomic(); - - // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS) - if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android)) - MaxVectorAlign = 64; - - // Do force alignment of members that follow zero length bitfields. If - // the alignment of the zero-length bitfield is greater than the member - // that follows it, `bar', `bar' will be aligned as the type of the - // zero length bitfield. - UseZeroLengthBitfieldAlignment = true; - - if (Triple.getOS() == llvm::Triple::Linux || - Triple.getOS() == llvm::Triple::UnknownOS) - this->MCountName = - Opts.EABIVersion == llvm::EABI::GNU ? "\01__gnu_mcount_nc" : "\01mcount"; - } - - StringRef getABI() const override { return ABI; } - - bool setABI(const std::string &Name) override { - ABI = Name; - - // The defaults (above) are for AAPCS, check if we need to change them. - // - // FIXME: We need support for -meabi... we could just mangle it into the - // name. - if (Name == "apcs-gnu" || Name == "aapcs16") { - setABIAPCS(Name == "aapcs16"); - return true; - } - if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { - setABIAAPCS(); - return true; - } - return false; - } - - // FIXME: This should be based on Arch attributes, not CPU names. - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - - std::vector<StringRef> TargetFeatures; - unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName()); - - // get default FPU features - unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); - llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); - - // get default Extension features - unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); - llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); - - for (auto Feature : TargetFeatures) - if (Feature[0] == '+') - Features[Feature.drop_front(1)] = true; - - // Enable or disable thumb-mode explicitly per function to enable mixed - // ARM and Thumb code generation. - if (isThumb()) - Features["thumb-mode"] = true; - else - Features["thumb-mode"] = false; - - // Convert user-provided arm and thumb GNU target attributes to - // [-|+]thumb-mode target features respectively. - std::vector<std::string> UpdatedFeaturesVec(FeaturesVec); - for (auto &Feature : UpdatedFeaturesVec) { - if (Feature.compare("+arm") == 0) - Feature = "-thumb-mode"; - else if (Feature.compare("+thumb") == 0) - Feature = "+thumb-mode"; - } - - return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec); - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - FPU = 0; - CRC = 0; - Crypto = 0; - DSP = 0; - Unaligned = 1; - SoftFloat = SoftFloatABI = false; - HWDiv = 0; - - // This does not diagnose illegal cases like having both - // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp". - uint32_t HW_FP_remove = 0; - for (const auto &Feature : Features) { - if (Feature == "+soft-float") { - SoftFloat = true; - } else if (Feature == "+soft-float-abi") { - SoftFloatABI = true; - } else if (Feature == "+vfp2") { - FPU |= VFP2FPU; - HW_FP |= HW_FP_SP | HW_FP_DP; - } else if (Feature == "+vfp3") { - FPU |= VFP3FPU; - HW_FP |= HW_FP_SP | HW_FP_DP; - } else if (Feature == "+vfp4") { - FPU |= VFP4FPU; - HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; - } else if (Feature == "+fp-armv8") { - FPU |= FPARMV8; - HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; - } else if (Feature == "+neon") { - FPU |= NeonFPU; - HW_FP |= HW_FP_SP | HW_FP_DP; - } else if (Feature == "+hwdiv") { - HWDiv |= HWDivThumb; - } else if (Feature == "+hwdiv-arm") { - HWDiv |= HWDivARM; - } else if (Feature == "+crc") { - CRC = 1; - } else if (Feature == "+crypto") { - Crypto = 1; - } else if (Feature == "+dsp") { - DSP = 1; - } else if (Feature == "+fp-only-sp") { - HW_FP_remove |= HW_FP_DP; - } else if (Feature == "+strict-align") { - Unaligned = 0; - } else if (Feature == "+fp16") { - HW_FP |= HW_FP_HP; - } - } - HW_FP &= ~HW_FP_remove; - - switch (ArchVersion) { - case 6: - if (ArchProfile == llvm::ARM::PK_M) - LDREX = 0; - else if (ArchKind == llvm::ARM::AK_ARMV6K) - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; - else - LDREX = LDREX_W; - break; - case 7: - if (ArchProfile == llvm::ARM::PK_M) - LDREX = LDREX_W | LDREX_H | LDREX_B ; - else - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; - break; - case 8: - LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; - } - - if (!(FPU & NeonFPU) && FPMath == FP_Neon) { - Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; - return false; - } - - if (FPMath == FP_Neon) - Features.push_back("+neonfp"); - else if (FPMath == FP_VFP) - Features.push_back("-neonfp"); - - // Remove front-end specific options which the backend handles differently. - auto Feature = - std::find(Features.begin(), Features.end(), "+soft-float-abi"); - if (Feature != Features.end()) - Features.erase(Feature); - - return true; - } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Case("arm", true) - .Case("aarch32", true) - .Case("softfloat", SoftFloat) - .Case("thumb", isThumb()) - .Case("neon", (FPU & NeonFPU) && !SoftFloat) - .Case("vfp", FPU && !SoftFloat) - .Case("hwdiv", HWDiv & HWDivThumb) - .Case("hwdiv-arm", HWDiv & HWDivARM) - .Default(false); - } - - bool setCPU(const std::string &Name) override { - if (Name != "generic") - setArchInfo(llvm::ARM::parseCPUArch(Name)); - - if (ArchKind == llvm::ARM::AK_INVALID) - return false; - setAtomic(); - CPU = Name; - return true; - } - - bool setFPMath(StringRef Name) override; - - void getTargetDefinesARMV81A(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); - } - - void getTargetDefinesARMV82A(const LangOptions &Opts, - MacroBuilder &Builder) const { - // Also include the ARMv8.1-A defines - getTargetDefinesARMV81A(Opts, Builder); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - // Target identification. - Builder.defineMacro("__arm"); - Builder.defineMacro("__arm__"); - // For bare-metal none-eabi. - if (getTriple().getOS() == llvm::Triple::UnknownOS && - (getTriple().getEnvironment() == llvm::Triple::EABI || - getTriple().getEnvironment() == llvm::Triple::EABIHF)) - Builder.defineMacro("__ELF__"); - - - // Target properties. - Builder.defineMacro("__REGISTER_PREFIX__", ""); - - // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU - // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. - if (getTriple().isWatchABI()) - Builder.defineMacro("__ARM_ARCH_7K__", "2"); - - if (!CPUAttr.empty()) - Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); - - // ACLE 6.4.1 ARM/Thumb instruction set architecture - // __ARM_ARCH is defined as an integer value indicating the current ARM ISA - Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); - - if (ArchVersion >= 8) { - // ACLE 6.5.7 Crypto Extension - if (Crypto) - Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); - // ACLE 6.5.8 CRC32 Extension - if (CRC) - Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); - // ACLE 6.5.10 Numeric Maximum and Minimum - Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); - // ACLE 6.5.9 Directed Rounding - Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); - } - - // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It - // is not defined for the M-profile. - // NOTE that the default profile is assumed to be 'A' - if (CPUProfile.empty() || ArchProfile != llvm::ARM::PK_M) - Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); - - // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original - // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the - // core supports the Thumb-2 ISA as found in the v6T2 architecture and all - // v7 and v8 architectures excluding v8-M Baseline. - if (supportsThumb2()) - Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); - else if (supportsThumb()) - Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); - - // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit - // instruction set such as ARM or Thumb. - Builder.defineMacro("__ARM_32BIT_STATE", "1"); - - // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) - - // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. - if (!CPUProfile.empty()) - Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); - - // ACLE 6.4.3 Unaligned access supported in hardware - if (Unaligned) - Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); - - // ACLE 6.4.4 LDREX/STREX - if (LDREX) - Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX)); - - // ACLE 6.4.5 CLZ - if (ArchVersion == 5 || - (ArchVersion == 6 && CPUProfile != "M") || - ArchVersion > 6) - Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); - - // ACLE 6.5.1 Hardware Floating Point - if (HW_FP) - Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); - - // ACLE predefines. - Builder.defineMacro("__ARM_ACLE", "200"); - - // FP16 support (we currently only support IEEE format). - Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); - Builder.defineMacro("__ARM_FP16_ARGS", "1"); - - // ACLE 6.5.3 Fused multiply-accumulate (FMA) - if (ArchVersion >= 7 && (FPU & VFP4FPU)) - Builder.defineMacro("__ARM_FEATURE_FMA", "1"); - - // Subtarget options. - - // FIXME: It's more complicated than this and we don't really support - // interworking. - // Windows on ARM does not "support" interworking - if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) - Builder.defineMacro("__THUMB_INTERWORK__"); - - if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { - // Embedded targets on Darwin follow AAPCS, but not EABI. - // Windows on ARM follows AAPCS VFP, but does not conform to EABI. - if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows()) - Builder.defineMacro("__ARM_EABI__"); - Builder.defineMacro("__ARM_PCS", "1"); - } - - if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || - ABI == "aapcs16") - Builder.defineMacro("__ARM_PCS_VFP", "1"); - - if (SoftFloat) - Builder.defineMacro("__SOFTFP__"); - - if (ArchKind == llvm::ARM::AK_XSCALE) - Builder.defineMacro("__XSCALE__"); - - if (isThumb()) { - Builder.defineMacro("__THUMBEL__"); - Builder.defineMacro("__thumb__"); - if (supportsThumb2()) - Builder.defineMacro("__thumb2__"); - } - - // ACLE 6.4.9 32-bit SIMD instructions - if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) - Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); - - // ACLE 6.4.10 Hardware Integer Divide - if (((HWDiv & HWDivThumb) && isThumb()) || - ((HWDiv & HWDivARM) && !isThumb())) { - Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); - Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); - } - - // Note, this is always on in gcc, even though it doesn't make sense. - Builder.defineMacro("__APCS_32__"); - - if (FPUModeIsVFP((FPUMode) FPU)) { - Builder.defineMacro("__VFP_FP__"); - if (FPU & VFP2FPU) - Builder.defineMacro("__ARM_VFPV2__"); - if (FPU & VFP3FPU) - Builder.defineMacro("__ARM_VFPV3__"); - if (FPU & VFP4FPU) - Builder.defineMacro("__ARM_VFPV4__"); - if (FPU & FPARMV8) - Builder.defineMacro("__ARM_FPV5__"); - } - - // This only gets set when Neon instructions are actually available, unlike - // the VFP define, hence the soft float and arch check. This is subtly - // different from gcc, we follow the intent which was that it should be set - // when Neon instructions are actually available. - if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { - Builder.defineMacro("__ARM_NEON", "1"); - Builder.defineMacro("__ARM_NEON__"); - // current AArch32 NEON implementations do not support double-precision - // floating-point even when it is present in VFP. - Builder.defineMacro("__ARM_NEON_FP", - "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP)); - } - - Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", - Opts.ShortWChar ? "2" : "4"); - - Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", - Opts.ShortEnums ? "1" : "4"); - - if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") { - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - } - - // ACLE 6.4.7 DSP instructions - if (DSP) { - Builder.defineMacro("__ARM_FEATURE_DSP", "1"); - } - - // ACLE 6.4.8 Saturation instructions - bool SAT = false; - if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6 ) { - Builder.defineMacro("__ARM_FEATURE_SAT", "1"); - SAT = true; - } - - // ACLE 6.4.6 Q (saturation) flag - if (DSP || SAT) - Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); - - if (Opts.UnsafeFPMath) - Builder.defineMacro("__ARM_FP_FAST", "1"); - - switch(ArchKind) { - default: break; - case llvm::ARM::AK_ARMV8_1A: - getTargetDefinesARMV81A(Opts, Builder); - break; - case llvm::ARM::AK_ARMV8_2A: - getTargetDefinesARMV82A(Opts, Builder); - break; - } - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin); - } - bool isCLZForZeroUndef() const override { return false; } - BuiltinVaListKind getBuiltinVaListKind() const override { - return IsAAPCS - ? AAPCSABIBuiltinVaList - : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList - : TargetInfo::VoidPtrBuiltinVaList); - } - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: break; - case 'l': // r0-r7 - case 'h': // r8-r15 - case 't': // VFP Floating point register single precision - case 'w': // VFP Floating point register double precision - Info.setAllowsRegister(); - return true; - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - // FIXME - return true; - case 'Q': // A memory address that is a single base register. - Info.setAllowsMemory(); - return true; - case 'U': // a memory reference... - switch (Name[1]) { - case 'q': // ...ARMV4 ldrsb - case 'v': // ...VFP load/store (reg+constant offset) - case 'y': // ...iWMMXt load/store - case 't': // address valid for load/store opaque types wider - // than 128-bits - case 'n': // valid address for Neon doubleword vector load/store - case 'm': // valid address for Neon element and structure load/store - case 's': // valid address for non-offset loads/stores of quad-word - // values in four ARM registers - Info.setAllowsMemory(); - Name++; - return true; - } - } - return false; - } - std::string convertConstraint(const char *&Constraint) const override { - std::string R; - switch (*Constraint) { - case 'U': // Two-character constraint; add "^" hint for later parsing. - R = std::string("^") + std::string(Constraint, 2); - Constraint++; - break; - case 'p': // 'p' should be translated to 'r' by default. - R = std::string("r"); - break; - default: - return std::string(1, *Constraint); - } - return R; - } - bool - validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, - std::string &SuggestedModifier) const override { - bool isOutput = (Constraint[0] == '='); - bool isInOut = (Constraint[0] == '+'); - - // Strip off constraint modifiers. - while (Constraint[0] == '=' || - Constraint[0] == '+' || - Constraint[0] == '&') - Constraint = Constraint.substr(1); - - switch (Constraint[0]) { - default: break; - case 'r': { - switch (Modifier) { - default: - return (isInOut || isOutput || Size <= 64); - case 'q': - // A register of size 32 cannot fit a vector type. - return false; - } - } - } - - return true; - } - const char *getClobbers() const override { - // FIXME: Is this really right? - return ""; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_AAPCS: - case CC_AAPCS_VFP: - case CC_Swift: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 0; - if (RegNo == 1) return 1; - return -1; - } - - bool hasSjLjLowering() const override { - return true; - } -}; - -bool ARMTargetInfo::setFPMath(StringRef Name) { - if (Name == "neon") { - FPMath = FP_Neon; - return true; - } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || - Name == "vfp4") { - FPMath = FP_VFP; - return true; - } - return false; -} - -const char * const ARMTargetInfo::GCCRegNames[] = { - // Integer registers - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", - - // Float registers - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", - "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", - "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", - - // Double registers - "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", - "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", - "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", - "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", - - // Quad registers - "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", - "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" -}; - -ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { - { { "a1" }, "r0" }, - { { "a2" }, "r1" }, - { { "a3" }, "r2" }, - { { "a4" }, "r3" }, - { { "v1" }, "r4" }, - { { "v2" }, "r5" }, - { { "v3" }, "r6" }, - { { "v4" }, "r7" }, - { { "v5" }, "r8" }, - { { "v6", "rfp" }, "r9" }, - { { "sl" }, "r10" }, - { { "fp" }, "r11" }, - { { "ip" }, "r12" }, - { { "r13" }, "sp" }, - { { "r14" }, "lr" }, - { { "r15" }, "pc" }, - // The S, D and Q registers overlap, but aren't really aliases; we - // don't want to substitute one of these for a different-sized one. -}; - -ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - -const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsNEON.def" - -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ - { #ID, TYPE, ATTRS, nullptr, LANG, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ - { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE }, -#include "clang/Basic/BuiltinsARM.def" -}; - -class ARMleTargetInfo : public ARMTargetInfo { -public: - ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : ARMTargetInfo(Triple, Opts) {} - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__ARMEL__"); - ARMTargetInfo::getTargetDefines(Opts, Builder); - } -}; - -class ARMbeTargetInfo : public ARMTargetInfo { -public: - ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : ARMTargetInfo(Triple, Opts) {} - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__ARMEB__"); - Builder.defineMacro("__ARM_BIG_ENDIAN"); - ARMTargetInfo::getTargetDefines(Opts, Builder); - } -}; - -class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> { - const llvm::Triple Triple; -public: - WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) { - WCharType = UnsignedShort; - SizeType = UnsignedInt; - } - void getVisualStudioDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder); - - // FIXME: this is invalid for WindowsCE - Builder.defineMacro("_M_ARM_NT", "1"); - Builder.defineMacro("_M_ARMT", "_M_ARM"); - Builder.defineMacro("_M_THUMB", "_M_ARM"); - - assert((Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb) && - "invalid architecture for Windows ARM target info"); - unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; - Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); - - // TODO map the complete set of values - // 31: VFPv3 40: VFPv4 - Builder.defineMacro("_M_ARM_FP", "31"); - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_X86StdCall: - case CC_X86ThisCall: - case CC_X86FastCall: - case CC_X86VectorCall: - return CCCR_Ignore; - case CC_C: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } -}; - -// Windows ARM + Itanium C++ ABI Target -class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo { -public: - ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : WindowsARMTargetInfo(Triple, Opts) { - TheCXXABI.set(TargetCXXABI::GenericARM); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsARMTargetInfo::getTargetDefines(Opts, Builder); - - if (Opts.MSVCCompat) - WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); - } -}; - -// Windows ARM, MS (C++) ABI -class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo { -public: - MicrosoftARMleTargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : WindowsARMTargetInfo(Triple, Opts) { - TheCXXABI.set(TargetCXXABI::Microsoft); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsARMTargetInfo::getTargetDefines(Opts, Builder); - WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); - } -}; - -// ARM MinGW target -class MinGWARMTargetInfo : public WindowsARMTargetInfo { -public: - MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : WindowsARMTargetInfo(Triple, Opts) { - TheCXXABI.set(TargetCXXABI::GenericARM); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsARMTargetInfo::getTargetDefines(Opts, Builder); - DefineStd(Builder, "WIN32", Opts); - DefineStd(Builder, "WINNT", Opts); - Builder.defineMacro("_ARM_"); - addMinGWDefines(Opts, Builder); - } -}; - -// ARM Cygwin target -class CygwinARMTargetInfo : public ARMleTargetInfo { -public: - CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : ARMleTargetInfo(Triple, Opts) { - TLSSupported = false; - WCharType = UnsignedShort; - DoubleAlign = LongLongAlign = 64; - resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - ARMleTargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("_ARM_"); - Builder.defineMacro("__CYGWIN__"); - Builder.defineMacro("__CYGWIN32__"); - DefineStd(Builder, "unix", Opts); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - } -}; - -class DarwinARMTargetInfo : public DarwinTargetInfo<ARMleTargetInfo> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); - } - -public: - DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) { - HasAlignMac68kSupport = true; - // iOS always has 64-bit atomic instructions. - // FIXME: This should be based off of the target features in - // ARMleTargetInfo. - MaxAtomicInlineWidth = 64; - - if (Triple.isWatchABI()) { - // Darwin on iOS uses a variant of the ARM C++ ABI. - TheCXXABI.set(TargetCXXABI::WatchOS); - - // The 32-bit ABI is silent on what ptrdiff_t should be, but given that - // size_t is long, it's a bit weird for it to be int. - PtrDiffType = SignedLong; - - // BOOL should be a real boolean on the new ABI - UseSignedCharForObjCBool = false; - } else - TheCXXABI.set(TargetCXXABI::iOS); - } -}; - -class AArch64TargetInfo : public TargetInfo { - virtual void setDataLayout() = 0; - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char *const GCCRegNames[]; - - enum FPUModeEnum { - FPUMode, - NeonMode = (1 << 0), - SveMode = (1 << 1) - }; - - unsigned FPU; - unsigned CRC; - unsigned Crypto; - unsigned Unaligned; - unsigned HasFullFP16; - llvm::AArch64::ArchKind ArchKind; - - static const Builtin::Info BuiltinInfo[]; - - std::string ABI; - -public: - AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TargetInfo(Triple), ABI("aapcs") { - if (getTriple().getOS() == llvm::Triple::NetBSD || - getTriple().getOS() == llvm::Triple::OpenBSD) { - WCharType = SignedInt; - - // NetBSD apparently prefers consistency across ARM targets to consistency - // across 64-bit targets. - Int64Type = SignedLongLong; - IntMaxType = SignedLongLong; - } else { - WCharType = UnsignedInt; - Int64Type = SignedLong; - IntMaxType = SignedLong; - } - - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - MaxVectorAlign = 128; - MaxAtomicInlineWidth = 128; - MaxAtomicPromoteWidth = 128; - - LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - - // Make __builtin_ms_va_list available. - HasBuiltinMSVaList = true; - - // {} in inline assembly are neon specifiers, not assembly variant - // specifiers. - NoAsmVariants = true; - - // AAPCS gives rules for bitfields. 7.1.7 says: "The container type - // contributes to the alignment of the containing aggregate in the same way - // a plain (non bit-field) member of that type would, without exception for - // zero-sized or anonymous bit-fields." - assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); - UseZeroLengthBitfieldAlignment = true; - - // AArch64 targets default to using the ARM C++ ABI. - TheCXXABI.set(TargetCXXABI::GenericAArch64); - - if (Triple.getOS() == llvm::Triple::Linux) - this->MCountName = "\01_mcount"; - else if (Triple.getOS() == llvm::Triple::UnknownOS) - this->MCountName = Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount"; - } - - StringRef getABI() const override { return ABI; } - bool setABI(const std::string &Name) override { - if (Name != "aapcs" && Name != "darwinpcs") - return false; - - ABI = Name; - return true; - } - - bool setCPU(const std::string &Name) override { - return Name == "generic" || - llvm::AArch64::parseCPUArch(Name) != - static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID); - } - - void getTargetDefinesARMV81A(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); - } - - void getTargetDefinesARMV82A(const LangOptions &Opts, - MacroBuilder &Builder) const { - // Also include the ARMv8.1 defines - getTargetDefinesARMV81A(Opts, Builder); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - // Target identification. - Builder.defineMacro("__aarch64__"); - // For bare-metal none-eabi. - if (getTriple().getOS() == llvm::Triple::UnknownOS && - (getTriple().getEnvironment() == llvm::Triple::EABI || - getTriple().getEnvironment() == llvm::Triple::EABIHF)) - Builder.defineMacro("__ELF__"); - - // Target properties. - Builder.defineMacro("_LP64"); - Builder.defineMacro("__LP64__"); - - // ACLE predefines. Many can only have one possible value on v8 AArch64. - Builder.defineMacro("__ARM_ACLE", "200"); - Builder.defineMacro("__ARM_ARCH", "8"); - Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); - - Builder.defineMacro("__ARM_64BIT_STATE", "1"); - Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); - Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); - - Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); - Builder.defineMacro("__ARM_FEATURE_FMA", "1"); - Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); - Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE - Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility - Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); - Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); - - Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); - - // 0xe implies support for half, single and double precision operations. - Builder.defineMacro("__ARM_FP", "0xE"); - - // PCS specifies this for SysV variants, which is all we support. Other ABIs - // may choose __ARM_FP16_FORMAT_ALTERNATIVE. - Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); - Builder.defineMacro("__ARM_FP16_ARGS", "1"); - - if (Opts.UnsafeFPMath) - Builder.defineMacro("__ARM_FP_FAST", "1"); - - Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); - - Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", - Opts.ShortEnums ? "1" : "4"); - - if (FPU & NeonMode) { - Builder.defineMacro("__ARM_NEON", "1"); - // 64-bit NEON supports half, single and double precision operations. - Builder.defineMacro("__ARM_NEON_FP", "0xE"); - } - - if (FPU & SveMode) - Builder.defineMacro("__ARM_FEATURE_SVE", "1"); - - if (CRC) - Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); - - if (Crypto) - Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); - - if (Unaligned) - Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); - - switch(ArchKind) { - default: break; - case llvm::AArch64::ArchKind::AK_ARMV8_1A: - getTargetDefinesARMV81A(Opts, Builder); - break; - case llvm::AArch64::ArchKind::AK_ARMV8_2A: - getTargetDefinesARMV82A(Opts, Builder); - break; - } - - // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - - bool hasFeature(StringRef Feature) const override { - return Feature == "aarch64" || - Feature == "arm64" || - Feature == "arm" || - (Feature == "neon" && (FPU & NeonMode)) || - (Feature == "sve" && (FPU & SveMode)); - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - FPU = FPUMode; - CRC = 0; - Crypto = 0; - Unaligned = 1; - HasFullFP16 = 0; - ArchKind = llvm::AArch64::ArchKind::AK_ARMV8A; - - for (const auto &Feature : Features) { - if (Feature == "+neon") - FPU |= NeonMode; - if (Feature == "+sve") - FPU |= SveMode; - if (Feature == "+crc") - CRC = 1; - if (Feature == "+crypto") - Crypto = 1; - if (Feature == "+strict-align") - Unaligned = 0; - if (Feature == "+v8.1a") - ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_1A; - if (Feature == "+v8.2a") - ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_2A; - if (Feature == "+fullfp16") - HasFullFP16 = 1; - } - - setDataLayout(); - - return true; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_C: - case CC_Swift: - case CC_PreserveMost: - case CC_PreserveAll: - case CC_OpenCLKernel: - case CC_Win64: - return CCCR_OK; - default: - return CCCR_Warning; - } - } - - bool isCLZForZeroUndef() const override { return false; } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::AArch64ABIBuiltinVaList; - } - - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: - return false; - case 'w': // Floating point and SIMD registers (V0-V31) - Info.setAllowsRegister(); - return true; - case 'I': // Constant that can be used with an ADD instruction - case 'J': // Constant that can be used with a SUB instruction - case 'K': // Constant that can be used with a 32-bit logical instruction - case 'L': // Constant that can be used with a 64-bit logical instruction - case 'M': // Constant that can be used as a 32-bit MOV immediate - case 'N': // Constant that can be used as a 64-bit MOV immediate - case 'Y': // Floating point constant zero - case 'Z': // Integer constant zero - return true; - case 'Q': // A memory reference with base register and no offset - Info.setAllowsMemory(); - return true; - case 'S': // A symbolic address - Info.setAllowsRegister(); - return true; - case 'U': - // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. - // Utf: A memory address suitable for ldp/stp in TF mode. - // Usa: An absolute symbolic address. - // Ush: The high part (bits 32:12) of a pc-relative symbolic address. - llvm_unreachable("FIXME: Unimplemented support for U* constraints."); - case 'z': // Zero register, wzr or xzr - Info.setAllowsRegister(); - return true; - case 'x': // Floating point and SIMD registers (V0-V15) - Info.setAllowsRegister(); - return true; - } - return false; - } - - bool - validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, - std::string &SuggestedModifier) const override { - // Strip off constraint modifiers. - while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') - Constraint = Constraint.substr(1); - - switch (Constraint[0]) { - default: - return true; - case 'z': - case 'r': { - switch (Modifier) { - case 'x': - case 'w': - // For now assume that the person knows what they're - // doing with the modifier. - return true; - default: - // By default an 'r' constraint will be in the 'x' - // registers. - if (Size == 64) - return true; - - SuggestedModifier = "w"; - return false; - } - } - } - } - - const char *getClobbers() const override { return ""; } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) - return 0; - if (RegNo == 1) - return 1; - return -1; - } -}; - -const char *const AArch64TargetInfo::GCCRegNames[] = { - // 32-bit Integer registers - "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", - "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", - "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", - - // 64-bit Integer registers - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", - "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", - "x22", "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", - - // 32-bit floating point regsisters - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", - "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", - "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", - - // 64-bit floating point regsisters - "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", - "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", - "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", - - // Vector registers - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", - "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", - "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" -}; - -ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { - { { "w31" }, "wsp" }, - { { "x29" }, "fp" }, - { { "x30" }, "lr" }, - { { "x31" }, "sp" }, - // The S/D/Q and W/X registers overlap, but aren't really aliases; we - // don't want to substitute one of these for a different-sized one. -}; - -ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - -const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsNEON.def" - -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsAArch64.def" -}; - -class AArch64leTargetInfo : public AArch64TargetInfo { - void setDataLayout() override { - if (getTriple().isOSBinFormatMachO()) - resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); - else - resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); - } - -public: - AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : AArch64TargetInfo(Triple, Opts) { - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__AARCH64EL__"); - AArch64TargetInfo::getTargetDefines(Opts, Builder); - } -}; - -class MicrosoftARM64TargetInfo - : public WindowsTargetInfo<AArch64leTargetInfo> { - const llvm::Triple Triple; - -public: - MicrosoftARM64TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) { - - // This is an LLP64 platform. - // int:4, long:4, long long:8, long double:8. - WCharType = UnsignedShort; - IntWidth = IntAlign = 32; - LongWidth = LongAlign = 32; - DoubleAlign = LongLongAlign = 64; - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - IntMaxType = SignedLongLong; - Int64Type = SignedLongLong; - SizeType = UnsignedLongLong; - PtrDiffType = SignedLongLong; - IntPtrType = SignedLongLong; - - TheCXXABI.set(TargetCXXABI::Microsoft); - } - - void setDataLayout() override { - resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"); - } - - void getVisualStudioDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, - Builder); - Builder.defineMacro("_WIN32", "1"); - Builder.defineMacro("_WIN64", "1"); - Builder.defineMacro("_M_ARM64", "1"); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WindowsTargetInfo::getTargetDefines(Opts, Builder); - getVisualStudioDefines(Opts, Builder); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } -}; - -class AArch64beTargetInfo : public AArch64TargetInfo { - void setDataLayout() override { - assert(!getTriple().isOSBinFormatMachO()); - resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); - } - -public: - AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : AArch64TargetInfo(Triple, Opts) {} - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__AARCH64EB__"); - Builder.defineMacro("__AARCH_BIG_ENDIAN"); - Builder.defineMacro("__ARM_BIG_ENDIAN"); - AArch64TargetInfo::getTargetDefines(Opts, Builder); - } -}; - -class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> { -protected: - void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override { - Builder.defineMacro("__AARCH64_SIMD__"); - Builder.defineMacro("__ARM64_ARCH_8__"); - Builder.defineMacro("__ARM_NEON__"); - Builder.defineMacro("__LITTLE_ENDIAN__"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - Builder.defineMacro("__arm64", "1"); - Builder.defineMacro("__arm64__", "1"); - - getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); - } - -public: - DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) { - Int64Type = SignedLongLong; - WCharType = SignedInt; - UseSignedCharForObjCBool = false; - - LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - - TheCXXABI.set(TargetCXXABI::iOS64); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } -}; - -// Hexagon abstract base class -class HexagonTargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - static const char * const GCCRegNames[]; - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - std::string CPU; - bool HasHVX, HasHVXDouble; - bool UseLongCalls; - -public: - HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - // Specify the vector alignment explicitly. For v512x1, the calculated - // alignment would be 512*alignment(i1), which is 512 bytes, instead of - // the required minimum of 64 bytes. - resetDataLayout("e-m:e-p:32:32:32-a:0-n16:32-" - "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-" - "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"); - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - - // {} in inline assembly are packet specifiers, not assembly variant - // specifiers. - NoAsmVariants = true; - - LargeArrayMinWidth = 64; - LargeArrayAlign = 64; - UseBitFieldTypeAlignment = true; - ZeroLengthBitfieldBoundary = 32; - HasHVX = HasHVXDouble = false; - UseLongCalls = false; - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin); - } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - case 'v': - case 'q': - if (HasHVX) { - Info.setAllowsRegister(); - return true; - } - break; - case 's': - // Relocatable constant. - return true; - } - return false; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; - - bool isCLZForZeroUndef() const override { return false; } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Case("hexagon", true) - .Case("hvx", HasHVX) - .Case("hvx-double", HasHVXDouble) - .Case("long-calls", UseLongCalls) - .Default(false); - } - - bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, const std::vector<std::string> &FeaturesVec) - const override; - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override; - - void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, - bool Enabled) const override; - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::CharPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - const char *getClobbers() const override { - return ""; - } - - static const char *getHexagonCPUSuffix(StringRef Name) { - return llvm::StringSwitch<const char*>(Name) - .Case("hexagonv4", "4") - .Case("hexagonv5", "5") - .Case("hexagonv55", "55") - .Case("hexagonv60", "60") - .Case("hexagonv62", "62") - .Default(nullptr); - } - - bool setCPU(const std::string &Name) override { - if (!getHexagonCPUSuffix(Name)) - return false; - CPU = Name; - return true; - } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - return RegNo < 2 ? RegNo : -1; - } -}; - -void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("__qdsp6__", "1"); - Builder.defineMacro("__hexagon__", "1"); - - if (CPU == "hexagonv4") { - Builder.defineMacro("__HEXAGON_V4__"); - Builder.defineMacro("__HEXAGON_ARCH__", "4"); - if (Opts.HexagonQdsp6Compat) { - Builder.defineMacro("__QDSP6_V4__"); - Builder.defineMacro("__QDSP6_ARCH__", "4"); - } - } else if (CPU == "hexagonv5") { - Builder.defineMacro("__HEXAGON_V5__"); - Builder.defineMacro("__HEXAGON_ARCH__", "5"); - if(Opts.HexagonQdsp6Compat) { - Builder.defineMacro("__QDSP6_V5__"); - Builder.defineMacro("__QDSP6_ARCH__", "5"); - } - } else if (CPU == "hexagonv55") { - Builder.defineMacro("__HEXAGON_V55__"); - Builder.defineMacro("__HEXAGON_ARCH__", "55"); - Builder.defineMacro("__QDSP6_V55__"); - Builder.defineMacro("__QDSP6_ARCH__", "55"); - } else if (CPU == "hexagonv60") { - Builder.defineMacro("__HEXAGON_V60__"); - Builder.defineMacro("__HEXAGON_ARCH__", "60"); - Builder.defineMacro("__QDSP6_V60__"); - Builder.defineMacro("__QDSP6_ARCH__", "60"); - } else if (CPU == "hexagonv62") { - Builder.defineMacro("__HEXAGON_V62__"); - Builder.defineMacro("__HEXAGON_ARCH__", "62"); - } - - if (hasFeature("hvx")) { - Builder.defineMacro("__HVX__"); - if (hasFeature("hvx-double")) - Builder.defineMacro("__HVXDBL__"); - } -} - -bool HexagonTargetInfo::initFeatureMap(llvm::StringMap<bool> &Features, - DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeaturesVec) const { - // Default for v60: -hvx, -hvx-double. - Features["hvx"] = false; - Features["hvx-double"] = false; - Features["long-calls"] = false; - - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); -} - -bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) { - for (auto &F : Features) { - if (F == "+hvx") - HasHVX = true; - else if (F == "-hvx") - HasHVX = HasHVXDouble = false; - else if (F == "+hvx-double") - HasHVX = HasHVXDouble = true; - else if (F == "-hvx-double") - HasHVXDouble = false; - - if (F == "+long-calls") - UseLongCalls = true; - else if (F == "-long-calls") - UseLongCalls = false; - } - return true; -} - -void HexagonTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, - StringRef Name, bool Enabled) const { - if (Enabled) { - if (Name == "hvx-double") - Features["hvx"] = true; - } else { - if (Name == "hvx") - Features["hvx-double"] = false; - } - Features[Name] = Enabled; -} - -const char *const HexagonTargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", - "p0", "p1", "p2", "p3", - "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" -}; - -ArrayRef<const char*> HexagonTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { - { { "sp" }, "r29" }, - { { "fp" }, "r30" }, - { { "lr" }, "r31" }, -}; - -ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - - -const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsHexagon.def" -}; - -class LanaiTargetInfo : public TargetInfo { - // Class for Lanai (32-bit). - // The CPU profiles supported by the Lanai backend - enum CPUKind { - CK_NONE, - CK_V11, - } CPU; - - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char *const GCCRegNames[]; - -public: - LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - // Description string has to be kept in sync with backend. - resetDataLayout("E" // Big endian - "-m:e" // ELF name manging - "-p:32:32" // 32 bit pointers, 32 bit aligned - "-i64:64" // 64 bit integers, 64 bit aligned - "-a:0:32" // 32 bit alignment of objects of aggregate type - "-n32" // 32 bit native integer width - "-S64" // 64 bit natural stack alignment - ); - - // Setting RegParmMax equal to what mregparm was set to in the old - // toolchain - RegParmMax = 4; - - // Set the default CPU to V11 - CPU = CK_V11; - - // Temporary approach to make everything at least word-aligned and allow for - // safely casting between pointers with different alignment requirements. - // TODO: Remove this when there are no more cast align warnings on the - // firmware. - MinGlobalAlign = 32; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - // Define __lanai__ when building for target lanai. - Builder.defineMacro("__lanai__"); - - // Set define for the CPU specified. - switch (CPU) { - case CK_V11: - Builder.defineMacro("__LANAI_V11__"); - break; - case CK_NONE: - llvm_unreachable("Unhandled target CPU"); - } - } - - bool setCPU(const std::string &Name) override { - CPU = llvm::StringSwitch<CPUKind>(Name) - .Case("v11", CK_V11) - .Default(CK_NONE); - - return CPU != CK_NONE; - } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false); - } - - ArrayRef<const char *> getGCCRegNames() const override; - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - return false; - } - - const char *getClobbers() const override { return ""; } -}; - -const char *const LanaiTargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", - "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", - "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; - -ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = { - {{"pc"}, "r2"}, - {{"sp"}, "r4"}, - {{"fp"}, "r5"}, - {{"rv"}, "r8"}, - {{"rr1"}, "r10"}, - {{"rr2"}, "r11"}, - {{"rca"}, "r15"}, -}; - -ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - -// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). -class SparcTargetInfo : public TargetInfo { - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char * const GCCRegNames[]; - bool SoftFloat; -public: - SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), SoftFloat(false) {} - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 24; - if (RegNo == 1) return 25; - return -1; - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - // Check if software floating point is enabled - auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); - if (Feature != Features.end()) { - SoftFloat = true; - } - return true; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "sparc", Opts); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - - if (SoftFloat) - Builder.defineMacro("SOFT_FLOAT", "1"); - } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Case("softfloat", SoftFloat) - .Case("sparc", true) - .Default(false); - } - - bool hasSjLjLowering() const override { - return true; - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - // FIXME: Implement! - return None; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - // FIXME: Implement! - switch (*Name) { - case 'I': // Signed 13-bit constant - case 'J': // Zero - case 'K': // 32-bit constant with the low 12 bits clear - case 'L': // A constant in the range supported by movcc (11-bit signed imm) - case 'M': // A constant in the range supported by movrcc (19-bit signed imm) - case 'N': // Same as 'K' but zext (required for SIMode) - case 'O': // The constant 4096 - return true; - - case 'f': - case 'e': - info.setAllowsRegister(); - return true; - } - return false; - } - const char *getClobbers() const override { - // FIXME: Implement! - return ""; - } - - // No Sparc V7 for now, the backend doesn't support it anyway. - enum CPUKind { - CK_GENERIC, - CK_V8, - CK_SUPERSPARC, - CK_SPARCLITE, - CK_F934, - CK_HYPERSPARC, - CK_SPARCLITE86X, - CK_SPARCLET, - CK_TSC701, - CK_V9, - CK_ULTRASPARC, - CK_ULTRASPARC3, - CK_NIAGARA, - CK_NIAGARA2, - CK_NIAGARA3, - CK_NIAGARA4, - CK_MYRIAD2100, - CK_MYRIAD2150, - CK_MYRIAD2450, - CK_LEON2, - CK_LEON2_AT697E, - CK_LEON2_AT697F, - CK_LEON3, - CK_LEON3_UT699, - CK_LEON3_GR712RC, - CK_LEON4, - CK_LEON4_GR740 - } CPU = CK_GENERIC; - - enum CPUGeneration { - CG_V8, - CG_V9, - }; - - CPUGeneration getCPUGeneration(CPUKind Kind) const { - switch (Kind) { - case CK_GENERIC: - case CK_V8: - case CK_SUPERSPARC: - case CK_SPARCLITE: - case CK_F934: - case CK_HYPERSPARC: - case CK_SPARCLITE86X: - case CK_SPARCLET: - case CK_TSC701: - case CK_MYRIAD2100: - case CK_MYRIAD2150: - case CK_MYRIAD2450: - case CK_LEON2: - case CK_LEON2_AT697E: - case CK_LEON2_AT697F: - case CK_LEON3: - case CK_LEON3_UT699: - case CK_LEON3_GR712RC: - case CK_LEON4: - case CK_LEON4_GR740: - return CG_V8; - case CK_V9: - case CK_ULTRASPARC: - case CK_ULTRASPARC3: - case CK_NIAGARA: - case CK_NIAGARA2: - case CK_NIAGARA3: - case CK_NIAGARA4: - return CG_V9; - } - llvm_unreachable("Unexpected CPU kind"); - } - - CPUKind getCPUKind(StringRef Name) const { - return llvm::StringSwitch<CPUKind>(Name) - .Case("v8", CK_V8) - .Case("supersparc", CK_SUPERSPARC) - .Case("sparclite", CK_SPARCLITE) - .Case("f934", CK_F934) - .Case("hypersparc", CK_HYPERSPARC) - .Case("sparclite86x", CK_SPARCLITE86X) - .Case("sparclet", CK_SPARCLET) - .Case("tsc701", CK_TSC701) - .Case("v9", CK_V9) - .Case("ultrasparc", CK_ULTRASPARC) - .Case("ultrasparc3", CK_ULTRASPARC3) - .Case("niagara", CK_NIAGARA) - .Case("niagara2", CK_NIAGARA2) - .Case("niagara3", CK_NIAGARA3) - .Case("niagara4", CK_NIAGARA4) - .Case("ma2100", CK_MYRIAD2100) - .Case("ma2150", CK_MYRIAD2150) - .Case("ma2450", CK_MYRIAD2450) - // FIXME: the myriad2[.n] spellings are obsolete, - // but a grace period is needed to allow updating dependent builds. - .Case("myriad2", CK_MYRIAD2100) - .Case("myriad2.1", CK_MYRIAD2100) - .Case("myriad2.2", CK_MYRIAD2150) - .Case("leon2", CK_LEON2) - .Case("at697e", CK_LEON2_AT697E) - .Case("at697f", CK_LEON2_AT697F) - .Case("leon3", CK_LEON3) - .Case("ut699", CK_LEON3_UT699) - .Case("gr712rc", CK_LEON3_GR712RC) - .Case("leon4", CK_LEON4) - .Case("gr740", CK_LEON4_GR740) - .Default(CK_GENERIC); - } - - bool setCPU(const std::string &Name) override { - CPU = getCPUKind(Name); - return CPU != CK_GENERIC; - } -}; - -const char * const SparcTargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -}; - -ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { - { { "g0" }, "r0" }, - { { "g1" }, "r1" }, - { { "g2" }, "r2" }, - { { "g3" }, "r3" }, - { { "g4" }, "r4" }, - { { "g5" }, "r5" }, - { { "g6" }, "r6" }, - { { "g7" }, "r7" }, - { { "o0" }, "r8" }, - { { "o1" }, "r9" }, - { { "o2" }, "r10" }, - { { "o3" }, "r11" }, - { { "o4" }, "r12" }, - { { "o5" }, "r13" }, - { { "o6", "sp" }, "r14" }, - { { "o7" }, "r15" }, - { { "l0" }, "r16" }, - { { "l1" }, "r17" }, - { { "l2" }, "r18" }, - { { "l3" }, "r19" }, - { { "l4" }, "r20" }, - { { "l5" }, "r21" }, - { { "l6" }, "r22" }, - { { "l7" }, "r23" }, - { { "i0" }, "r24" }, - { { "i1" }, "r25" }, - { { "i2" }, "r26" }, - { { "i3" }, "r27" }, - { { "i4" }, "r28" }, - { { "i5" }, "r29" }, - { { "i6", "fp" }, "r30" }, - { { "i7" }, "r31" }, -}; - -ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const { - return llvm::makeArrayRef(GCCRegAliases); -} - -// SPARC v8 is the 32-bit mode selected by Triple::sparc. -class SparcV8TargetInfo : public SparcTargetInfo { -public: - SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : SparcTargetInfo(Triple, Opts) { - resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); - // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. - switch (getTriple().getOS()) { - default: - SizeType = UnsignedInt; - IntPtrType = SignedInt; - PtrDiffType = SignedInt; - break; - case llvm::Triple::NetBSD: - case llvm::Triple::OpenBSD: - SizeType = UnsignedLong; - IntPtrType = SignedLong; - PtrDiffType = SignedLong; - break; - } - // Up to 32 bits are lock-free atomic, but we're willing to do atomic ops - // on up to 64 bits. - MaxAtomicPromoteWidth = 64; - MaxAtomicInlineWidth = 32; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - SparcTargetInfo::getTargetDefines(Opts, Builder); - switch (getCPUGeneration(CPU)) { - case CG_V8: - Builder.defineMacro("__sparcv8"); - if (getTriple().getOS() != llvm::Triple::Solaris) - Builder.defineMacro("__sparcv8__"); - break; - case CG_V9: - Builder.defineMacro("__sparcv9"); - if (getTriple().getOS() != llvm::Triple::Solaris) { - Builder.defineMacro("__sparcv9__"); - Builder.defineMacro("__sparc_v9__"); - } - break; - } - if (getTriple().getVendor() == llvm::Triple::Myriad) { - std::string MyriadArchValue, Myriad2Value; - Builder.defineMacro("__sparc_v8__"); - Builder.defineMacro("__leon__"); - switch (CPU) { - case CK_MYRIAD2150: - MyriadArchValue = "__ma2150"; - Myriad2Value = "2"; - break; - case CK_MYRIAD2450: - MyriadArchValue = "__ma2450"; - Myriad2Value = "2"; - break; - default: - MyriadArchValue = "__ma2100"; - Myriad2Value = "1"; - break; - } - Builder.defineMacro(MyriadArchValue, "1"); - Builder.defineMacro(MyriadArchValue+"__", "1"); - Builder.defineMacro("__myriad2__", Myriad2Value); - Builder.defineMacro("__myriad2", Myriad2Value); - } - } - - bool hasSjLjLowering() const override { - return true; - } -}; - -// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. -class SparcV8elTargetInfo : public SparcV8TargetInfo { - public: - SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : SparcV8TargetInfo(Triple, Opts) { - resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64"); - } -}; - -// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. -class SparcV9TargetInfo : public SparcTargetInfo { -public: - SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : SparcTargetInfo(Triple, Opts) { - // FIXME: Support Sparc quad-precision long double? - resetDataLayout("E-m:e-i64:64-n32:64-S128"); - // This is an LP64 platform. - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - - // OpenBSD uses long long for int64_t and intmax_t. - if (getTriple().getOS() == llvm::Triple::OpenBSD) - IntMaxType = SignedLongLong; - else - IntMaxType = SignedLong; - Int64Type = IntMaxType; - - // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit - // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. - LongDoubleWidth = 128; - LongDoubleAlign = 128; - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - SparcTargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("__sparcv9"); - Builder.defineMacro("__arch64__"); - // Solaris doesn't need these variants, but the BSDs do. - if (getTriple().getOS() != llvm::Triple::Solaris) { - Builder.defineMacro("__sparc64__"); - Builder.defineMacro("__sparc_v9__"); - Builder.defineMacro("__sparcv9__"); - } - } - - bool setCPU(const std::string &Name) override { - if (!SparcTargetInfo::setCPU(Name)) - return false; - return getCPUGeneration(CPU) == CG_V9; - } -}; - -class SystemZTargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - static const char *const GCCRegNames[]; - std::string CPU; - int ISARevision; - bool HasTransactionalExecution; - bool HasVector; - -public: - SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), CPU("z10"), ISARevision(8), - HasTransactionalExecution(false), HasVector(false) { - IntMaxType = SignedLong; - Int64Type = SignedLong; - TLSSupported = true; - IntWidth = IntAlign = 32; - LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; - PointerWidth = PointerAlign = 64; - LongDoubleWidth = 128; - LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - DefaultAlignForAttributeAligned = 64; - MinGlobalAlign = 16; - resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__s390__"); - Builder.defineMacro("__s390x__"); - Builder.defineMacro("__zarch__"); - Builder.defineMacro("__LONG_DOUBLE_128__"); - - Builder.defineMacro("__ARCH__", Twine(ISARevision)); - - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - - if (HasTransactionalExecution) - Builder.defineMacro("__HTM__"); - if (HasVector) - Builder.defineMacro("__VX__"); - if (Opts.ZVector) - Builder.defineMacro("__VEC__", "10302"); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin); - } - - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - // No aliases. - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; - const char *getClobbers() const override { - // FIXME: Is this really right? - return ""; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::SystemZBuiltinVaList; - } - int getISARevision(const StringRef &Name) const { - return llvm::StringSwitch<int>(Name) - .Cases("arch8", "z10", 8) - .Cases("arch9", "z196", 9) - .Cases("arch10", "zEC12", 10) - .Cases("arch11", "z13", 11) - .Cases("arch12", "z14", 12) - .Default(-1); - } - bool setCPU(const std::string &Name) override { - CPU = Name; - ISARevision = getISARevision(CPU); - return ISARevision != -1; - } - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - int ISARevision = getISARevision(CPU); - if (ISARevision >= 10) - Features["transactional-execution"] = true; - if (ISARevision >= 11) - Features["vector"] = true; - if (ISARevision >= 12) - Features["vector-enhancements-1"] = true; - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - HasTransactionalExecution = false; - HasVector = false; - for (const auto &Feature : Features) { - if (Feature == "+transactional-execution") - HasTransactionalExecution = true; - else if (Feature == "+vector") - HasVector = true; - } - // If we use the vector ABI, vector types are 64-bit aligned. - if (HasVector) { - MaxVectorAlign = 64; - resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" - "-v128:64-a:8:16-n32:64"); - } - return true; - } - - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Case("systemz", true) - .Case("arch8", ISARevision >= 8) - .Case("arch9", ISARevision >= 9) - .Case("arch10", ISARevision >= 10) - .Case("arch11", ISARevision >= 11) - .Case("arch12", ISARevision >= 12) - .Case("htm", HasTransactionalExecution) - .Case("vx", HasVector) - .Default(false); - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - case CC_C: - case CC_Swift: - case CC_OpenCLKernel: - return CCCR_OK; - default: - return CCCR_Warning; - } - } - - StringRef getABI() const override { - if (HasVector) - return "vector"; - return ""; - } - - bool useFloat128ManglingForLongDouble() const override { - return true; - } -}; - -const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, -#include "clang/Basic/BuiltinsSystemZ.def" -}; - -const char *const SystemZTargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", - "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" -}; - -ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -bool SystemZTargetInfo:: -validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const { - switch (*Name) { - default: - return false; - - case 'a': // Address register - case 'd': // Data register (equivalent to 'r') - case 'f': // Floating-point register - Info.setAllowsRegister(); - return true; - - case 'I': // Unsigned 8-bit constant - case 'J': // Unsigned 12-bit constant - case 'K': // Signed 16-bit constant - case 'L': // Signed 20-bit displacement (on all targets we support) - case 'M': // 0x7fffffff - return true; - - case 'Q': // Memory with base and unsigned 12-bit displacement - case 'R': // Likewise, plus an index - case 'S': // Memory with base and signed 20-bit displacement - case 'T': // Likewise, plus an index - Info.setAllowsMemory(); - return true; - } -} - -class MSP430TargetInfo : public TargetInfo { - static const char *const GCCRegNames[]; - -public: - MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - TLSSupported = false; - IntWidth = 16; - IntAlign = 16; - LongWidth = 32; - LongLongWidth = 64; - LongAlign = LongLongAlign = 16; - PointerWidth = 16; - PointerAlign = 16; - SuitableAlign = 16; - SizeType = UnsignedInt; - IntMaxType = SignedLongLong; - IntPtrType = SignedInt; - PtrDiffType = SignedInt; - SigAtomicType = SignedLong; - resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("MSP430"); - Builder.defineMacro("__MSP430__"); - // FIXME: defines for different 'flavours' of MCU - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - // FIXME: Implement. - return None; - } - bool hasFeature(StringRef Feature) const override { - return Feature == "msp430"; - } - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - // No aliases. - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - // FIXME: implement - switch (*Name) { - case 'K': // the constant 1 - case 'L': // constant -1^20 .. 1^19 - case 'M': // constant 1-4: - return true; - } - // No target constraints for now. - return false; - } - const char *getClobbers() const override { - // FIXME: Is this really right? - return ""; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - // FIXME: implement - return TargetInfo::CharPtrBuiltinVaList; - } -}; - -const char *const MSP430TargetInfo::GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; - -ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const { - return llvm::makeArrayRef(GCCRegNames); -} - -// LLVM and Clang cannot be used directly to output native binaries for -// target, but is used to compile C code to llvm bitcode with correct -// type and alignment information. -// -// TCE uses the llvm bitcode as input and uses it for generating customized -// target processor and program binary. TCE co-design environment is -// publicly available in http://tce.cs.tut.fi - -static const unsigned TCEOpenCLAddrSpaceMap[] = { - 0, // Default - 3, // opencl_global - 4, // opencl_local - 5, // opencl_constant - // FIXME: generic has to be added to the target - 0, // opencl_generic - 0, // cuda_device - 0, // cuda_constant - 0 // cuda_shared -}; - -class TCETargetInfo : public TargetInfo { -public: - TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - TLSSupported = false; - IntWidth = 32; - LongWidth = LongLongWidth = 32; - PointerWidth = 32; - IntAlign = 32; - LongAlign = LongLongAlign = 32; - PointerAlign = 32; - SuitableAlign = 32; - SizeType = UnsignedInt; - IntMaxType = SignedLong; - IntPtrType = SignedInt; - PtrDiffType = SignedInt; - FloatWidth = 32; - FloatAlign = 32; - DoubleWidth = 32; - DoubleAlign = 32; - LongDoubleWidth = 32; - LongDoubleAlign = 32; - FloatFormat = &llvm::APFloat::IEEEsingle(); - DoubleFormat = &llvm::APFloat::IEEEsingle(); - LongDoubleFormat = &llvm::APFloat::IEEEsingle(); - resetDataLayout("E-p:32:32:32-i1:8:8-i8:8:32-" - "i16:16:32-i32:32:32-i64:32:32-" - "f32:32:32-f64:32:32-v64:32:32-" - "v128:32:32-v256:32:32-v512:32:32-" - "v1024:32:32-a0:0:32-n32"); - AddrSpaceMap = &TCEOpenCLAddrSpaceMap; - UseAddrSpaceMapMangling = true; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "tce", Opts); - Builder.defineMacro("__TCE__"); - Builder.defineMacro("__TCE_V1__"); - } - bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } - const char *getClobbers() const override { return ""; } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override { return None; } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - return true; - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } -}; - -class TCELETargetInfo : public TCETargetInfo { -public: - TCELETargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TCETargetInfo(Triple, Opts) { - BigEndian = false; - - resetDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-" - "i16:16:32-i32:32:32-i64:32:32-" - "f32:32:32-f64:32:32-v64:32:32-" - "v128:32:32-v256:32:32-v512:32:32-" - "v1024:32:32-a0:0:32-n32"); - - } - - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - DefineStd(Builder, "tcele", Opts); - Builder.defineMacro("__TCE__"); - Builder.defineMacro("__TCE_V1__"); - Builder.defineMacro("__TCELE__"); - Builder.defineMacro("__TCELE_V1__"); - } - -}; - -class BPFTargetInfo : public TargetInfo { -public: - BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - SizeType = UnsignedLong; - PtrDiffType = SignedLong; - IntPtrType = SignedLong; - IntMaxType = SignedLong; - Int64Type = SignedLong; - RegParmMax = 5; - if (Triple.getArch() == llvm::Triple::bpfeb) { - resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128"); - } else { - resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); - } - MaxAtomicPromoteWidth = 64; - MaxAtomicInlineWidth = 64; - TLSSupported = false; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "bpf", Opts); - Builder.defineMacro("__BPF__"); - } - bool hasFeature(StringRef Feature) const override { - return Feature == "bpf"; - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } - const char *getClobbers() const override { - return ""; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override { - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - return true; - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - switch (CC) { - default: - return CCCR_Warning; - case CC_C: - case CC_OpenCLKernel: - return CCCR_OK; - } - } -}; - -class Nios2TargetInfo : public TargetInfo { - void setDataLayout() { - if (BigEndian) - resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32"); - else - resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32"); - } - - static const Builtin::Info BuiltinInfo[]; - std::string CPU; - std::string ABI; - -public: - Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts) - : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) { - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; - setDataLayout(); - } - - StringRef getABI() const override { return ABI; } - bool setABI(const std::string &Name) override { - if (Name == "o32" || Name == "eabi") { - ABI = Name; - return true; - } - return false; - } - - bool setCPU(const std::string &Name) override { - if (Name == "nios2r1" || Name == "nios2r2") { - CPU = Name; - return true; - } - return false; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "nios2", Opts); - DefineStd(Builder, "NIOS2", Opts); - - Builder.defineMacro("__nios2"); - Builder.defineMacro("__NIOS2"); - Builder.defineMacro("__nios2__"); - Builder.defineMacro("__NIOS2__"); - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin - - Builtin::FirstTSBuiltin); - } - - bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const { - const bool isR2 = CPU == "nios2r2"; - return llvm::StringSwitch<bool>(Feature) - .Case("nios2r2mandatory", isR2) - .Case("nios2r2bmx", isR2) - .Case("nios2r2mpx", isR2) - .Case("nios2r2cdx", isR2) - .Default(false); - } - - bool initFeatureMap(llvm::StringMap<bool> &Features, - DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeatureVec) const override { - static const char *allFeatures[] = { - "nios2r2mandatory", "nios2r2bmx", "nios2r2mpx", "nios2r2cdx" - }; - for (const char *feature : allFeatures) { - Features[feature] = isFeatureSupportedByCPU(feature, CPU); - } - return true; - } - - bool hasFeature(StringRef Feature) const override { - return isFeatureSupportedByCPU(Feature, CPU); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - - ArrayRef<const char *> getGCCRegNames() const override { - static const char *const GCCRegNames[] = { - // CPU register names - // Must match second column of GCCRegAliases - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", - "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", - "r31", - // Floating point register names - "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8", - "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15" - }; - return llvm::makeArrayRef(GCCRegNames); - } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: - return false; - - case 'r': // CPU registers. - case 'd': // Equivalent to "r" unless generating MIPS16 code. - case 'y': // Equivalent to "r", backwards compatibility only. - case 'f': // floating-point registers. - case 'c': // $25 for indirect jumps - case 'l': // lo register - case 'x': // hilo register pair - Info.setAllowsRegister(); - return true; - } - } - - const char *getClobbers() const override { return ""; } - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - static const TargetInfo::GCCRegAlias aliases[] = { - {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"}, - {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"}, - {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"}, - {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"}, - {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"}, - {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"}, - {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"}, - {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"}, - }; - return llvm::makeArrayRef(aliases); - } -}; - -const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, -#include "clang/Basic/BuiltinsNios2.def" -}; - -class MipsTargetInfo : public TargetInfo { - void setDataLayout() { - StringRef Layout; - - if (ABI == "o32") - Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; - else if (ABI == "n32") - Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; - else if (ABI == "n64") - Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"; - else - llvm_unreachable("Invalid ABI"); - - if (BigEndian) - resetDataLayout(("E-" + Layout).str()); - else - resetDataLayout(("e-" + Layout).str()); - } - - - static const Builtin::Info BuiltinInfo[]; - std::string CPU; - bool IsMips16; - bool IsMicromips; - bool IsNan2008; - bool IsSingleFloat; - bool IsNoABICalls; - bool CanUseBSDABICalls; - enum MipsFloatABI { - HardFloat, SoftFloat - } FloatABI; - enum DspRevEnum { - NoDSP, DSP1, DSP2 - } DspRev; - bool HasMSA; - bool DisableMadd4; - -protected: - bool HasFP64; - std::string ABI; - -public: - MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), IsMips16(false), IsMicromips(false), - IsNan2008(false), IsSingleFloat(false), IsNoABICalls(false), - CanUseBSDABICalls(false), FloatABI(HardFloat), DspRev(NoDSP), - HasMSA(false), DisableMadd4(false), HasFP64(false) { - TheCXXABI.set(TargetCXXABI::GenericMIPS); - - setABI((getTriple().getArch() == llvm::Triple::mips || - getTriple().getArch() == llvm::Triple::mipsel) - ? "o32" - : "n64"); - - CPU = ABI == "o32" ? "mips32r2" : "mips64r2"; - - CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::OpenBSD; - } - - bool isNaN2008Default() const { - return CPU == "mips32r6" || CPU == "mips64r6"; - } - - bool isFP64Default() const { - return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; - } - - bool isNan2008() const override { - return IsNan2008; - } - - bool processorSupportsGPR64() const { - return llvm::StringSwitch<bool>(CPU) - .Case("mips3", true) - .Case("mips4", true) - .Case("mips5", true) - .Case("mips64", true) - .Case("mips64r2", true) - .Case("mips64r3", true) - .Case("mips64r5", true) - .Case("mips64r6", true) - .Case("octeon", true) - .Default(false); - return false; - } - - StringRef getABI() const override { return ABI; } - bool setABI(const std::string &Name) override { - if (Name == "o32") { - setO32ABITypes(); - ABI = Name; - return true; - } - - if (Name == "n32") { - setN32ABITypes(); - ABI = Name; - return true; - } - if (Name == "n64") { - setN64ABITypes(); - ABI = Name; - return true; - } - return false; - } - - void setO32ABITypes() { - Int64Type = SignedLongLong; - IntMaxType = Int64Type; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - LongDoubleWidth = LongDoubleAlign = 64; - LongWidth = LongAlign = 32; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; - PointerWidth = PointerAlign = 32; - PtrDiffType = SignedInt; - SizeType = UnsignedInt; - SuitableAlign = 64; - } - - void setN32N64ABITypes() { - LongDoubleWidth = LongDoubleAlign = 128; - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - if (getTriple().getOS() == llvm::Triple::FreeBSD) { - LongDoubleWidth = LongDoubleAlign = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - } - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - SuitableAlign = 128; - } - - void setN64ABITypes() { - setN32N64ABITypes(); - if (getTriple().getOS() == llvm::Triple::OpenBSD) { - Int64Type = SignedLongLong; - } else { - Int64Type = SignedLong; - } - IntMaxType = Int64Type; - LongWidth = LongAlign = 64; - PointerWidth = PointerAlign = 64; - PtrDiffType = SignedLong; - SizeType = UnsignedLong; - } - - void setN32ABITypes() { - setN32N64ABITypes(); - Int64Type = SignedLongLong; - IntMaxType = Int64Type; - LongWidth = LongAlign = 32; - PointerWidth = PointerAlign = 32; - PtrDiffType = SignedInt; - SizeType = UnsignedInt; - } - - bool setCPU(const std::string &Name) override { - CPU = Name; - return llvm::StringSwitch<bool>(Name) - .Case("mips1", true) - .Case("mips2", true) - .Case("mips3", true) - .Case("mips4", true) - .Case("mips5", true) - .Case("mips32", true) - .Case("mips32r2", true) - .Case("mips32r3", true) - .Case("mips32r5", true) - .Case("mips32r6", true) - .Case("mips64", true) - .Case("mips64r2", true) - .Case("mips64r3", true) - .Case("mips64r5", true) - .Case("mips64r6", true) - .Case("octeon", true) - .Case("p5600", true) - .Default(false); - } - const std::string& getCPU() const { return CPU; } - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - if (CPU.empty()) - CPU = getCPU(); - if (CPU == "octeon") - Features["mips64r2"] = Features["cnmips"] = true; - else - Features[CPU] = true; - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - if (BigEndian) { - DefineStd(Builder, "MIPSEB", Opts); - Builder.defineMacro("_MIPSEB"); - } else { - DefineStd(Builder, "MIPSEL", Opts); - Builder.defineMacro("_MIPSEL"); - } - - Builder.defineMacro("__mips__"); - Builder.defineMacro("_mips"); - if (Opts.GNUMode) - Builder.defineMacro("mips"); - - if (ABI == "o32") { - Builder.defineMacro("__mips", "32"); - Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); - } else { - Builder.defineMacro("__mips", "64"); - Builder.defineMacro("__mips64"); - Builder.defineMacro("__mips64__"); - Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); - } - - const std::string ISARev = llvm::StringSwitch<std::string>(getCPU()) - .Cases("mips32", "mips64", "1") - .Cases("mips32r2", "mips64r2", "2") - .Cases("mips32r3", "mips64r3", "3") - .Cases("mips32r5", "mips64r5", "5") - .Cases("mips32r6", "mips64r6", "6") - .Default(""); - if (!ISARev.empty()) - Builder.defineMacro("__mips_isa_rev", ISARev); - - if (ABI == "o32") { - Builder.defineMacro("__mips_o32"); - Builder.defineMacro("_ABIO32", "1"); - Builder.defineMacro("_MIPS_SIM", "_ABIO32"); - } else if (ABI == "n32") { - Builder.defineMacro("__mips_n32"); - Builder.defineMacro("_ABIN32", "2"); - Builder.defineMacro("_MIPS_SIM", "_ABIN32"); - } else if (ABI == "n64") { - Builder.defineMacro("__mips_n64"); - Builder.defineMacro("_ABI64", "3"); - Builder.defineMacro("_MIPS_SIM", "_ABI64"); - } else - llvm_unreachable("Invalid ABI."); - - if (!IsNoABICalls) { - Builder.defineMacro("__mips_abicalls"); - if (CanUseBSDABICalls) - Builder.defineMacro("__ABICALLS__"); - } - - Builder.defineMacro("__REGISTER_PREFIX__", ""); - - switch (FloatABI) { - case HardFloat: - Builder.defineMacro("__mips_hard_float", Twine(1)); - break; - case SoftFloat: - Builder.defineMacro("__mips_soft_float", Twine(1)); - break; - } - - if (IsSingleFloat) - Builder.defineMacro("__mips_single_float", Twine(1)); - - Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); - Builder.defineMacro("_MIPS_FPSET", - Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); - - if (IsMips16) - Builder.defineMacro("__mips16", Twine(1)); - - if (IsMicromips) - Builder.defineMacro("__mips_micromips", Twine(1)); - - if (IsNan2008) - Builder.defineMacro("__mips_nan2008", Twine(1)); - - switch (DspRev) { - default: - break; - case DSP1: - Builder.defineMacro("__mips_dsp_rev", Twine(1)); - Builder.defineMacro("__mips_dsp", Twine(1)); - break; - case DSP2: - Builder.defineMacro("__mips_dsp_rev", Twine(2)); - Builder.defineMacro("__mips_dspr2", Twine(1)); - Builder.defineMacro("__mips_dsp", Twine(1)); - break; - } - - if (HasMSA) - Builder.defineMacro("__mips_msa", Twine(1)); - - if (DisableMadd4) - Builder.defineMacro("__mips_no_madd4", Twine(1)); - - Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); - Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); - Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); - - Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); - Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); - - // These shouldn't be defined for MIPS-I but there's no need to check - // for that since MIPS-I isn't supported. - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); - - // 32-bit MIPS processors don't have the necessary lld/scd instructions - // found in 64-bit processors. In the case of O32 on a 64-bit processor, - // the instructions exist but using them violates the ABI since they - // require 64-bit GPRs and O32 only supports 32-bit GPRs. - if (ABI == "n32" || ABI == "n64") - Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - bool hasFeature(StringRef Feature) const override { - return llvm::StringSwitch<bool>(Feature) - .Case("mips", true) - .Case("fp64", HasFP64) - .Default(false); - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override { - static const char *const GCCRegNames[] = { - // CPU register names - // Must match second column of GCCRegAliases - "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", - "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", - "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", - // Floating point register names - "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", - "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", - "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", - "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", - // Hi/lo and condition register names - "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", - "$fcc5","$fcc6","$fcc7","$ac1hi","$ac1lo","$ac2hi","$ac2lo", - "$ac3hi","$ac3lo", - // MSA register names - "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", - "$w8", "$w9", "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", - "$w16", "$w17", "$w18", "$w19", "$w20", "$w21", "$w22", "$w23", - "$w24", "$w25", "$w26", "$w27", "$w28", "$w29", "$w30", "$w31", - // MSA control register names - "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", - "$msarequest", "$msamap", "$msaunmap" - }; - return llvm::makeArrayRef(GCCRegNames); - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: - return false; - case 'r': // CPU registers. - case 'd': // Equivalent to "r" unless generating MIPS16 code. - case 'y': // Equivalent to "r", backward compatibility only. - case 'f': // floating-point registers. - case 'c': // $25 for indirect jumps - case 'l': // lo register - case 'x': // hilo register pair - Info.setAllowsRegister(); - return true; - case 'I': // Signed 16-bit constant - case 'J': // Integer 0 - case 'K': // Unsigned 16-bit constant - case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) - case 'M': // Constants not loadable via lui, addiu, or ori - case 'N': // Constant -1 to -65535 - case 'O': // A signed 15-bit constant - case 'P': // A constant between 1 go 65535 - return true; - case 'R': // An address that can be used in a non-macro load or store - Info.setAllowsMemory(); - return true; - case 'Z': - if (Name[1] == 'C') { // An address usable by ll, and sc. - Info.setAllowsMemory(); - Name++; // Skip over 'Z'. - return true; - } - return false; - } - } - - std::string convertConstraint(const char *&Constraint) const override { - std::string R; - switch (*Constraint) { - case 'Z': // Two-character constraint; add "^" hint for later parsing. - if (Constraint[1] == 'C') { - R = std::string("^") + std::string(Constraint, 2); - Constraint++; - return R; - } - break; - } - return TargetInfo::convertConstraint(Constraint); - } - - const char *getClobbers() const override { - // In GCC, $1 is not widely used in generated code (it's used only in a few - // specific situations), so there is no real need for users to add it to - // the clobbers list if they want to use it in their inline assembly code. - // - // In LLVM, $1 is treated as a normal GPR and is always allocatable during - // code generation, so using it in inline assembly without adding it to the - // clobbers list can cause conflicts between the inline assembly code and - // the surrounding generated code. - // - // Another problem is that LLVM is allowed to choose $1 for inline assembly - // operands, which will conflict with the ".set at" assembler option (which - // we use only for inline assembly, in order to maintain compatibility with - // GCC) and will also conflict with the user's usage of $1. - // - // The easiest way to avoid these conflicts and keep $1 as an allocatable - // register for generated code is to automatically clobber $1 for all inline - // assembly code. - // - // FIXME: We should automatically clobber $1 only for inline assembly code - // which actually uses it. This would allow LLVM to use $1 for inline - // assembly operands if the user's assembly code doesn't use it. - return "~{$1}"; - } - - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) override { - IsMips16 = false; - IsMicromips = false; - IsNan2008 = isNaN2008Default(); - IsSingleFloat = false; - FloatABI = HardFloat; - DspRev = NoDSP; - HasFP64 = isFP64Default(); - - for (const auto &Feature : Features) { - if (Feature == "+single-float") - IsSingleFloat = true; - else if (Feature == "+soft-float") - FloatABI = SoftFloat; - else if (Feature == "+mips16") - IsMips16 = true; - else if (Feature == "+micromips") - IsMicromips = true; - else if (Feature == "+dsp") - DspRev = std::max(DspRev, DSP1); - else if (Feature == "+dspr2") - DspRev = std::max(DspRev, DSP2); - else if (Feature == "+msa") - HasMSA = true; - else if (Feature == "+nomadd4") - DisableMadd4 = true; - else if (Feature == "+fp64") - HasFP64 = true; - else if (Feature == "-fp64") - HasFP64 = false; - else if (Feature == "+nan2008") - IsNan2008 = true; - else if (Feature == "-nan2008") - IsNan2008 = false; - else if (Feature == "+noabicalls") - IsNoABICalls = true; - } - - setDataLayout(); - - return true; - } - - int getEHDataRegisterNumber(unsigned RegNo) const override { - if (RegNo == 0) return 4; - if (RegNo == 1) return 5; - return -1; - } - - bool isCLZForZeroUndef() const override { return false; } - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - static const TargetInfo::GCCRegAlias O32RegAliases[] = { - {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, - {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, - {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"}, - {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"}, - {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"}, - {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, - {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, - {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, - {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, - {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, - {{"ra"}, "$31"}}; - static const TargetInfo::GCCRegAlias NewABIRegAliases[] = { - {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, - {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, - {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"}, - {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"}, - {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"}, - {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, - {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, - {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, - {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, - {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, - {{"ra"}, "$31"}}; - if (ABI == "o32") - return llvm::makeArrayRef(O32RegAliases); - return llvm::makeArrayRef(NewABIRegAliases); - } - - bool hasInt128Type() const override { - return ABI == "n32" || ABI == "n64"; - } - - bool validateTarget(DiagnosticsEngine &Diags) const override { - // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle - // this yet. It's better to fail here than on the backend assertion. - if (processorSupportsGPR64() && ABI == "o32") { - Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; - return false; - } - - // 64-bit ABI's require 64-bit CPU's. - if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) { - Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; - return false; - } - - // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend - // can't handle this yet. It's better to fail here than on the - // backend assertion. - if ((getTriple().getArch() == llvm::Triple::mips64 || - getTriple().getArch() == llvm::Triple::mips64el) && - ABI == "o32") { - Diags.Report(diag::err_target_unsupported_abi_for_triple) - << ABI << getTriple().str(); - return false; - } - - // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend - // can't handle this yet. It's better to fail here than on the - // backend assertion. - if ((getTriple().getArch() == llvm::Triple::mips || - getTriple().getArch() == llvm::Triple::mipsel) && - (ABI == "n32" || ABI == "n64")) { - Diags.Report(diag::err_target_unsupported_abi_for_triple) - << ABI << getTriple().str(); - return false; - } - - return true; - } -}; - -const Builtin::Info MipsTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsMips.def" -}; - -class PNaClTargetInfo : public TargetInfo { -public: - PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : TargetInfo(Triple) { - this->LongAlign = 32; - this->LongWidth = 32; - this->PointerAlign = 32; - this->PointerWidth = 32; - this->IntMaxType = TargetInfo::SignedLongLong; - this->Int64Type = TargetInfo::SignedLongLong; - this->DoubleAlign = 64; - this->LongDoubleWidth = 64; - this->LongDoubleAlign = 64; - this->SizeType = TargetInfo::UnsignedInt; - this->PtrDiffType = TargetInfo::SignedInt; - this->IntPtrType = TargetInfo::SignedInt; - this->RegParmMax = 0; // Disallow regparm - } - - void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - Builder.defineMacro("__le32__"); - Builder.defineMacro("__pnacl__"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - getArchDefines(Opts, Builder); - } - bool hasFeature(StringRef Feature) const override { - return Feature == "pnacl"; - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::PNaClABIBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const override; - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - return false; - } - - const char *getClobbers() const override { - return ""; - } -}; - -ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { - return None; -} - -ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const { - return None; + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); + addCygMingDefines(Opts, Builder); } -// We attempt to use PNaCl (le32) frontend and Mips32EL backend. -class NaClMips32TargetInfo : public MipsTargetInfo { -public: - NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : MipsTargetInfo(Triple, Opts) {} - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::PNaClABIBuiltinVaList; - } -}; - -class Le64TargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - -public: - Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - NoAsmVariants = true; - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "unix", Opts); - defineCPUMacros(Builder, "le64", /*Tuning=*/false); - Builder.defineMacro("__ELF__"); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::PNaClABIBuiltinVaList; - } - const char *getClobbers() const override { return ""; } - ArrayRef<const char *> getGCCRegNames() const override { - return None; - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - return false; - } - - bool hasProtectedVisibility() const override { return false; } -}; - -class WebAssemblyTargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; - - enum SIMDEnum { - NoSIMD, - SIMD128, - } SIMDLevel; - -public: - explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &) - : TargetInfo(T), SIMDLevel(NoSIMD) { - NoAsmVariants = true; - SuitableAlign = 128; - LargeArrayMinWidth = 128; - LargeArrayAlign = 128; - SimdDefaultAlign = 128; - SigAtomicType = SignedLong; - LongDoubleWidth = LongDoubleAlign = 128; - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - } - -protected: - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - defineCPUMacros(Builder, "wasm", /*Tuning=*/false); - if (SIMDLevel >= SIMD128) - Builder.defineMacro("__wasm_simd128__"); - } - -private: - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - if (CPU == "bleeding-edge") - Features["simd128"] = true; - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); - } - bool hasFeature(StringRef Feature) const final { - return llvm::StringSwitch<bool>(Feature) - .Case("simd128", SIMDLevel >= SIMD128) - .Default(false); - } - bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) final { - for (const auto &Feature : Features) { - if (Feature == "+simd128") { - SIMDLevel = std::max(SIMDLevel, SIMD128); - continue; - } - if (Feature == "-simd128") { - SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); - continue; - } - - Diags.Report(diag::err_opt_not_valid_with_opt) << Feature - << "-target-feature"; - return false; - } - return true; - } - bool setCPU(const std::string &Name) final { - return llvm::StringSwitch<bool>(Name) - .Case("mvp", true) - .Case("bleeding-edge", true) - .Case("generic", true) - .Default(false); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const final { - return llvm::makeArrayRef(BuiltinInfo, - clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin); - } - BuiltinVaListKind getBuiltinVaListKind() const final { - return VoidPtrBuiltinVaList; - } - ArrayRef<const char *> getGCCRegNames() const final { - return None; - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final { - return None; - } - bool - validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const final { - return false; - } - const char *getClobbers() const final { return ""; } - bool isCLZForZeroUndef() const final { return false; } - bool hasInt128Type() const final { return true; } - IntType getIntTypeByWidth(unsigned BitWidth, - bool IsSigned) const final { - // WebAssembly prefers long long for explicitly 64-bit integers. - return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) - : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); - } - IntType getLeastIntTypeByWidth(unsigned BitWidth, - bool IsSigned) const final { - // WebAssembly uses long long for int_least64_t and int_fast64_t. - return BitWidth == 64 - ? (IsSigned ? SignedLongLong : UnsignedLongLong) - : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); - } -}; - -const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsWebAssembly.def" -}; - -class WebAssembly32TargetInfo : public WebAssemblyTargetInfo { -public: - explicit WebAssembly32TargetInfo(const llvm::Triple &T, - const TargetOptions &Opts) - : WebAssemblyTargetInfo(T, Opts) { - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128"); - } - -protected: - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); - defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); - } -}; - -class WebAssembly64TargetInfo : public WebAssemblyTargetInfo { -public: - explicit WebAssembly64TargetInfo(const llvm::Triple &T, - const TargetOptions &Opts) - : WebAssemblyTargetInfo(T, Opts) { - LongAlign = LongWidth = 64; - PointerAlign = PointerWidth = 64; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - SizeType = UnsignedLong; - PtrDiffType = SignedLong; - IntPtrType = SignedLong; - resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); - } - -protected: - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); - defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); - } -}; - -const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsLe64.def" -}; - -static const unsigned SPIRAddrSpaceMap[] = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 4, // opencl_generic - 0, // cuda_device - 0, // cuda_constant - 0 // cuda_shared -}; -class SPIRTargetInfo : public TargetInfo { -public: - SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - assert(getTriple().getOS() == llvm::Triple::UnknownOS && - "SPIR target must use unknown OS"); - assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && - "SPIR target must use unknown environment type"); - TLSSupported = false; - LongWidth = LongAlign = 64; - AddrSpaceMap = &SPIRAddrSpaceMap; - UseAddrSpaceMapMangling = true; - // Define available target features - // These must be defined in sorted order! - NoAsmVariants = true; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "SPIR", Opts); - } - bool hasFeature(StringRef Feature) const override { - return Feature == "spir"; - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } - const char *getClobbers() const override { return ""; } - ArrayRef<const char *> getGCCRegNames() const override { return None; } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - return true; - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK - : CCCR_Warning; - } - - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { - return CC_SpirFunction; - } - - void setSupportedOpenCLOpts() override { - // Assume all OpenCL extensions and optional core features are supported - // for SPIR since it is a generic target. - getSupportedOpenCLOpts().supportAll(); - } -}; - -class SPIR32TargetInfo : public SPIRTargetInfo { -public: - SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : SPIRTargetInfo(Triple, Opts) { - PointerWidth = PointerAlign = 32; - SizeType = TargetInfo::UnsignedInt; - PtrDiffType = IntPtrType = TargetInfo::SignedInt; - resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" - "v96:128-v192:256-v256:256-v512:512-v1024:1024"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "SPIR32", Opts); - } -}; - -class SPIR64TargetInfo : public SPIRTargetInfo { -public: - SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : SPIRTargetInfo(Triple, Opts) { - PointerWidth = PointerAlign = 64; - SizeType = TargetInfo::UnsignedLong; - PtrDiffType = IntPtrType = TargetInfo::SignedLong; - resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" - "v96:128-v192:256-v256:256-v512:512-v1024:1024"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - DefineStd(Builder, "SPIR64", Opts); - } -}; - -class XCoreTargetInfo : public TargetInfo { - static const Builtin::Info BuiltinInfo[]; -public: - XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - NoAsmVariants = true; - LongLongAlign = 32; - SuitableAlign = 32; - DoubleAlign = LongDoubleAlign = 32; - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - WCharType = UnsignedChar; - WIntType = UnsignedInt; - UseZeroLengthBitfieldAlignment = true; - resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32" - "-f64:32-a:0:32-n32"); - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__XS1B__"); - } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return llvm::makeArrayRef(BuiltinInfo, - clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin); - } - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - const char *getClobbers() const override { - return ""; - } - ArrayRef<const char *> getGCCRegNames() const override { - static const char * const GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" - }; - return llvm::makeArrayRef(GCCRegNames); - } - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - return false; - } - int getEHDataRegisterNumber(unsigned RegNo) const override { - // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister - return (RegNo < 2)? RegNo : -1; - } - bool allowsLargerPreferedTypeAlignment() const override { - return false; - } -}; - -const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, -#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ - { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, -#include "clang/Basic/BuiltinsXCore.def" -}; - -// x86_32 Android target -class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> { -public: - AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) { - SuitableAlign = 32; - LongDoubleWidth = 64; - LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - } -}; - -// x86_64 Android target -class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> { -public: - AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) - : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) { - LongDoubleFormat = &llvm::APFloat::IEEEquad(); - } - - bool useFloat128ManglingForLongDouble() const override { - return true; - } -}; - -// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes -class RenderScript32TargetInfo : public ARMleTargetInfo { -public: - RenderScript32TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), - Triple.getOSName(), - Triple.getEnvironmentName()), - Opts) { - IsRenderScriptTarget = true; - LongWidth = LongAlign = 64; - } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__RENDERSCRIPT__"); - ARMleTargetInfo::getTargetDefines(Opts, Builder); - } -}; - -// 64-bit RenderScript is aarch64 -class RenderScript64TargetInfo : public AArch64leTargetInfo { -public: - RenderScript64TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), - Triple.getOSName(), - Triple.getEnvironmentName()), - Opts) { - IsRenderScriptTarget = true; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("__RENDERSCRIPT__"); - AArch64leTargetInfo::getTargetDefines(Opts, Builder); - } -}; - -/// Information about a specific microcontroller. -struct MCUInfo { - const char *Name; - const char *DefineName; -}; - -// This list should be kept up-to-date with AVRDevices.td in LLVM. -static ArrayRef<MCUInfo> AVRMcus = { - { "at90s1200", "__AVR_AT90S1200__" }, - { "attiny11", "__AVR_ATtiny11__" }, - { "attiny12", "__AVR_ATtiny12__" }, - { "attiny15", "__AVR_ATtiny15__" }, - { "attiny28", "__AVR_ATtiny28__" }, - { "at90s2313", "__AVR_AT90S2313__" }, - { "at90s2323", "__AVR_AT90S2323__" }, - { "at90s2333", "__AVR_AT90S2333__" }, - { "at90s2343", "__AVR_AT90S2343__" }, - { "attiny22", "__AVR_ATtiny22__" }, - { "attiny26", "__AVR_ATtiny26__" }, - { "at86rf401", "__AVR_AT86RF401__" }, - { "at90s4414", "__AVR_AT90S4414__" }, - { "at90s4433", "__AVR_AT90S4433__" }, - { "at90s4434", "__AVR_AT90S4434__" }, - { "at90s8515", "__AVR_AT90S8515__" }, - { "at90c8534", "__AVR_AT90c8534__" }, - { "at90s8535", "__AVR_AT90S8535__" }, - { "ata5272", "__AVR_ATA5272__" }, - { "attiny13", "__AVR_ATtiny13__" }, - { "attiny13a", "__AVR_ATtiny13A__" }, - { "attiny2313", "__AVR_ATtiny2313__" }, - { "attiny2313a", "__AVR_ATtiny2313A__" }, - { "attiny24", "__AVR_ATtiny24__" }, - { "attiny24a", "__AVR_ATtiny24A__" }, - { "attiny4313", "__AVR_ATtiny4313__" }, - { "attiny44", "__AVR_ATtiny44__" }, - { "attiny44a", "__AVR_ATtiny44A__" }, - { "attiny84", "__AVR_ATtiny84__" }, - { "attiny84a", "__AVR_ATtiny84A__" }, - { "attiny25", "__AVR_ATtiny25__" }, - { "attiny45", "__AVR_ATtiny45__" }, - { "attiny85", "__AVR_ATtiny85__" }, - { "attiny261", "__AVR_ATtiny261__" }, - { "attiny261a", "__AVR_ATtiny261A__" }, - { "attiny461", "__AVR_ATtiny461__" }, - { "attiny461a", "__AVR_ATtiny461A__" }, - { "attiny861", "__AVR_ATtiny861__" }, - { "attiny861a", "__AVR_ATtiny861A__" }, - { "attiny87", "__AVR_ATtiny87__" }, - { "attiny43u", "__AVR_ATtiny43U__" }, - { "attiny48", "__AVR_ATtiny48__" }, - { "attiny88", "__AVR_ATtiny88__" }, - { "attiny828", "__AVR_ATtiny828__" }, - { "at43usb355", "__AVR_AT43USB355__" }, - { "at76c711", "__AVR_AT76C711__" }, - { "atmega103", "__AVR_ATmega103__" }, - { "at43usb320", "__AVR_AT43USB320__" }, - { "attiny167", "__AVR_ATtiny167__" }, - { "at90usb82", "__AVR_AT90USB82__" }, - { "at90usb162", "__AVR_AT90USB162__" }, - { "ata5505", "__AVR_ATA5505__" }, - { "atmega8u2", "__AVR_ATmega8U2__" }, - { "atmega16u2", "__AVR_ATmega16U2__" }, - { "atmega32u2", "__AVR_ATmega32U2__" }, - { "attiny1634", "__AVR_ATtiny1634__" }, - { "atmega8", "__AVR_ATmega8__" }, - { "ata6289", "__AVR_ATA6289__" }, - { "atmega8a", "__AVR_ATmega8A__" }, - { "ata6285", "__AVR_ATA6285__" }, - { "ata6286", "__AVR_ATA6286__" }, - { "atmega48", "__AVR_ATmega48__" }, - { "atmega48a", "__AVR_ATmega48A__" }, - { "atmega48pa", "__AVR_ATmega48PA__" }, - { "atmega48p", "__AVR_ATmega48P__" }, - { "atmega88", "__AVR_ATmega88__" }, - { "atmega88a", "__AVR_ATmega88A__" }, - { "atmega88p", "__AVR_ATmega88P__" }, - { "atmega88pa", "__AVR_ATmega88PA__" }, - { "atmega8515", "__AVR_ATmega8515__" }, - { "atmega8535", "__AVR_ATmega8535__" }, - { "atmega8hva", "__AVR_ATmega8HVA__" }, - { "at90pwm1", "__AVR_AT90PWM1__" }, - { "at90pwm2", "__AVR_AT90PWM2__" }, - { "at90pwm2b", "__AVR_AT90PWM2B__" }, - { "at90pwm3", "__AVR_AT90PWM3__" }, - { "at90pwm3b", "__AVR_AT90PWM3B__" }, - { "at90pwm81", "__AVR_AT90PWM81__" }, - { "ata5790", "__AVR_ATA5790__" }, - { "ata5795", "__AVR_ATA5795__" }, - { "atmega16", "__AVR_ATmega16__" }, - { "atmega16a", "__AVR_ATmega16A__" }, - { "atmega161", "__AVR_ATmega161__" }, - { "atmega162", "__AVR_ATmega162__" }, - { "atmega163", "__AVR_ATmega163__" }, - { "atmega164a", "__AVR_ATmega164A__" }, - { "atmega164p", "__AVR_ATmega164P__" }, - { "atmega164pa", "__AVR_ATmega164PA__" }, - { "atmega165", "__AVR_ATmega165__" }, - { "atmega165a", "__AVR_ATmega165A__" }, - { "atmega165p", "__AVR_ATmega165P__" }, - { "atmega165pa", "__AVR_ATmega165PA__" }, - { "atmega168", "__AVR_ATmega168__" }, - { "atmega168a", "__AVR_ATmega168A__" }, - { "atmega168p", "__AVR_ATmega168P__" }, - { "atmega168pa", "__AVR_ATmega168PA__" }, - { "atmega169", "__AVR_ATmega169__" }, - { "atmega169a", "__AVR_ATmega169A__" }, - { "atmega169p", "__AVR_ATmega169P__" }, - { "atmega169pa", "__AVR_ATmega169PA__" }, - { "atmega32", "__AVR_ATmega32__" }, - { "atmega32a", "__AVR_ATmega32A__" }, - { "atmega323", "__AVR_ATmega323__" }, - { "atmega324a", "__AVR_ATmega324A__" }, - { "atmega324p", "__AVR_ATmega324P__" }, - { "atmega324pa", "__AVR_ATmega324PA__" }, - { "atmega325", "__AVR_ATmega325__" }, - { "atmega325a", "__AVR_ATmega325A__" }, - { "atmega325p", "__AVR_ATmega325P__" }, - { "atmega325pa", "__AVR_ATmega325PA__" }, - { "atmega3250", "__AVR_ATmega3250__" }, - { "atmega3250a", "__AVR_ATmega3250A__" }, - { "atmega3250p", "__AVR_ATmega3250P__" }, - { "atmega3250pa", "__AVR_ATmega3250PA__" }, - { "atmega328", "__AVR_ATmega328__" }, - { "atmega328p", "__AVR_ATmega328P__" }, - { "atmega329", "__AVR_ATmega329__" }, - { "atmega329a", "__AVR_ATmega329A__" }, - { "atmega329p", "__AVR_ATmega329P__" }, - { "atmega329pa", "__AVR_ATmega329PA__" }, - { "atmega3290", "__AVR_ATmega3290__" }, - { "atmega3290a", "__AVR_ATmega3290A__" }, - { "atmega3290p", "__AVR_ATmega3290P__" }, - { "atmega3290pa", "__AVR_ATmega3290PA__" }, - { "atmega406", "__AVR_ATmega406__" }, - { "atmega64", "__AVR_ATmega64__" }, - { "atmega64a", "__AVR_ATmega64A__" }, - { "atmega640", "__AVR_ATmega640__" }, - { "atmega644", "__AVR_ATmega644__" }, - { "atmega644a", "__AVR_ATmega644A__" }, - { "atmega644p", "__AVR_ATmega644P__" }, - { "atmega644pa", "__AVR_ATmega644PA__" }, - { "atmega645", "__AVR_ATmega645__" }, - { "atmega645a", "__AVR_ATmega645A__" }, - { "atmega645p", "__AVR_ATmega645P__" }, - { "atmega649", "__AVR_ATmega649__" }, - { "atmega649a", "__AVR_ATmega649A__" }, - { "atmega649p", "__AVR_ATmega649P__" }, - { "atmega6450", "__AVR_ATmega6450__" }, - { "atmega6450a", "__AVR_ATmega6450A__" }, - { "atmega6450p", "__AVR_ATmega6450P__" }, - { "atmega6490", "__AVR_ATmega6490__" }, - { "atmega6490a", "__AVR_ATmega6490A__" }, - { "atmega6490p", "__AVR_ATmega6490P__" }, - { "atmega64rfr2", "__AVR_ATmega64RFR2__" }, - { "atmega644rfr2", "__AVR_ATmega644RFR2__" }, - { "atmega16hva", "__AVR_ATmega16HVA__" }, - { "atmega16hva2", "__AVR_ATmega16HVA2__" }, - { "atmega16hvb", "__AVR_ATmega16HVB__" }, - { "atmega16hvbrevb", "__AVR_ATmega16HVBREVB__" }, - { "atmega32hvb", "__AVR_ATmega32HVB__" }, - { "atmega32hvbrevb", "__AVR_ATmega32HVBREVB__" }, - { "atmega64hve", "__AVR_ATmega64HVE__" }, - { "at90can32", "__AVR_AT90CAN32__" }, - { "at90can64", "__AVR_AT90CAN64__" }, - { "at90pwm161", "__AVR_AT90PWM161__" }, - { "at90pwm216", "__AVR_AT90PWM216__" }, - { "at90pwm316", "__AVR_AT90PWM316__" }, - { "atmega32c1", "__AVR_ATmega32C1__" }, - { "atmega64c1", "__AVR_ATmega64C1__" }, - { "atmega16m1", "__AVR_ATmega16M1__" }, - { "atmega32m1", "__AVR_ATmega32M1__" }, - { "atmega64m1", "__AVR_ATmega64M1__" }, - { "atmega16u4", "__AVR_ATmega16U4__" }, - { "atmega32u4", "__AVR_ATmega32U4__" }, - { "atmega32u6", "__AVR_ATmega32U6__" }, - { "at90usb646", "__AVR_AT90USB646__" }, - { "at90usb647", "__AVR_AT90USB647__" }, - { "at90scr100", "__AVR_AT90SCR100__" }, - { "at94k", "__AVR_AT94K__" }, - { "m3000", "__AVR_AT000__" }, - { "atmega128", "__AVR_ATmega128__" }, - { "atmega128a", "__AVR_ATmega128A__" }, - { "atmega1280", "__AVR_ATmega1280__" }, - { "atmega1281", "__AVR_ATmega1281__" }, - { "atmega1284", "__AVR_ATmega1284__" }, - { "atmega1284p", "__AVR_ATmega1284P__" }, - { "atmega128rfa1", "__AVR_ATmega128RFA1__" }, - { "atmega128rfr2", "__AVR_ATmega128RFR2__" }, - { "atmega1284rfr2", "__AVR_ATmega1284RFR2__" }, - { "at90can128", "__AVR_AT90CAN128__" }, - { "at90usb1286", "__AVR_AT90USB1286__" }, - { "at90usb1287", "__AVR_AT90USB1287__" }, - { "atmega2560", "__AVR_ATmega2560__" }, - { "atmega2561", "__AVR_ATmega2561__" }, - { "atmega256rfr2", "__AVR_ATmega256RFR2__" }, - { "atmega2564rfr2", "__AVR_ATmega2564RFR2__" }, - { "atxmega16a4", "__AVR_ATxmega16A4__" }, - { "atxmega16a4u", "__AVR_ATxmega16a4U__" }, - { "atxmega16c4", "__AVR_ATxmega16C4__" }, - { "atxmega16d4", "__AVR_ATxmega16D4__" }, - { "atxmega32a4", "__AVR_ATxmega32A4__" }, - { "atxmega32a4u", "__AVR_ATxmega32A4U__" }, - { "atxmega32c4", "__AVR_ATxmega32C4__" }, - { "atxmega32d4", "__AVR_ATxmega32D4__" }, - { "atxmega32e5", "__AVR_ATxmega32E5__" }, - { "atxmega16e5", "__AVR_ATxmega16E5__" }, - { "atxmega8e5", "__AVR_ATxmega8E5__" }, - { "atxmega32x1", "__AVR_ATxmega32X1__" }, - { "atxmega64a3", "__AVR_ATxmega64A3__" }, - { "atxmega64a3u", "__AVR_ATxmega64A3U__" }, - { "atxmega64a4u", "__AVR_ATxmega64A4U__" }, - { "atxmega64b1", "__AVR_ATxmega64B1__" }, - { "atxmega64b3", "__AVR_ATxmega64B3__" }, - { "atxmega64c3", "__AVR_ATxmega64C3__" }, - { "atxmega64d3", "__AVR_ATxmega64D3__" }, - { "atxmega64d4", "__AVR_ATxmega64D4__" }, - { "atxmega64a1", "__AVR_ATxmega64A1__" }, - { "atxmega64a1u", "__AVR_ATxmega64A1U__" }, - { "atxmega128a3", "__AVR_ATxmega128A3__" }, - { "atxmega128a3u", "__AVR_ATxmega128A3U__" }, - { "atxmega128b1", "__AVR_ATxmega128B1__" }, - { "atxmega128b3", "__AVR_ATxmega128B3__" }, - { "atxmega128c3", "__AVR_ATxmega128C3__" }, - { "atxmega128d3", "__AVR_ATxmega128D3__" }, - { "atxmega128d4", "__AVR_ATxmega128D4__" }, - { "atxmega192a3", "__AVR_ATxmega192A3__" }, - { "atxmega192a3u", "__AVR_ATxmega192A3U__" }, - { "atxmega192c3", "__AVR_ATxmega192C3__" }, - { "atxmega192d3", "__AVR_ATxmega192D3__" }, - { "atxmega256a3", "__AVR_ATxmega256A3__" }, - { "atxmega256a3u", "__AVR_ATxmega256A3U__" }, - { "atxmega256a3b", "__AVR_ATxmega256A3B__" }, - { "atxmega256a3bu", "__AVR_ATxmega256A3BU__" }, - { "atxmega256c3", "__AVR_ATxmega256C3__" }, - { "atxmega256d3", "__AVR_ATxmega256D3__" }, - { "atxmega384c3", "__AVR_ATxmega384C3__" }, - { "atxmega384d3", "__AVR_ATxmega384D3__" }, - { "atxmega128a1", "__AVR_ATxmega128A1__" }, - { "atxmega128a1u", "__AVR_ATxmega128A1U__" }, - { "atxmega128a4u", "__AVR_ATxmega128a4U__" }, - { "attiny4", "__AVR_ATtiny4__" }, - { "attiny5", "__AVR_ATtiny5__" }, - { "attiny9", "__AVR_ATtiny9__" }, - { "attiny10", "__AVR_ATtiny10__" }, - { "attiny20", "__AVR_ATtiny20__" }, - { "attiny40", "__AVR_ATtiny40__" }, - { "attiny102", "__AVR_ATtiny102__" }, - { "attiny104", "__AVR_ATtiny104__" }, -}; - -// AVR Target -class AVRTargetInfo : public TargetInfo { -public: - AVRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple) { - TLSSupported = false; - PointerWidth = 16; - PointerAlign = 8; - IntWidth = 16; - IntAlign = 8; - LongWidth = 32; - LongAlign = 8; - LongLongWidth = 64; - LongLongAlign = 8; - SuitableAlign = 8; - DefaultAlignForAttributeAligned = 8; - HalfWidth = 16; - HalfAlign = 8; - FloatWidth = 32; - FloatAlign = 8; - DoubleWidth = 32; - DoubleAlign = 8; - DoubleFormat = &llvm::APFloat::IEEEsingle(); - LongDoubleWidth = 32; - LongDoubleAlign = 8; - LongDoubleFormat = &llvm::APFloat::IEEEsingle(); - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - IntPtrType = SignedInt; - Char16Type = UnsignedInt; - WCharType = SignedInt; - WIntType = SignedInt; - Char32Type = UnsignedLong; - SigAtomicType = SignedChar; - resetDataLayout("e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"); - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - Builder.defineMacro("AVR"); - Builder.defineMacro("__AVR"); - Builder.defineMacro("__AVR__"); - - if (!this->CPU.empty()) { - auto It = std::find_if(AVRMcus.begin(), AVRMcus.end(), - [&](const MCUInfo &Info) { return Info.Name == this->CPU; }); - - if (It != AVRMcus.end()) - Builder.defineMacro(It->DefineName); - } - } - - ArrayRef<Builtin::Info> getTargetBuiltins() const override { - return None; - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - - const char *getClobbers() const override { - return ""; - } - - ArrayRef<const char *> getGCCRegNames() const override { - static const char * const GCCRegNames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "X", "Y", "Z", "SP" - }; - return llvm::makeArrayRef(GCCRegNames); - } - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - return None; - } - - ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override { - static const TargetInfo::AddlRegName AddlRegNames[] = { - { { "r26", "r27"}, 26 }, - { { "r28", "r29"}, 27 }, - { { "r30", "r31"}, 28 }, - { { "SPL", "SPH"}, 29 }, - }; - return llvm::makeArrayRef(AddlRegNames); - } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - // There aren't any multi-character AVR specific constraints. - if (StringRef(Name).size() > 1) return false; - - switch (*Name) { - default: return false; - case 'a': // Simple upper registers - case 'b': // Base pointer registers pairs - case 'd': // Upper register - case 'l': // Lower registers - case 'e': // Pointer register pairs - case 'q': // Stack pointer register - case 'r': // Any register - case 'w': // Special upper register pairs - case 't': // Temporary register - case 'x': case 'X': // Pointer register pair X - case 'y': case 'Y': // Pointer register pair Y - case 'z': case 'Z': // Pointer register pair Z - Info.setAllowsRegister(); - return true; - case 'I': // 6-bit positive integer constant - Info.setRequiresImmediate(0, 63); - return true; - case 'J': // 6-bit negative integer constant - Info.setRequiresImmediate(-63, 0); - return true; - case 'K': // Integer constant (Range: 2) - Info.setRequiresImmediate(2); - return true; - case 'L': // Integer constant (Range: 0) - Info.setRequiresImmediate(0); - return true; - case 'M': // 8-bit integer constant - Info.setRequiresImmediate(0, 0xff); - return true; - case 'N': // Integer constant (Range: -1) - Info.setRequiresImmediate(-1); - return true; - case 'O': // Integer constant (Range: 8, 16, 24) - Info.setRequiresImmediate({8, 16, 24}); - return true; - case 'P': // Integer constant (Range: 1) - Info.setRequiresImmediate(1); - return true; - case 'R': // Integer constant (Range: -6 to 5) - Info.setRequiresImmediate(-6, 5); - return true; - case 'G': // Floating point constant - case 'Q': // A memory address based on Y or Z pointer with displacement. - return true; - } - - return false; - } - - IntType getIntTypeByWidth(unsigned BitWidth, - bool IsSigned) const final { - // AVR prefers int for 16-bit integers. - return BitWidth == 16 ? (IsSigned ? SignedInt : UnsignedInt) - : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); - } - - IntType getLeastIntTypeByWidth(unsigned BitWidth, - bool IsSigned) const final { - // AVR uses int for int_least16_t and int_fast16_t. - return BitWidth == 16 - ? (IsSigned ? SignedInt : UnsignedInt) - : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); - } - - bool setCPU(const std::string &Name) override { - bool IsFamily = llvm::StringSwitch<bool>(Name) - .Case("avr1", true) - .Case("avr2", true) - .Case("avr25", true) - .Case("avr3", true) - .Case("avr31", true) - .Case("avr35", true) - .Case("avr4", true) - .Case("avr5", true) - .Case("avr51", true) - .Case("avr6", true) - .Case("avrxmega1", true) - .Case("avrxmega2", true) - .Case("avrxmega3", true) - .Case("avrxmega4", true) - .Case("avrxmega5", true) - .Case("avrxmega6", true) - .Case("avrxmega7", true) - .Case("avrtiny", true) - .Default(false); - - if (IsFamily) this->CPU = Name; - - bool IsMCU = std::find_if(AVRMcus.begin(), AVRMcus.end(), - [&](const MCUInfo &Info) { return Info.Name == Name; }) != AVRMcus.end(); - - if (IsMCU) this->CPU = Name; - - return IsFamily || IsMCU; - } - -protected: - std::string CPU; -}; - -} // end anonymous namespace - //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// -static TargetInfo *AllocateTarget(const llvm::Triple &Triple, - const TargetOptions &Opts) { +TargetInfo *AllocateTarget(const llvm::Triple &Triple, + const TargetOptions &Opts) { llvm::Triple::OSType os = Triple.getOS(); switch (Triple.getArch()) { @@ -9558,7 +149,13 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); case llvm::Triple::Win32: - return new MicrosoftARM64TargetInfo(Triple, Opts); + switch (Triple.getEnvironment()) { + case llvm::Triple::GNU: + return new MinGWARM64TargetInfo(Triple, Opts); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftARM64TargetInfo(Triple, Opts); + } default: return new AArch64leTargetInfo(Triple, Opts); } @@ -9593,8 +190,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NetBSDTargetInfo<ARMleTargetInfo>(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo<ARMleTargetInfo>(Triple, Opts); - case llvm::Triple::Bitrig: - return new BitrigTargetInfo<ARMleTargetInfo>(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo<ARMleTargetInfo>(Triple, Opts); case llvm::Triple::NaCl: @@ -9629,8 +224,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts); - case llvm::Triple::Bitrig: - return new BitrigTargetInfo<ARMbeTargetInfo>(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo<ARMbeTargetInfo>(Triple, Opts); case llvm::Triple::NaCl: @@ -9861,8 +454,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NetBSDI386TargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDI386TargetInfo(Triple, Opts); - case llvm::Triple::Bitrig: - return new BitrigI386TargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts); case llvm::Triple::KFreeBSD: @@ -9918,8 +509,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NetBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDX86_64TargetInfo(Triple, Opts); - case llvm::Triple::Bitrig: - return new BitrigX86_64TargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); case llvm::Triple::Fuchsia: @@ -9984,7 +573,10 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new LinuxTargetInfo<RenderScript64TargetInfo>(Triple, Opts); } } +} // namespace targets +} // namespace clang +using namespace clang::targets; /// CreateTargetInfo - Return the target info object for the specified target /// options. TargetInfo * @@ -10023,7 +615,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, llvm::StringMap<bool> Features; if (!Target->initFeatureMap(Features, Diags, Opts->CPU, Opts->FeaturesAsWritten)) - return nullptr; + return nullptr; // Add the features to the compile options. Opts->Features.clear(); @@ -10035,6 +627,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Target->setSupportedOpenCLOpts(); Target->setOpenCLExtensionOpts(); + Target->setMaxAtomicWidth(); if (!Target->validateTarget(Diags)) return nullptr; diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.h b/contrib/llvm/tools/clang/lib/Basic/Targets.h new file mode 100644 index 0000000000000..6fc967ddabee0 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.h @@ -0,0 +1,51 @@ +//===------- Targets.h - Declare target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares things required for construction of a TargetInfo object +// from a target triple. Typically individual targets will need to include from +// here in order to get these functions if required. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace targets { + +LLVM_LIBRARY_VISIBILITY +clang::TargetInfo *AllocateTarget(const llvm::Triple &Triple, + const clang::TargetOptions &Opts); + +/// DefineStd - Define a macro name and standard variants. For example if +/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" +/// when in GNU mode. +LLVM_LIBRARY_VISIBILITY +void DefineStd(clang::MacroBuilder &Builder, llvm::StringRef MacroName, + const clang::LangOptions &Opts); + +LLVM_LIBRARY_VISIBILITY +void defineCPUMacros(clang::MacroBuilder &Builder, llvm::StringRef CPUName, + bool Tuning = true); + +LLVM_LIBRARY_VISIBILITY +void addMinGWDefines(const llvm::Triple &Triple, const clang::LangOptions &Opts, + clang::MacroBuilder &Builder); + +LLVM_LIBRARY_VISIBILITY +void addCygMingDefines(const clang::LangOptions &Opts, + clang::MacroBuilder &Builder); +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.cpp new file mode 100644 index 0000000000000..62990dc23821e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.cpp @@ -0,0 +1,537 @@ +//===--- AArch64.cpp - Implement AArch64 target feature support -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AArch64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, +#include "clang/Basic/BuiltinsAArch64.def" +}; + +AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), ABI("aapcs") { + if (getTriple().getOS() == llvm::Triple::NetBSD || + getTriple().getOS() == llvm::Triple::OpenBSD) { + // NetBSD apparently prefers consistency across ARM targets to + // consistency across 64-bit targets. + Int64Type = SignedLongLong; + IntMaxType = SignedLongLong; + } else { + if (!getTriple().isOSDarwin()) + WCharType = UnsignedInt; + + Int64Type = SignedLong; + IntMaxType = SignedLong; + } + + + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxVectorAlign = 128; + MaxAtomicInlineWidth = 128; + MaxAtomicPromoteWidth = 128; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // AAPCS gives rules for bitfields. 7.1.7 says: "The container type + // contributes to the alignment of the containing aggregate in the same way + // a plain (non bit-field) member of that type would, without exception for + // zero-sized or anonymous bit-fields." + assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); + UseZeroLengthBitfieldAlignment = true; + + // AArch64 targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericAArch64); + + if (Triple.getOS() == llvm::Triple::Linux) + this->MCountName = "\01_mcount"; + else if (Triple.getOS() == llvm::Triple::UnknownOS) + this->MCountName = + Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount"; +} + +StringRef AArch64TargetInfo::getABI() const { return ABI; } + +bool AArch64TargetInfo::setABI(const std::string &Name) { + if (Name != "aapcs" && Name != "darwinpcs") + return false; + + ABI = Name; + return true; +} + +bool AArch64TargetInfo::isValidCPUName(StringRef Name) const { + return Name == "generic" || + llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID; +} + +bool AArch64TargetInfo::setCPU(const std::string &Name) { + return isValidCPUName(Name); +} + +void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); +} + +void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1 defines + getTargetDefinesARMV81A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__aarch64__"); + // For bare-metal none-eabi. + if (getTriple().getOS() == llvm::Triple::UnknownOS && + (getTriple().getEnvironment() == llvm::Triple::EABI || + getTriple().getEnvironment() == llvm::Triple::EABIHF)) + Builder.defineMacro("__ELF__"); + + // Target properties. + if (!getTriple().isOSWindows()) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } + + // ACLE predefines. Many can only have one possible value on v8 AArch64. + Builder.defineMacro("__ARM_ACLE", "200"); + Builder.defineMacro("__ARM_ARCH", "8"); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); + + Builder.defineMacro("__ARM_64BIT_STATE", "1"); + Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); + Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); + + Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE + Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); + + Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); + + // 0xe implies support for half, single and double precision operations. + Builder.defineMacro("__ARM_FP", "0xE"); + + // PCS specifies this for SysV variants, which is all we support. Other ABIs + // may choose __ARM_FP16_FORMAT_ALTERNATIVE. + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); + + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", + llvm::utostr(Opts.WCharSize ? Opts.WCharSize : 4)); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); + + if (FPU & NeonMode) { + Builder.defineMacro("__ARM_NEON", "1"); + // 64-bit NEON supports half, single and double precision operations. + Builder.defineMacro("__ARM_NEON_FP", "0xE"); + } + + if (FPU & SveMode) + Builder.defineMacro("__ARM_FEATURE_SVE", "1"); + + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + + if (Unaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + switch (ArchKind) { + default: + break; + case llvm::AArch64::ArchKind::ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + } + + // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +} + +ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool AArch64TargetInfo::hasFeature(StringRef Feature) const { + return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || + (Feature == "neon" && (FPU & NeonMode)) || + (Feature == "sve" && (FPU & SveMode)); +} + +bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FPU = FPUMode; + CRC = 0; + Crypto = 0; + Unaligned = 1; + HasFullFP16 = 0; + ArchKind = llvm::AArch64::ArchKind::ARMV8A; + + for (const auto &Feature : Features) { + if (Feature == "+neon") + FPU |= NeonMode; + if (Feature == "+sve") + FPU |= SveMode; + if (Feature == "+crc") + CRC = 1; + if (Feature == "+crypto") + Crypto = 1; + if (Feature == "+strict-align") + Unaligned = 0; + if (Feature == "+v8.1a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_1A; + if (Feature == "+v8.2a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_2A; + if (Feature == "+fullfp16") + HasFullFP16 = 1; + } + + setDataLayout(); + + return true; +} + +TargetInfo::CallingConvCheckResult +AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_OpenCLKernel: + case CC_Win64: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +bool AArch64TargetInfo::isCLZForZeroUndef() const { return false; } + +TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::AArch64ABIBuiltinVaList; +} + +const char *const AArch64TargetInfo::GCCRegNames[] = { + // 32-bit Integer registers + "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", + "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", + "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", + + // 64-bit Integer registers + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", + "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", + "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", + + // 32-bit floating point regsisters + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + + // 64-bit floating point regsisters + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", + "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + + // Vector registers + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", + "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", + "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" +}; + +ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { + {{"w31"}, "wsp"}, {{"x29"}, "fp"}, {{"x30"}, "lr"}, {{"x31"}, "sp"}, + // The S/D/Q and W/X registers overlap, but aren't really aliases; we + // don't want to substitute one of these for a different-sized one. +}; + +ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool AArch64TargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + case 'w': // Floating point and SIMD registers (V0-V31) + Info.setAllowsRegister(); + return true; + case 'I': // Constant that can be used with an ADD instruction + case 'J': // Constant that can be used with a SUB instruction + case 'K': // Constant that can be used with a 32-bit logical instruction + case 'L': // Constant that can be used with a 64-bit logical instruction + case 'M': // Constant that can be used as a 32-bit MOV immediate + case 'N': // Constant that can be used as a 64-bit MOV immediate + case 'Y': // Floating point constant zero + case 'Z': // Integer constant zero + return true; + case 'Q': // A memory reference with base register and no offset + Info.setAllowsMemory(); + return true; + case 'S': // A symbolic address + Info.setAllowsRegister(); + return true; + case 'U': + // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. + // Utf: A memory address suitable for ldp/stp in TF mode. + // Usa: An absolute symbolic address. + // Ush: The high part (bits 32:12) of a pc-relative symbolic address. + llvm_unreachable("FIXME: Unimplemented support for U* constraints."); + case 'z': // Zero register, wzr or xzr + Info.setAllowsRegister(); + return true; + case 'x': // Floating point and SIMD registers (V0-V15) + Info.setAllowsRegister(); + return true; + } + return false; +} + +bool AArch64TargetInfo::validateConstraintModifier( + StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: + return true; + case 'z': + case 'r': { + switch (Modifier) { + case 'x': + case 'w': + // For now assume that the person knows what they're + // doing with the modifier. + return true; + default: + // By default an 'r' constraint will be in the 'x' + // registers. + if (Size == 64) + return true; + + SuggestedModifier = "w"; + return false; + } + } + } +} + +const char *AArch64TargetInfo::getClobbers() const { return ""; } + +int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; +} + +AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64TargetInfo(Triple, Opts) {} + +void AArch64leTargetInfo::setDataLayout() { + if (getTriple().isOSBinFormatMachO()) + resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); + else + resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); +} + +void AArch64leTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64EL__"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); +} + +AArch64beTargetInfo::AArch64beTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64TargetInfo(Triple, Opts) {} + +void AArch64beTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64EB__"); + Builder.defineMacro("__AARCH_BIG_ENDIAN"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); +} + +void AArch64beTargetInfo::setDataLayout() { + assert(!getTriple().isOSBinFormatMachO()); + resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); +} + +WindowsARM64TargetInfo::WindowsARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) { + + // This is an LLP64 platform. + // int:4, long:4, long long:8, long double:8. + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + SizeType = UnsignedLongLong; + PtrDiffType = SignedLongLong; + IntPtrType = SignedLongLong; +} + +void WindowsARM64TargetInfo::setDataLayout() { + resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"); +} + +TargetInfo::BuiltinVaListKind +WindowsARM64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +TargetInfo::CallingConvCheckResult +WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86VectorCall: + return CCCR_Ignore; + case CC_C: + case CC_OpenCLKernel: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_Win64: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +MicrosoftARM64TargetInfo::MicrosoftARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARM64TargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::Microsoft); +} + +void MicrosoftARM64TargetInfo::getVisualStudioDefines( + const LangOptions &Opts, MacroBuilder &Builder) const { + WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, Builder); + Builder.defineMacro("_M_ARM64", "1"); +} + +void MicrosoftARM64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsTargetInfo::getTargetDefines(Opts, Builder); + getVisualStudioDefines(Opts, Builder); +} + +MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARM64TargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericAArch64); +} + +DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) { + Int64Type = SignedLongLong; + UseSignedCharForObjCBool = false; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + + TheCXXABI.set(TargetCXXABI::iOS64); +} + +void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts, + const llvm::Triple &Triple, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64_SIMD__"); + Builder.defineMacro("__ARM64_ARCH_8__"); + Builder.defineMacro("__ARM_NEON__"); + Builder.defineMacro("__LITTLE_ENDIAN__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + Builder.defineMacro("__arm64", "1"); + Builder.defineMacro("__arm64__", "1"); + + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); +} + +TargetInfo::BuiltinVaListKind +DarwinAArch64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +// 64-bit RenderScript is aarch64 +RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), + Triple.getOSName(), + Triple.getEnvironmentName()), + Opts) { + IsRenderScriptTarget = true; +} + +void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__RENDERSCRIPT__"); + AArch64leTargetInfo::getTargetDefines(Opts, Builder); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.h b/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.h new file mode 100644 index 0000000000000..33268f0f8d990 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AArch64.h @@ -0,0 +1,167 @@ +//===--- AArch64.h - Declare AArch64 target feature support -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares AArch64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H + +#include "OSTargets.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/Support/TargetParser.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { + virtual void setDataLayout() = 0; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + + enum FPUModeEnum { FPUMode, NeonMode = (1 << 0), SveMode = (1 << 1) }; + + unsigned FPU; + unsigned CRC; + unsigned Crypto; + unsigned Unaligned; + unsigned HasFullFP16; + llvm::AArch64::ArchKind ArchKind; + + static const Builtin::Info BuiltinInfo[]; + + std::string ABI; + +public: + AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + StringRef getABI() const override; + bool setABI(const std::string &Name) override; + + bool isValidCPUName(StringRef Name) const override; + bool setCPU(const std::string &Name) override; + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool hasFeature(StringRef Feature) const override; + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + + bool isCLZForZeroUndef() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override; + bool + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override; + const char *getClobbers() const override; + + int getEHDataRegisterNumber(unsigned RegNo) const override; +}; + +class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo { +public: + AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +private: + void setDataLayout() override; +}; + +class LLVM_LIBRARY_VISIBILITY WindowsARM64TargetInfo + : public WindowsTargetInfo<AArch64leTargetInfo> { + const llvm::Triple Triple; + +public: + WindowsARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void setDataLayout() override; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; +}; + +// Windows ARM, MS (C++) ABI +class LLVM_LIBRARY_VISIBILITY MicrosoftARM64TargetInfo + : public WindowsARM64TargetInfo { +public: + MicrosoftARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// ARM64 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWARM64TargetInfo + : public WindowsARM64TargetInfo { +public: + MinGWARM64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); +}; + +class LLVM_LIBRARY_VISIBILITY AArch64beTargetInfo : public AArch64TargetInfo { +public: + AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + +private: + void setDataLayout() override; +}; + +class LLVM_LIBRARY_VISIBILITY DarwinAArch64TargetInfo + : public DarwinTargetInfo<AArch64leTargetInfo> { +public: + DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + BuiltinVaListKind getBuiltinVaListKind() const override; + + protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override; +}; + +// 64-bit RenderScript is aarch64 +class LLVM_LIBRARY_VISIBILITY RenderScript64TargetInfo + : public AArch64leTargetInfo { +public: + RenderScript64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.cpp new file mode 100644 index 0000000000000..4c510e47379f5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.cpp @@ -0,0 +1,373 @@ +//===--- AMDGPU.cpp - Implement AMDGPU target feature support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AMDGPU TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AMDGPU.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +// If you edit the description strings, make sure you update +// getPointerWidthV(). + +static const char *const DataLayoutStringR600 = + "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; + +static const char *const DataLayoutStringSIPrivateIsZero = + "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32" + "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; + +static const char *const DataLayoutStringSIGenericIsZero = + "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-p4:32:32-p5:32:32" + "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-A5"; + +static const LangASMap AMDGPUPrivIsZeroDefIsGenMap = { + 4, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; + +static const LangASMap AMDGPUGenIsZeroDefIsGenMap = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 5, // opencl_private + 0, // opencl_generic + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; + +static const LangASMap AMDGPUPrivIsZeroDefIsPrivMap = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; + +static const LangASMap AMDGPUGenIsZeroDefIsPrivMap = { + 5, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 5, // opencl_private + 0, // opencl_generic + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; +} // namespace targets +} // namespace clang + +const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsAMDGPU.def" +}; + +const char *const AMDGPUTargetInfo::GCCRegNames[] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", + "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", + "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", + "v27", "v28", "v29", "v30", "v31", "v32", "v33", "v34", "v35", + "v36", "v37", "v38", "v39", "v40", "v41", "v42", "v43", "v44", + "v45", "v46", "v47", "v48", "v49", "v50", "v51", "v52", "v53", + "v54", "v55", "v56", "v57", "v58", "v59", "v60", "v61", "v62", + "v63", "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", + "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", "v80", + "v81", "v82", "v83", "v84", "v85", "v86", "v87", "v88", "v89", + "v90", "v91", "v92", "v93", "v94", "v95", "v96", "v97", "v98", + "v99", "v100", "v101", "v102", "v103", "v104", "v105", "v106", "v107", + "v108", "v109", "v110", "v111", "v112", "v113", "v114", "v115", "v116", + "v117", "v118", "v119", "v120", "v121", "v122", "v123", "v124", "v125", + "v126", "v127", "v128", "v129", "v130", "v131", "v132", "v133", "v134", + "v135", "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", + "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", "v152", + "v153", "v154", "v155", "v156", "v157", "v158", "v159", "v160", "v161", + "v162", "v163", "v164", "v165", "v166", "v167", "v168", "v169", "v170", + "v171", "v172", "v173", "v174", "v175", "v176", "v177", "v178", "v179", + "v180", "v181", "v182", "v183", "v184", "v185", "v186", "v187", "v188", + "v189", "v190", "v191", "v192", "v193", "v194", "v195", "v196", "v197", + "v198", "v199", "v200", "v201", "v202", "v203", "v204", "v205", "v206", + "v207", "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", + "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", "v224", + "v225", "v226", "v227", "v228", "v229", "v230", "v231", "v232", "v233", + "v234", "v235", "v236", "v237", "v238", "v239", "v240", "v241", "v242", + "v243", "v244", "v245", "v246", "v247", "v248", "v249", "v250", "v251", + "v252", "v253", "v254", "v255", "s0", "s1", "s2", "s3", "s4", + "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", + "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", + "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", + "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58", + "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67", + "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76", + "s77", "s78", "s79", "s80", "s81", "s82", "s83", "s84", "s85", + "s86", "s87", "s88", "s89", "s90", "s91", "s92", "s93", "s94", + "s95", "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", + "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", "s112", + "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121", + "s122", "s123", "s124", "s125", "s126", "s127", "exec", "vcc", "scc", + "m0", "flat_scratch", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi", + "flat_scratch_lo", "flat_scratch_hi" +}; + +ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +bool AMDGPUTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const { + + // XXX - What does the member GPU mean if device name string passed here? + if (getTriple().getArch() == llvm::Triple::amdgcn) { + if (CPU.empty()) + CPU = "tahiti"; + + switch (parseAMDGCNName(CPU)) { + case GK_GFX6: + case GK_GFX7: + break; + + case GK_GFX9: + Features["gfx9-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX8: + Features["s-memrealtime"] = true; + Features["16-bit-insts"] = true; + Features["dpp"] = true; + break; + + case GK_NONE: + return false; + default: + llvm_unreachable("unhandled subtarget"); + } + } else { + if (CPU.empty()) + CPU = "r600"; + + switch (parseR600Name(CPU)) { + case GK_R600: + case GK_R700: + case GK_EVERGREEN: + case GK_NORTHERN_ISLANDS: + break; + case GK_R600_DOUBLE_OPS: + case GK_R700_DOUBLE_OPS: + case GK_EVERGREEN_DOUBLE_OPS: + case GK_CAYMAN: + // TODO: Add fp64 when implemented. + break; + case GK_NONE: + return false; + default: + llvm_unreachable("unhandled subtarget"); + } + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec); +} + +void AMDGPUTargetInfo::adjustTargetOptions(const CodeGenOptions &CGOpts, + TargetOptions &TargetOpts) const { + bool hasFP32Denormals = false; + bool hasFP64Denormals = false; + for (auto &I : TargetOpts.FeaturesAsWritten) { + if (I == "+fp32-denormals" || I == "-fp32-denormals") + hasFP32Denormals = true; + if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals") + hasFP64Denormals = true; + } + if (!hasFP32Denormals) + TargetOpts.Features.push_back( + (Twine(hasFullSpeedFMAF32(TargetOpts.CPU) && !CGOpts.FlushDenorm + ? '+' + : '-') + + Twine("fp32-denormals")) + .str()); + // Always do not flush fp64 or fp16 denorms. + if (!hasFP64Denormals && hasFP64) + TargetOpts.Features.push_back("+fp64-fp16-denormals"); +} + +AMDGPUTargetInfo::GPUKind AMDGPUTargetInfo::parseR600Name(StringRef Name) { + return llvm::StringSwitch<GPUKind>(Name) + .Case("r600", GK_R600) + .Case("rv610", GK_R600) + .Case("rv620", GK_R600) + .Case("rv630", GK_R600) + .Case("rv635", GK_R600) + .Case("rs780", GK_R600) + .Case("rs880", GK_R600) + .Case("rv670", GK_R600_DOUBLE_OPS) + .Case("rv710", GK_R700) + .Case("rv730", GK_R700) + .Case("rv740", GK_R700_DOUBLE_OPS) + .Case("rv770", GK_R700_DOUBLE_OPS) + .Case("palm", GK_EVERGREEN) + .Case("cedar", GK_EVERGREEN) + .Case("sumo", GK_EVERGREEN) + .Case("sumo2", GK_EVERGREEN) + .Case("redwood", GK_EVERGREEN) + .Case("juniper", GK_EVERGREEN) + .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS) + .Case("cypress", GK_EVERGREEN_DOUBLE_OPS) + .Case("barts", GK_NORTHERN_ISLANDS) + .Case("turks", GK_NORTHERN_ISLANDS) + .Case("caicos", GK_NORTHERN_ISLANDS) + .Case("cayman", GK_CAYMAN) + .Case("aruba", GK_CAYMAN) + .Default(GK_NONE); +} + +AMDGPUTargetInfo::GPUKind AMDGPUTargetInfo::parseAMDGCNName(StringRef Name) { + return llvm::StringSwitch<GPUKind>(Name) + .Case("gfx600", GK_GFX6) + .Case("tahiti", GK_GFX6) + .Case("gfx601", GK_GFX6) + .Case("pitcairn", GK_GFX6) + .Case("verde", GK_GFX6) + .Case("oland", GK_GFX6) + .Case("hainan", GK_GFX6) + .Case("gfx700", GK_GFX7) + .Case("bonaire", GK_GFX7) + .Case("kaveri", GK_GFX7) + .Case("gfx701", GK_GFX7) + .Case("hawaii", GK_GFX7) + .Case("gfx702", GK_GFX7) + .Case("gfx703", GK_GFX7) + .Case("kabini", GK_GFX7) + .Case("mullins", GK_GFX7) + .Case("gfx800", GK_GFX8) + .Case("iceland", GK_GFX8) + .Case("gfx801", GK_GFX8) + .Case("carrizo", GK_GFX8) + .Case("gfx802", GK_GFX8) + .Case("tonga", GK_GFX8) + .Case("gfx803", GK_GFX8) + .Case("fiji", GK_GFX8) + .Case("polaris10", GK_GFX8) + .Case("polaris11", GK_GFX8) + .Case("gfx804", GK_GFX8) + .Case("gfx810", GK_GFX8) + .Case("stoney", GK_GFX8) + .Case("gfx900", GK_GFX9) + .Case("gfx901", GK_GFX9) + .Case("gfx902", GK_GFX9) + .Case("gfx903", GK_GFX9) + .Default(GK_NONE); +} + +void AMDGPUTargetInfo::setAddressSpaceMap(bool DefaultIsPrivate) { + if (isGenericZero(getTriple())) { + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap + : &AMDGPUGenIsZeroDefIsGenMap; + } else { + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap + : &AMDGPUPrivIsZeroDefIsGenMap; + } +} + +AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), + GPU(isAMDGCN(Triple) ? GK_GFX6 : parseR600Name(Opts.CPU)), + hasFP64(false), hasFMAF(false), hasLDEXPF(false), + AS(isGenericZero(Triple)) { + if (getTriple().getArch() == llvm::Triple::amdgcn) { + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = true; + } + if (getTriple().getArch() == llvm::Triple::r600) { + if (GPU == GK_EVERGREEN_DOUBLE_OPS || GPU == GK_CAYMAN) { + hasFMAF = true; + } + } + auto IsGenericZero = isGenericZero(Triple); + resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn + ? (IsGenericZero ? DataLayoutStringSIGenericIsZero + : DataLayoutStringSIPrivateIsZero) + : DataLayoutStringR600); + assert(DataLayout->getAllocaAddrSpace() == AS.Private); + + setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || + Triple.getEnvironment() == llvm::Triple::OpenCL || + Triple.getEnvironmentName() == "amdgizcl" || + !isAMDGCN(Triple)); + UseAddrSpaceMapMangling = true; + + // Set pointer width and alignment for target address space 0. + PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits(); + if (getMaxPointerWidth() == 64) { + LongWidth = LongAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } + + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; +} + +void AMDGPUTargetInfo::adjust(LangOptions &Opts) { + TargetInfo::adjust(Opts); + setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple())); +} + +ArrayRef<Builtin::Info> AMDGPUTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (getTriple().getArch() == llvm::Triple::amdgcn) + Builder.defineMacro("__AMDGCN__"); + else + Builder.defineMacro("__R600__"); + + if (hasFMAF) + Builder.defineMacro("__HAS_FMAF__"); + if (hasLDEXPF) + Builder.defineMacro("__HAS_LDEXPF__"); + if (hasFP64) + Builder.defineMacro("__HAS_FP64__"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.h b/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.h new file mode 100644 index 0000000000000..a4e070f1cb12e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AMDGPU.h @@ -0,0 +1,322 @@ +//===--- AMDGPU.h - Declare AMDGPU target feature support -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares AMDGPU TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + + struct LLVM_LIBRARY_VISIBILITY AddrSpace { + unsigned Generic, Global, Local, Constant, Private; + AddrSpace(bool IsGenericZero_ = false) { + if (IsGenericZero_) { + Generic = 0; + Global = 1; + Local = 3; + Constant = 2; + Private = 5; + } else { + Generic = 4; + Global = 1; + Local = 3; + Constant = 2; + Private = 0; + } + } + }; + + /// \brief The GPU profiles supported by the AMDGPU target. + enum GPUKind { + GK_NONE, + GK_R600, + GK_R600_DOUBLE_OPS, + GK_R700, + GK_R700_DOUBLE_OPS, + GK_EVERGREEN, + GK_EVERGREEN_DOUBLE_OPS, + GK_NORTHERN_ISLANDS, + GK_CAYMAN, + GK_GFX6, + GK_GFX7, + GK_GFX8, + GK_GFX9 + } GPU; + + bool hasFP64 : 1; + bool hasFMAF : 1; + bool hasLDEXPF : 1; + const AddrSpace AS; + + static bool hasFullSpeedFMAF32(StringRef GPUName) { + return parseAMDGCNName(GPUName) >= GK_GFX9; + } + + static bool isAMDGCN(const llvm::Triple &TT) { + return TT.getArch() == llvm::Triple::amdgcn; + } + + static bool isGenericZero(const llvm::Triple &TT) { + return TT.getEnvironmentName() == "amdgiz" || + TT.getEnvironmentName() == "amdgizcl"; + } + +public: + AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void setAddressSpaceMap(bool DefaultIsPrivate); + + void adjust(LangOptions &Opts) override; + + uint64_t getPointerWidthV(unsigned AddrSpace) const override { + if (GPU <= GK_CAYMAN) + return 32; + + if (AddrSpace == AS.Private || AddrSpace == AS.Local) { + return 32; + } + return 64; + } + + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } + + uint64_t getMaxPointerWidth() const override { + return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + /// Accepted register names: (n, m is unsigned integer, n < m) + /// v + /// s + /// {vn}, {v[n]} + /// {sn}, {s[n]} + /// {S} , where S is a special register name + ////{v[n:m]} + /// {s[n:m]} + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + static const ::llvm::StringSet<> SpecialRegs({ + "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma", + "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo", + "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi", + }); + + StringRef S(Name); + bool HasLeftParen = false; + if (S.front() == '{') { + HasLeftParen = true; + S = S.drop_front(); + } + if (S.empty()) + return false; + if (S.front() != 'v' && S.front() != 's') { + if (!HasLeftParen) + return false; + auto E = S.find('}'); + if (!SpecialRegs.count(S.substr(0, E))) + return false; + S = S.drop_front(E + 1); + if (!S.empty()) + return false; + // Found {S} where S is a special register. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + S = S.drop_front(); + if (!HasLeftParen) { + if (!S.empty()) + return false; + // Found s or v. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + bool HasLeftBracket = false; + if (!S.empty() && S.front() == '[') { + HasLeftBracket = true; + S = S.drop_front(); + } + unsigned long long N; + if (S.empty() || consumeUnsignedInteger(S, 10, N)) + return false; + if (!S.empty() && S.front() == ':') { + if (!HasLeftBracket) + return false; + S = S.drop_front(); + unsigned long long M; + if (consumeUnsignedInteger(S, 10, M) || N >= M) + return false; + } + if (HasLeftBracket) { + if (S.empty() || S.front() != ']') + return false; + S = S.drop_front(); + } + if (S.empty() || S.front() != '}') + return false; + S = S.drop_front(); + if (!S.empty()) + return false; + // Found {vn}, {sn}, {v[n]}, {s[n]}, {v[n:m]}, or {s[n:m]}. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeatureVec) const override; + + void adjustTargetOptions(const CodeGenOptions &CGOpts, + TargetOptions &TargetOpts) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + static GPUKind parseR600Name(StringRef Name); + + static GPUKind parseAMDGCNName(StringRef Name); + + bool isValidCPUName(StringRef Name) const override { + if (getTriple().getArch() == llvm::Triple::amdgcn) + return GK_NONE != parseAMDGCNName(Name); + else + return GK_NONE != parseR600Name(Name); + } + + bool setCPU(const std::string &Name) override { + if (getTriple().getArch() == llvm::Triple::amdgcn) + GPU = parseAMDGCNName(Name); + else + GPU = parseR600Name(Name); + + return GPU != GK_NONE; + } + + void setSupportedOpenCLOpts() override { + auto &Opts = getSupportedOpenCLOpts(); + Opts.support("cl_clang_storage_class_specifiers"); + Opts.support("cl_khr_icd"); + + if (hasFP64) + Opts.support("cl_khr_fp64"); + if (GPU >= GK_EVERGREEN) { + Opts.support("cl_khr_byte_addressable_store"); + Opts.support("cl_khr_global_int32_base_atomics"); + Opts.support("cl_khr_global_int32_extended_atomics"); + Opts.support("cl_khr_local_int32_base_atomics"); + Opts.support("cl_khr_local_int32_extended_atomics"); + } + if (GPU >= GK_GFX6) { + Opts.support("cl_khr_fp16"); + Opts.support("cl_khr_int64_base_atomics"); + Opts.support("cl_khr_int64_extended_atomics"); + Opts.support("cl_khr_mipmap_image"); + Opts.support("cl_khr_subgroups"); + Opts.support("cl_khr_3d_image_writes"); + Opts.support("cl_amd_media_ops"); + Opts.support("cl_amd_media_ops2"); + } + } + + LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const override { + switch (TK) { + case OCLTK_Image: + return LangAS::opencl_constant; + + case OCLTK_ClkEvent: + case OCLTK_Queue: + case OCLTK_ReserveID: + return LangAS::opencl_global; + + default: + return TargetInfo::getOpenCLTypeAddrSpace(TK); + } + } + + llvm::Optional<LangAS> getConstantAddressSpace() const override { + return getLangASFromTargetAS(AS.Constant); + } + + /// \returns Target specific vtbl ptr address space. + unsigned getVtblPtrAddressSpace() const override { return AS.Constant; } + + /// \returns If a target requires an address within a target specific address + /// space \p AddressSpace to be converted in order to be used, then return the + /// corresponding target specific DWARF address space. + /// + /// \returns Otherwise return None and no conversion will be emitted in the + /// DWARF. + Optional<unsigned> + getDWARFAddressSpace(unsigned AddressSpace) const override { + const unsigned DWARF_Private = 1; + const unsigned DWARF_Local = 2; + if (AddressSpace == AS.Private) { + return DWARF_Private; + } else if (AddressSpace == AS.Local) { + return DWARF_Local; + } else { + return None; + } + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + } + } + + // In amdgcn target the null pointer in global, constant, and generic + // address space has value 0 but in private and local address space has + // value ~0. + uint64_t getNullPointerValue(LangAS AS) const override { + return AS == LangAS::opencl_local ? ~0 : 0; + } +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.cpp new file mode 100644 index 0000000000000..fe261b7748550 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.cpp @@ -0,0 +1,1064 @@ +//===--- ARM.cpp - Implement ARM target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ARM TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +void ARMTargetInfo::setABIAAPCS() { + IsAAPCS = true; + + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + const llvm::Triple &T = getTriple(); + + bool IsNetBSD = T.getOS() == llvm::Triple::NetBSD; + bool IsOpenBSD = T.getOS() == llvm::Triple::OpenBSD; + if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD) + WCharType = UnsignedInt; + + UseBitFieldTypeAlignment = true; + + ZeroLengthBitfieldBoundary = 0; + + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. + if (T.isOSBinFormatMachO()) { + resetDataLayout(BigEndian + ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); + } else if (T.isOSWindows()) { + assert(!BigEndian && "Windows on ARM does not support big endian"); + resetDataLayout("e" + "-m:w" + "-p:32:32" + "-i64:64" + "-v128:64:128" + "-a:0:32" + "-n32" + "-S64"); + } else if (T.isOSNaCl()) { + assert(!BigEndian && "NaCl on ARM does not support big endian"); + resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"); + } else { + resetDataLayout(BigEndian + ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); + } + + // FIXME: Enumerated types are variable width in straight AAPCS. +} + +void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) { + const llvm::Triple &T = getTriple(); + + IsAAPCS = false; + + if (IsAAPCS16) + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + else + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + + WCharType = SignedInt; + + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + + /// gcc forces the alignment to 4 bytes, regardless of the type of the + /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in + /// gcc. + ZeroLengthBitfieldBoundary = 32; + + if (T.isOSBinFormatMachO() && IsAAPCS16) { + assert(!BigEndian && "AAPCS16 does not support big-endian"); + resetDataLayout("e-m:o-p:32:32-i64:64-a:0:32-n32-S128"); + } else if (T.isOSBinFormatMachO()) + resetDataLayout( + BigEndian + ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); + else + resetDataLayout( + BigEndian + ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); + + // FIXME: Override "preferred align" for double and long long. +} + +void ARMTargetInfo::setArchInfo() { + StringRef ArchName = getTriple().getArchName(); + + ArchISA = llvm::ARM::parseArchISA(ArchName); + CPU = llvm::ARM::getDefaultCPU(ArchName); + llvm::ARM::ArchKind AK = llvm::ARM::parseArch(ArchName); + if (AK != llvm::ARM::ArchKind::INVALID) + ArchKind = AK; + setArchInfo(ArchKind); +} + +void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) { + StringRef SubArch; + + // cache TargetParser info + ArchKind = Kind; + SubArch = llvm::ARM::getSubArch(ArchKind); + ArchProfile = llvm::ARM::parseArchProfile(SubArch); + ArchVersion = llvm::ARM::parseArchVersion(SubArch); + + // cache CPU related strings + CPUAttr = getCPUAttr(); + CPUProfile = getCPUProfile(); +} + +void ARMTargetInfo::setAtomic() { + // when triple does not specify a sub arch, + // then we are not using inline atomics + bool ShouldUseInlineAtomic = + (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) || + (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7); + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + if (ArchProfile == llvm::ARM::ProfileKind::M) { + MaxAtomicPromoteWidth = 32; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 32; + } else { + MaxAtomicPromoteWidth = 64; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 64; + } +} + +bool ARMTargetInfo::isThumb() const { + return ArchISA == llvm::ARM::ISAKind::THUMB; +} + +bool ARMTargetInfo::supportsThumb() const { + return CPUAttr.count('T') || ArchVersion >= 6; +} + +bool ARMTargetInfo::supportsThumb2() const { + return CPUAttr.equals("6T2") || + (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE")); +} + +StringRef ARMTargetInfo::getCPUAttr() const { + // For most sub-arches, the build attribute CPU name is enough. + // For Cortex variants, it's slightly different. + switch (ArchKind) { + default: + return llvm::ARM::getCPUAttr(ArchKind); + case llvm::ARM::ArchKind::ARMV6M: + return "6M"; + case llvm::ARM::ArchKind::ARMV7S: + return "7S"; + case llvm::ARM::ArchKind::ARMV7A: + return "7A"; + case llvm::ARM::ArchKind::ARMV7R: + return "7R"; + case llvm::ARM::ArchKind::ARMV7M: + return "7M"; + case llvm::ARM::ArchKind::ARMV7EM: + return "7EM"; + case llvm::ARM::ArchKind::ARMV7VE: + return "7VE"; + case llvm::ARM::ArchKind::ARMV8A: + return "8A"; + case llvm::ARM::ArchKind::ARMV8_1A: + return "8_1A"; + case llvm::ARM::ArchKind::ARMV8_2A: + return "8_2A"; + case llvm::ARM::ArchKind::ARMV8MBaseline: + return "8M_BASE"; + case llvm::ARM::ArchKind::ARMV8MMainline: + return "8M_MAIN"; + case llvm::ARM::ArchKind::ARMV8R: + return "8R"; + } +} + +StringRef ARMTargetInfo::getCPUProfile() const { + switch (ArchProfile) { + case llvm::ARM::ProfileKind::A: + return "A"; + case llvm::ARM::ProfileKind::R: + return "R"; + case llvm::ARM::ProfileKind::M: + return "M"; + default: + return ""; + } +} + +ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), + HW_FP(0) { + bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD; + bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD; + + // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like + // environment where size_t is `unsigned long` rather than `unsigned int` + + PtrDiffType = IntPtrType = + (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || + IsNetBSD) + ? SignedLong + : SignedInt; + + SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || + IsNetBSD) + ? UnsignedLong + : UnsignedInt; + + // ptrdiff_t is inconsistent on Darwin + if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) && + !Triple.isWatchABI()) + PtrDiffType = SignedInt; + + // Cache arch related info. + setArchInfo(); + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // FIXME: This duplicates code from the driver that sets the -target-abi + // option - this code is used if -target-abi isn't passed and should + // be unified in some way. + if (Triple.isOSBinFormatMachO()) { + // The backend is hardwired to assume AAPCS for M-class processors, ensure + // the frontend matches that. + if (Triple.getEnvironment() == llvm::Triple::EABI || + Triple.getOS() == llvm::Triple::UnknownOS || + ArchProfile == llvm::ARM::ProfileKind::M) { + setABI("aapcs"); + } else if (Triple.isWatchABI()) { + setABI("aapcs16"); + } else { + setABI("apcs-gnu"); + } + } else if (Triple.isOSWindows()) { + // FIXME: this is invalid for WindowsCE + setABI("aapcs"); + } else { + // Select the default based on the platform. + switch (Triple.getEnvironment()) { + case llvm::Triple::Android: + case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABI: + case llvm::Triple::MuslEABIHF: + setABI("aapcs-linux"); + break; + case llvm::Triple::EABIHF: + case llvm::Triple::EABI: + setABI("aapcs"); + break; + case llvm::Triple::GNU: + setABI("apcs-gnu"); + break; + default: + if (Triple.getOS() == llvm::Triple::NetBSD) + setABI("apcs-gnu"); + else if (Triple.getOS() == llvm::Triple::OpenBSD) + setABI("aapcs-linux"); + else + setABI("aapcs"); + break; + } + } + + // ARM targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericARM); + + // ARM has atomics up to 8 bytes + setAtomic(); + + // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS) + if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android)) + MaxVectorAlign = 64; + + // Do force alignment of members that follow zero length bitfields. If + // the alignment of the zero-length bitfield is greater than the member + // that follows it, `bar', `bar' will be aligned as the type of the + // zero length bitfield. + UseZeroLengthBitfieldAlignment = true; + + if (Triple.getOS() == llvm::Triple::Linux || + Triple.getOS() == llvm::Triple::UnknownOS) + this->MCountName = Opts.EABIVersion == llvm::EABI::GNU + ? "\01__gnu_mcount_nc" + : "\01mcount"; +} + +StringRef ARMTargetInfo::getABI() const { return ABI; } + +bool ARMTargetInfo::setABI(const std::string &Name) { + ABI = Name; + + // The defaults (above) are for AAPCS, check if we need to change them. + // + // FIXME: We need support for -meabi... we could just mangle it into the + // name. + if (Name == "apcs-gnu" || Name == "aapcs16") { + setABIAPCS(Name == "aapcs16"); + return true; + } + if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { + setABIAAPCS(); + return true; + } + return false; +} + +// FIXME: This should be based on Arch attributes, not CPU names. +bool ARMTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + + std::vector<StringRef> TargetFeatures; + llvm::ARM::ArchKind Arch = llvm::ARM::parseArch(getTriple().getArchName()); + + // get default FPU features + unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); + llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); + + // get default Extension features + unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); + llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); + + for (auto Feature : TargetFeatures) + if (Feature[0] == '+') + Features[Feature.drop_front(1)] = true; + + // Enable or disable thumb-mode explicitly per function to enable mixed + // ARM and Thumb code generation. + if (isThumb()) + Features["thumb-mode"] = true; + else + Features["thumb-mode"] = false; + + // Convert user-provided arm and thumb GNU target attributes to + // [-|+]thumb-mode target features respectively. + std::vector<std::string> UpdatedFeaturesVec(FeaturesVec); + for (auto &Feature : UpdatedFeaturesVec) { + if (Feature.compare("+arm") == 0) + Feature = "-thumb-mode"; + else if (Feature.compare("+thumb") == 0) + Feature = "+thumb-mode"; + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec); +} + + +bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FPU = 0; + CRC = 0; + Crypto = 0; + DSP = 0; + Unaligned = 1; + SoftFloat = SoftFloatABI = false; + HWDiv = 0; + + // This does not diagnose illegal cases like having both + // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp". + uint32_t HW_FP_remove = 0; + for (const auto &Feature : Features) { + if (Feature == "+soft-float") { + SoftFloat = true; + } else if (Feature == "+soft-float-abi") { + SoftFloatABI = true; + } else if (Feature == "+vfp2") { + FPU |= VFP2FPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } else if (Feature == "+vfp3") { + FPU |= VFP3FPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } else if (Feature == "+vfp4") { + FPU |= VFP4FPU; + HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; + } else if (Feature == "+fp-armv8") { + FPU |= FPARMV8; + HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; + } else if (Feature == "+neon") { + FPU |= NeonFPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } else if (Feature == "+hwdiv") { + HWDiv |= HWDivThumb; + } else if (Feature == "+hwdiv-arm") { + HWDiv |= HWDivARM; + } else if (Feature == "+crc") { + CRC = 1; + } else if (Feature == "+crypto") { + Crypto = 1; + } else if (Feature == "+dsp") { + DSP = 1; + } else if (Feature == "+fp-only-sp") { + HW_FP_remove |= HW_FP_DP; + } else if (Feature == "+strict-align") { + Unaligned = 0; + } else if (Feature == "+fp16") { + HW_FP |= HW_FP_HP; + } + } + HW_FP &= ~HW_FP_remove; + + switch (ArchVersion) { + case 6: + if (ArchProfile == llvm::ARM::ProfileKind::M) + LDREX = 0; + else if (ArchKind == llvm::ARM::ArchKind::ARMV6K) + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + else + LDREX = LDREX_W; + break; + case 7: + if (ArchProfile == llvm::ARM::ProfileKind::M) + LDREX = LDREX_W | LDREX_H | LDREX_B; + else + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + break; + case 8: + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + } + + if (!(FPU & NeonFPU) && FPMath == FP_Neon) { + Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; + return false; + } + + if (FPMath == FP_Neon) + Features.push_back("+neonfp"); + else if (FPMath == FP_VFP) + Features.push_back("-neonfp"); + + // Remove front-end specific options which the backend handles differently. + auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi"); + if (Feature != Features.end()) + Features.erase(Feature); + + return true; +} + +bool ARMTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("arm", true) + .Case("aarch32", true) + .Case("softfloat", SoftFloat) + .Case("thumb", isThumb()) + .Case("neon", (FPU & NeonFPU) && !SoftFloat) + .Case("vfp", FPU && !SoftFloat) + .Case("hwdiv", HWDiv & HWDivThumb) + .Case("hwdiv-arm", HWDiv & HWDivARM) + .Default(false); +} + +bool ARMTargetInfo::isValidCPUName(StringRef Name) const { + return Name == "generic" || + llvm::ARM::parseCPUArch(Name) != llvm::ARM::ArchKind::INVALID; +} + +bool ARMTargetInfo::setCPU(const std::string &Name) { + if (Name != "generic") + setArchInfo(llvm::ARM::parseCPUArch(Name)); + + if (ArchKind == llvm::ARM::ArchKind::INVALID) + return false; + setAtomic(); + CPU = Name; + return true; +} + +bool ARMTargetInfo::setFPMath(StringRef Name) { + if (Name == "neon") { + FPMath = FP_Neon; + return true; + } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || + Name == "vfp4") { + FPMath = FP_VFP; + return true; + } + return false; +} + +void ARMTargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); +} + +void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1-A defines + getTargetDefinesARMV81A(Opts, Builder); +} + +void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__arm"); + Builder.defineMacro("__arm__"); + // For bare-metal none-eabi. + if (getTriple().getOS() == llvm::Triple::UnknownOS && + (getTriple().getEnvironment() == llvm::Triple::EABI || + getTriple().getEnvironment() == llvm::Triple::EABIHF)) + Builder.defineMacro("__ELF__"); + + // Target properties. + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU + // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. + if (getTriple().isWatchABI()) + Builder.defineMacro("__ARM_ARCH_7K__", "2"); + + if (!CPUAttr.empty()) + Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + + // ACLE 6.4.1 ARM/Thumb instruction set architecture + // __ARM_ARCH is defined as an integer value indicating the current ARM ISA + Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); + + if (ArchVersion >= 8) { + // ACLE 6.5.7 Crypto Extension + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + // ACLE 6.5.8 CRC32 Extension + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + // ACLE 6.5.10 Numeric Maximum and Minimum + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + // ACLE 6.5.9 Directed Rounding + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); + } + + // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It + // is not defined for the M-profile. + // NOTE that the default profile is assumed to be 'A' + if (CPUProfile.empty() || ArchProfile != llvm::ARM::ProfileKind::M) + Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); + + // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original + // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the + // core supports the Thumb-2 ISA as found in the v6T2 architecture and all + // v7 and v8 architectures excluding v8-M Baseline. + if (supportsThumb2()) + Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); + else if (supportsThumb()) + Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); + + // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit + // instruction set such as ARM or Thumb. + Builder.defineMacro("__ARM_32BIT_STATE", "1"); + + // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) + + // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. + if (!CPUProfile.empty()) + Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); + + // ACLE 6.4.3 Unaligned access supported in hardware + if (Unaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + // ACLE 6.4.4 LDREX/STREX + if (LDREX) + Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX)); + + // ACLE 6.4.5 CLZ + if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") || + ArchVersion > 6) + Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + + // ACLE 6.5.1 Hardware Floating Point + if (HW_FP) + Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); + + // ACLE predefines. + Builder.defineMacro("__ARM_ACLE", "200"); + + // FP16 support (we currently only support IEEE format). + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); + + // ACLE 6.5.3 Fused multiply-accumulate (FMA) + if (ArchVersion >= 7 && (FPU & VFP4FPU)) + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + + // Subtarget options. + + // FIXME: It's more complicated than this and we don't really support + // interworking. + // Windows on ARM does not "support" interworking + if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) + Builder.defineMacro("__THUMB_INTERWORK__"); + + if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { + // Embedded targets on Darwin follow AAPCS, but not EABI. + // Windows on ARM follows AAPCS VFP, but does not conform to EABI. + if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows()) + Builder.defineMacro("__ARM_EABI__"); + Builder.defineMacro("__ARM_PCS", "1"); + } + + if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16") + Builder.defineMacro("__ARM_PCS_VFP", "1"); + + if (SoftFloat) + Builder.defineMacro("__SOFTFP__"); + + if (ArchKind == llvm::ARM::ArchKind::XSCALE) + Builder.defineMacro("__XSCALE__"); + + if (isThumb()) { + Builder.defineMacro("__THUMBEL__"); + Builder.defineMacro("__thumb__"); + if (supportsThumb2()) + Builder.defineMacro("__thumb2__"); + } + + // ACLE 6.4.9 32-bit SIMD instructions + if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) + Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); + + // ACLE 6.4.10 Hardware Integer Divide + if (((HWDiv & HWDivThumb) && isThumb()) || + ((HWDiv & HWDivARM) && !isThumb())) { + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); + Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); + } + + // Note, this is always on in gcc, even though it doesn't make sense. + Builder.defineMacro("__APCS_32__"); + + if (FPUModeIsVFP((FPUMode)FPU)) { + Builder.defineMacro("__VFP_FP__"); + if (FPU & VFP2FPU) + Builder.defineMacro("__ARM_VFPV2__"); + if (FPU & VFP3FPU) + Builder.defineMacro("__ARM_VFPV3__"); + if (FPU & VFP4FPU) + Builder.defineMacro("__ARM_VFPV4__"); + if (FPU & FPARMV8) + Builder.defineMacro("__ARM_FPV5__"); + } + + // This only gets set when Neon instructions are actually available, unlike + // the VFP define, hence the soft float and arch check. This is subtly + // different from gcc, we follow the intent which was that it should be set + // when Neon instructions are actually available. + if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { + Builder.defineMacro("__ARM_NEON", "1"); + Builder.defineMacro("__ARM_NEON__"); + // current AArch32 NEON implementations do not support double-precision + // floating-point even when it is present in VFP. + Builder.defineMacro("__ARM_NEON_FP", + "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP)); + } + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", + llvm::utostr(Opts.WCharSize ? Opts.WCharSize : 4)); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); + + if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } + + // ACLE 6.4.7 DSP instructions + if (DSP) { + Builder.defineMacro("__ARM_FEATURE_DSP", "1"); + } + + // ACLE 6.4.8 Saturation instructions + bool SAT = false; + if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) { + Builder.defineMacro("__ARM_FEATURE_SAT", "1"); + SAT = true; + } + + // ACLE 6.4.6 Q (saturation) flag + if (DSP || SAT) + Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); + + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); + + switch (ArchKind) { + default: + break; + case llvm::ARM::ArchKind::ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::ARM::ArchKind::ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + } +} + +const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsARM.def" +}; + +ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool ARMTargetInfo::isCLZForZeroUndef() const { return false; } +TargetInfo::BuiltinVaListKind ARMTargetInfo::getBuiltinVaListKind() const { + return IsAAPCS + ? AAPCSABIBuiltinVaList + : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList + : TargetInfo::VoidPtrBuiltinVaList); +} + +const char *const ARMTargetInfo::GCCRegNames[] = { + // Integer registers + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "sp", "lr", "pc", + + // Float registers + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + + // Double registers + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", + "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + + // Quad registers + "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", + "q12", "q13", "q14", "q15"}; + +ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { + {{"a1"}, "r0"}, {{"a2"}, "r1"}, {{"a3"}, "r2"}, {{"a4"}, "r3"}, + {{"v1"}, "r4"}, {{"v2"}, "r5"}, {{"v3"}, "r6"}, {{"v4"}, "r7"}, + {{"v5"}, "r8"}, {{"v6", "rfp"}, "r9"}, {{"sl"}, "r10"}, {{"fp"}, "r11"}, + {{"ip"}, "r12"}, {{"r13"}, "sp"}, {{"r14"}, "lr"}, {{"r15"}, "pc"}, + // The S, D and Q registers overlap, but aren't really aliases; we + // don't want to substitute one of these for a different-sized one. +}; + +ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool ARMTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + break; + case 'l': // r0-r7 + case 'h': // r8-r15 + case 't': // VFP Floating point register single precision + case 'w': // VFP Floating point register double precision + Info.setAllowsRegister(); + return true; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + // FIXME + return true; + case 'Q': // A memory address that is a single base register. + Info.setAllowsMemory(); + return true; + case 'U': // a memory reference... + switch (Name[1]) { + case 'q': // ...ARMV4 ldrsb + case 'v': // ...VFP load/store (reg+constant offset) + case 'y': // ...iWMMXt load/store + case 't': // address valid for load/store opaque types wider + // than 128-bits + case 'n': // valid address for Neon doubleword vector load/store + case 'm': // valid address for Neon element and structure load/store + case 's': // valid address for non-offset loads/stores of quad-word + // values in four ARM registers + Info.setAllowsMemory(); + Name++; + return true; + } + } + return false; +} + +std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const { + std::string R; + switch (*Constraint) { + case 'U': // Two-character constraint; add "^" hint for later parsing. + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + break; + case 'p': // 'p' should be translated to 'r' by default. + R = std::string("r"); + break; + default: + return std::string(1, *Constraint); + } + return R; +} + +bool ARMTargetInfo::validateConstraintModifier( + StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const { + bool isOutput = (Constraint[0] == '='); + bool isInOut = (Constraint[0] == '+'); + + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: + break; + case 'r': { + switch (Modifier) { + default: + return (isInOut || isOutput || Size <= 64); + case 'q': + // A register of size 32 cannot fit a vector type. + return false; + } + } + } + + return true; +} +const char *ARMTargetInfo::getClobbers() const { + // FIXME: Is this really right? + return ""; +} + +TargetInfo::CallingConvCheckResult +ARMTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_AAPCS: + case CC_AAPCS_VFP: + case CC_Swift: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; +} + +bool ARMTargetInfo::hasSjLjLowering() const { return true; } + +ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMTargetInfo(Triple, Opts) {} + +void ARMleTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARMEL__"); + ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +ARMbeTargetInfo::ARMbeTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMTargetInfo(Triple, Opts) {} + +void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARMEB__"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) { +} + +void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder); + + // FIXME: this is invalid for WindowsCE + Builder.defineMacro("_M_ARM_NT", "1"); + Builder.defineMacro("_M_ARMT", "_M_ARM"); + Builder.defineMacro("_M_THUMB", "_M_ARM"); + + assert((Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) && + "invalid architecture for Windows ARM target info"); + unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; + Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); + + // TODO map the complete set of values + // 31: VFPv3 40: VFPv4 + Builder.defineMacro("_M_ARM_FP", "31"); +} + +TargetInfo::BuiltinVaListKind +WindowsARMTargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +TargetInfo::CallingConvCheckResult +WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86VectorCall: + return CCCR_Ignore; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +// Windows ARM + Itanium C++ ABI Target +ItaniumWindowsARMleTargetInfo::ItaniumWindowsARMleTargetInfo( + const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void ItaniumWindowsARMleTargetInfo::getTargetDefines( + const LangOptions &Opts, MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + + if (Opts.MSVCCompat) + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +// Windows ARM, MS (C++) ABI +MicrosoftARMleTargetInfo::MicrosoftARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::Microsoft); +} + +void MicrosoftARMleTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +MinGWARMTargetInfo::MinGWARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void MinGWARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_ARM_"); +} + +CygwinARMTargetInfo::CygwinARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMleTargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + TLSSupported = false; + DoubleAlign = LongLongAlign = 64; + resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); +} + +void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + ARMleTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_ARM_"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); +} + +DarwinARMTargetInfo::DarwinARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + // iOS always has 64-bit atomic instructions. + // FIXME: This should be based off of the target features in + // ARMleTargetInfo. + MaxAtomicInlineWidth = 64; + + if (Triple.isWatchABI()) { + // Darwin on iOS uses a variant of the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::WatchOS); + + // BOOL should be a real boolean on the new ABI + UseSignedCharForObjCBool = false; + } else + TheCXXABI.set(TargetCXXABI::iOS); +} + +void DarwinARMTargetInfo::getOSDefines(const LangOptions &Opts, + const llvm::Triple &Triple, + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); +} + +RenderScript32TargetInfo::RenderScript32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), + Triple.getOSName(), + Triple.getEnvironmentName()), + Opts) { + IsRenderScriptTarget = true; + LongWidth = LongAlign = 64; +} + +void RenderScript32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__RENDERSCRIPT__"); + ARMleTargetInfo::getTargetDefines(Opts, Builder); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.h b/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.h new file mode 100644 index 0000000000000..fb0e7e66bea38 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/ARM.h @@ -0,0 +1,256 @@ +//===--- ARM.h - Declare ARM target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares ARM TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TargetParser.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { + // Possible FPU choices. + enum FPUMode { + VFP2FPU = (1 << 0), + VFP3FPU = (1 << 1), + VFP4FPU = (1 << 2), + NeonFPU = (1 << 3), + FPARMV8 = (1 << 4) + }; + + // Possible HWDiv features. + enum HWDivMode { HWDivThumb = (1 << 0), HWDivARM = (1 << 1) }; + + static bool FPUModeIsVFP(FPUMode Mode) { + return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + + std::string ABI, CPU; + + StringRef CPUProfile; + StringRef CPUAttr; + + enum { FP_Default, FP_VFP, FP_Neon } FPMath; + + llvm::ARM::ISAKind ArchISA; + llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T; + llvm::ARM::ProfileKind ArchProfile; + unsigned ArchVersion; + + unsigned FPU : 5; + + unsigned IsAAPCS : 1; + unsigned HWDiv : 2; + + // Initialized via features. + unsigned SoftFloat : 1; + unsigned SoftFloatABI : 1; + + unsigned CRC : 1; + unsigned Crypto : 1; + unsigned DSP : 1; + unsigned Unaligned : 1; + + enum { + LDREX_B = (1 << 0), /// byte (8-bit) + LDREX_H = (1 << 1), /// half (16-bit) + LDREX_W = (1 << 2), /// word (32-bit) + LDREX_D = (1 << 3), /// double (64-bit) + }; + + uint32_t LDREX; + + // ACLE 6.5.1 Hardware floating point + enum { + HW_FP_HP = (1 << 1), /// half (16-bit) + HW_FP_SP = (1 << 2), /// single (32-bit) + HW_FP_DP = (1 << 3), /// double (64-bit) + }; + uint32_t HW_FP; + + static const Builtin::Info BuiltinInfo[]; + + void setABIAAPCS(); + void setABIAPCS(bool IsAAPCS16); + + void setArchInfo(); + void setArchInfo(llvm::ARM::ArchKind Kind); + + void setAtomic(); + + bool isThumb() const; + bool supportsThumb() const; + bool supportsThumb2() const; + + StringRef getCPUAttr() const; + StringRef getCPUProfile() const; + +public: + ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + StringRef getABI() const override; + bool setABI(const std::string &Name) override; + + // FIXME: This should be based on Arch attributes, not CPU names. + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + bool hasFeature(StringRef Feature) const override; + + bool isValidCPUName(StringRef Name) const override; + bool setCPU(const std::string &Name) override; + + bool setFPMath(StringRef Name) override; + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const; + + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool isCLZForZeroUndef() const override; + BuiltinVaListKind getBuiltinVaListKind() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override; + std::string convertConstraint(const char *&Constraint) const override; + bool + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override; + const char *getClobbers() const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + + int getEHDataRegisterNumber(unsigned RegNo) const override; + + bool hasSjLjLowering() const override; +}; + +class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo { +public: + ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY ARMbeTargetInfo : public ARMTargetInfo { +public: + ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY WindowsARMTargetInfo + : public WindowsTargetInfo<ARMleTargetInfo> { + const llvm::Triple Triple; + +public: + WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; +}; + +// Windows ARM + Itanium C++ ABI Target +class LLVM_LIBRARY_VISIBILITY ItaniumWindowsARMleTargetInfo + : public WindowsARMTargetInfo { +public: + ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// Windows ARM, MS (C++) ABI +class LLVM_LIBRARY_VISIBILITY MicrosoftARMleTargetInfo + : public WindowsARMTargetInfo { +public: + MicrosoftARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// ARM MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWARMTargetInfo : public WindowsARMTargetInfo { +public: + MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// ARM Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinARMTargetInfo : public ARMleTargetInfo { +public: + CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY DarwinARMTargetInfo + : public DarwinTargetInfo<ARMleTargetInfo> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override; + +public: + DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); +}; + +// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes +class LLVM_LIBRARY_VISIBILITY RenderScript32TargetInfo + : public ARMleTargetInfo { +public: + RenderScript32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.cpp new file mode 100644 index 0000000000000..3022fe33d76cc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.cpp @@ -0,0 +1,320 @@ +//===--- AVR.cpp - Implement AVR target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AVR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AVR.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +/// Information about a specific microcontroller. +struct LLVM_LIBRARY_VISIBILITY MCUInfo { + const char *Name; + const char *DefineName; +}; + +// This list should be kept up-to-date with AVRDevices.td in LLVM. +static ArrayRef<MCUInfo> AVRMcus = { + {"at90s1200", "__AVR_AT90S1200__"}, + {"attiny11", "__AVR_ATtiny11__"}, + {"attiny12", "__AVR_ATtiny12__"}, + {"attiny15", "__AVR_ATtiny15__"}, + {"attiny28", "__AVR_ATtiny28__"}, + {"at90s2313", "__AVR_AT90S2313__"}, + {"at90s2323", "__AVR_AT90S2323__"}, + {"at90s2333", "__AVR_AT90S2333__"}, + {"at90s2343", "__AVR_AT90S2343__"}, + {"attiny22", "__AVR_ATtiny22__"}, + {"attiny26", "__AVR_ATtiny26__"}, + {"at86rf401", "__AVR_AT86RF401__"}, + {"at90s4414", "__AVR_AT90S4414__"}, + {"at90s4433", "__AVR_AT90S4433__"}, + {"at90s4434", "__AVR_AT90S4434__"}, + {"at90s8515", "__AVR_AT90S8515__"}, + {"at90c8534", "__AVR_AT90c8534__"}, + {"at90s8535", "__AVR_AT90S8535__"}, + {"ata5272", "__AVR_ATA5272__"}, + {"attiny13", "__AVR_ATtiny13__"}, + {"attiny13a", "__AVR_ATtiny13A__"}, + {"attiny2313", "__AVR_ATtiny2313__"}, + {"attiny2313a", "__AVR_ATtiny2313A__"}, + {"attiny24", "__AVR_ATtiny24__"}, + {"attiny24a", "__AVR_ATtiny24A__"}, + {"attiny4313", "__AVR_ATtiny4313__"}, + {"attiny44", "__AVR_ATtiny44__"}, + {"attiny44a", "__AVR_ATtiny44A__"}, + {"attiny84", "__AVR_ATtiny84__"}, + {"attiny84a", "__AVR_ATtiny84A__"}, + {"attiny25", "__AVR_ATtiny25__"}, + {"attiny45", "__AVR_ATtiny45__"}, + {"attiny85", "__AVR_ATtiny85__"}, + {"attiny261", "__AVR_ATtiny261__"}, + {"attiny261a", "__AVR_ATtiny261A__"}, + {"attiny461", "__AVR_ATtiny461__"}, + {"attiny461a", "__AVR_ATtiny461A__"}, + {"attiny861", "__AVR_ATtiny861__"}, + {"attiny861a", "__AVR_ATtiny861A__"}, + {"attiny87", "__AVR_ATtiny87__"}, + {"attiny43u", "__AVR_ATtiny43U__"}, + {"attiny48", "__AVR_ATtiny48__"}, + {"attiny88", "__AVR_ATtiny88__"}, + {"attiny828", "__AVR_ATtiny828__"}, + {"at43usb355", "__AVR_AT43USB355__"}, + {"at76c711", "__AVR_AT76C711__"}, + {"atmega103", "__AVR_ATmega103__"}, + {"at43usb320", "__AVR_AT43USB320__"}, + {"attiny167", "__AVR_ATtiny167__"}, + {"at90usb82", "__AVR_AT90USB82__"}, + {"at90usb162", "__AVR_AT90USB162__"}, + {"ata5505", "__AVR_ATA5505__"}, + {"atmega8u2", "__AVR_ATmega8U2__"}, + {"atmega16u2", "__AVR_ATmega16U2__"}, + {"atmega32u2", "__AVR_ATmega32U2__"}, + {"attiny1634", "__AVR_ATtiny1634__"}, + {"atmega8", "__AVR_ATmega8__"}, + {"ata6289", "__AVR_ATA6289__"}, + {"atmega8a", "__AVR_ATmega8A__"}, + {"ata6285", "__AVR_ATA6285__"}, + {"ata6286", "__AVR_ATA6286__"}, + {"atmega48", "__AVR_ATmega48__"}, + {"atmega48a", "__AVR_ATmega48A__"}, + {"atmega48pa", "__AVR_ATmega48PA__"}, + {"atmega48p", "__AVR_ATmega48P__"}, + {"atmega88", "__AVR_ATmega88__"}, + {"atmega88a", "__AVR_ATmega88A__"}, + {"atmega88p", "__AVR_ATmega88P__"}, + {"atmega88pa", "__AVR_ATmega88PA__"}, + {"atmega8515", "__AVR_ATmega8515__"}, + {"atmega8535", "__AVR_ATmega8535__"}, + {"atmega8hva", "__AVR_ATmega8HVA__"}, + {"at90pwm1", "__AVR_AT90PWM1__"}, + {"at90pwm2", "__AVR_AT90PWM2__"}, + {"at90pwm2b", "__AVR_AT90PWM2B__"}, + {"at90pwm3", "__AVR_AT90PWM3__"}, + {"at90pwm3b", "__AVR_AT90PWM3B__"}, + {"at90pwm81", "__AVR_AT90PWM81__"}, + {"ata5790", "__AVR_ATA5790__"}, + {"ata5795", "__AVR_ATA5795__"}, + {"atmega16", "__AVR_ATmega16__"}, + {"atmega16a", "__AVR_ATmega16A__"}, + {"atmega161", "__AVR_ATmega161__"}, + {"atmega162", "__AVR_ATmega162__"}, + {"atmega163", "__AVR_ATmega163__"}, + {"atmega164a", "__AVR_ATmega164A__"}, + {"atmega164p", "__AVR_ATmega164P__"}, + {"atmega164pa", "__AVR_ATmega164PA__"}, + {"atmega165", "__AVR_ATmega165__"}, + {"atmega165a", "__AVR_ATmega165A__"}, + {"atmega165p", "__AVR_ATmega165P__"}, + {"atmega165pa", "__AVR_ATmega165PA__"}, + {"atmega168", "__AVR_ATmega168__"}, + {"atmega168a", "__AVR_ATmega168A__"}, + {"atmega168p", "__AVR_ATmega168P__"}, + {"atmega168pa", "__AVR_ATmega168PA__"}, + {"atmega169", "__AVR_ATmega169__"}, + {"atmega169a", "__AVR_ATmega169A__"}, + {"atmega169p", "__AVR_ATmega169P__"}, + {"atmega169pa", "__AVR_ATmega169PA__"}, + {"atmega32", "__AVR_ATmega32__"}, + {"atmega32a", "__AVR_ATmega32A__"}, + {"atmega323", "__AVR_ATmega323__"}, + {"atmega324a", "__AVR_ATmega324A__"}, + {"atmega324p", "__AVR_ATmega324P__"}, + {"atmega324pa", "__AVR_ATmega324PA__"}, + {"atmega325", "__AVR_ATmega325__"}, + {"atmega325a", "__AVR_ATmega325A__"}, + {"atmega325p", "__AVR_ATmega325P__"}, + {"atmega325pa", "__AVR_ATmega325PA__"}, + {"atmega3250", "__AVR_ATmega3250__"}, + {"atmega3250a", "__AVR_ATmega3250A__"}, + {"atmega3250p", "__AVR_ATmega3250P__"}, + {"atmega3250pa", "__AVR_ATmega3250PA__"}, + {"atmega328", "__AVR_ATmega328__"}, + {"atmega328p", "__AVR_ATmega328P__"}, + {"atmega329", "__AVR_ATmega329__"}, + {"atmega329a", "__AVR_ATmega329A__"}, + {"atmega329p", "__AVR_ATmega329P__"}, + {"atmega329pa", "__AVR_ATmega329PA__"}, + {"atmega3290", "__AVR_ATmega3290__"}, + {"atmega3290a", "__AVR_ATmega3290A__"}, + {"atmega3290p", "__AVR_ATmega3290P__"}, + {"atmega3290pa", "__AVR_ATmega3290PA__"}, + {"atmega406", "__AVR_ATmega406__"}, + {"atmega64", "__AVR_ATmega64__"}, + {"atmega64a", "__AVR_ATmega64A__"}, + {"atmega640", "__AVR_ATmega640__"}, + {"atmega644", "__AVR_ATmega644__"}, + {"atmega644a", "__AVR_ATmega644A__"}, + {"atmega644p", "__AVR_ATmega644P__"}, + {"atmega644pa", "__AVR_ATmega644PA__"}, + {"atmega645", "__AVR_ATmega645__"}, + {"atmega645a", "__AVR_ATmega645A__"}, + {"atmega645p", "__AVR_ATmega645P__"}, + {"atmega649", "__AVR_ATmega649__"}, + {"atmega649a", "__AVR_ATmega649A__"}, + {"atmega649p", "__AVR_ATmega649P__"}, + {"atmega6450", "__AVR_ATmega6450__"}, + {"atmega6450a", "__AVR_ATmega6450A__"}, + {"atmega6450p", "__AVR_ATmega6450P__"}, + {"atmega6490", "__AVR_ATmega6490__"}, + {"atmega6490a", "__AVR_ATmega6490A__"}, + {"atmega6490p", "__AVR_ATmega6490P__"}, + {"atmega64rfr2", "__AVR_ATmega64RFR2__"}, + {"atmega644rfr2", "__AVR_ATmega644RFR2__"}, + {"atmega16hva", "__AVR_ATmega16HVA__"}, + {"atmega16hva2", "__AVR_ATmega16HVA2__"}, + {"atmega16hvb", "__AVR_ATmega16HVB__"}, + {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__"}, + {"atmega32hvb", "__AVR_ATmega32HVB__"}, + {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__"}, + {"atmega64hve", "__AVR_ATmega64HVE__"}, + {"at90can32", "__AVR_AT90CAN32__"}, + {"at90can64", "__AVR_AT90CAN64__"}, + {"at90pwm161", "__AVR_AT90PWM161__"}, + {"at90pwm216", "__AVR_AT90PWM216__"}, + {"at90pwm316", "__AVR_AT90PWM316__"}, + {"atmega32c1", "__AVR_ATmega32C1__"}, + {"atmega64c1", "__AVR_ATmega64C1__"}, + {"atmega16m1", "__AVR_ATmega16M1__"}, + {"atmega32m1", "__AVR_ATmega32M1__"}, + {"atmega64m1", "__AVR_ATmega64M1__"}, + {"atmega16u4", "__AVR_ATmega16U4__"}, + {"atmega32u4", "__AVR_ATmega32U4__"}, + {"atmega32u6", "__AVR_ATmega32U6__"}, + {"at90usb646", "__AVR_AT90USB646__"}, + {"at90usb647", "__AVR_AT90USB647__"}, + {"at90scr100", "__AVR_AT90SCR100__"}, + {"at94k", "__AVR_AT94K__"}, + {"m3000", "__AVR_AT000__"}, + {"atmega128", "__AVR_ATmega128__"}, + {"atmega128a", "__AVR_ATmega128A__"}, + {"atmega1280", "__AVR_ATmega1280__"}, + {"atmega1281", "__AVR_ATmega1281__"}, + {"atmega1284", "__AVR_ATmega1284__"}, + {"atmega1284p", "__AVR_ATmega1284P__"}, + {"atmega128rfa1", "__AVR_ATmega128RFA1__"}, + {"atmega128rfr2", "__AVR_ATmega128RFR2__"}, + {"atmega1284rfr2", "__AVR_ATmega1284RFR2__"}, + {"at90can128", "__AVR_AT90CAN128__"}, + {"at90usb1286", "__AVR_AT90USB1286__"}, + {"at90usb1287", "__AVR_AT90USB1287__"}, + {"atmega2560", "__AVR_ATmega2560__"}, + {"atmega2561", "__AVR_ATmega2561__"}, + {"atmega256rfr2", "__AVR_ATmega256RFR2__"}, + {"atmega2564rfr2", "__AVR_ATmega2564RFR2__"}, + {"atxmega16a4", "__AVR_ATxmega16A4__"}, + {"atxmega16a4u", "__AVR_ATxmega16a4U__"}, + {"atxmega16c4", "__AVR_ATxmega16C4__"}, + {"atxmega16d4", "__AVR_ATxmega16D4__"}, + {"atxmega32a4", "__AVR_ATxmega32A4__"}, + {"atxmega32a4u", "__AVR_ATxmega32A4U__"}, + {"atxmega32c4", "__AVR_ATxmega32C4__"}, + {"atxmega32d4", "__AVR_ATxmega32D4__"}, + {"atxmega32e5", "__AVR_ATxmega32E5__"}, + {"atxmega16e5", "__AVR_ATxmega16E5__"}, + {"atxmega8e5", "__AVR_ATxmega8E5__"}, + {"atxmega32x1", "__AVR_ATxmega32X1__"}, + {"atxmega64a3", "__AVR_ATxmega64A3__"}, + {"atxmega64a3u", "__AVR_ATxmega64A3U__"}, + {"atxmega64a4u", "__AVR_ATxmega64A4U__"}, + {"atxmega64b1", "__AVR_ATxmega64B1__"}, + {"atxmega64b3", "__AVR_ATxmega64B3__"}, + {"atxmega64c3", "__AVR_ATxmega64C3__"}, + {"atxmega64d3", "__AVR_ATxmega64D3__"}, + {"atxmega64d4", "__AVR_ATxmega64D4__"}, + {"atxmega64a1", "__AVR_ATxmega64A1__"}, + {"atxmega64a1u", "__AVR_ATxmega64A1U__"}, + {"atxmega128a3", "__AVR_ATxmega128A3__"}, + {"atxmega128a3u", "__AVR_ATxmega128A3U__"}, + {"atxmega128b1", "__AVR_ATxmega128B1__"}, + {"atxmega128b3", "__AVR_ATxmega128B3__"}, + {"atxmega128c3", "__AVR_ATxmega128C3__"}, + {"atxmega128d3", "__AVR_ATxmega128D3__"}, + {"atxmega128d4", "__AVR_ATxmega128D4__"}, + {"atxmega192a3", "__AVR_ATxmega192A3__"}, + {"atxmega192a3u", "__AVR_ATxmega192A3U__"}, + {"atxmega192c3", "__AVR_ATxmega192C3__"}, + {"atxmega192d3", "__AVR_ATxmega192D3__"}, + {"atxmega256a3", "__AVR_ATxmega256A3__"}, + {"atxmega256a3u", "__AVR_ATxmega256A3U__"}, + {"atxmega256a3b", "__AVR_ATxmega256A3B__"}, + {"atxmega256a3bu", "__AVR_ATxmega256A3BU__"}, + {"atxmega256c3", "__AVR_ATxmega256C3__"}, + {"atxmega256d3", "__AVR_ATxmega256D3__"}, + {"atxmega384c3", "__AVR_ATxmega384C3__"}, + {"atxmega384d3", "__AVR_ATxmega384D3__"}, + {"atxmega128a1", "__AVR_ATxmega128A1__"}, + {"atxmega128a1u", "__AVR_ATxmega128A1U__"}, + {"atxmega128a4u", "__AVR_ATxmega128a4U__"}, + {"attiny4", "__AVR_ATtiny4__"}, + {"attiny5", "__AVR_ATtiny5__"}, + {"attiny9", "__AVR_ATtiny9__"}, + {"attiny10", "__AVR_ATtiny10__"}, + {"attiny20", "__AVR_ATtiny20__"}, + {"attiny40", "__AVR_ATtiny40__"}, + {"attiny102", "__AVR_ATtiny102__"}, + {"attiny104", "__AVR_ATtiny104__"}, +}; + +} // namespace targets +} // namespace clang + +bool AVRTargetInfo::isValidCPUName(StringRef Name) const { + bool IsFamily = llvm::StringSwitch<bool>(Name) + .Case("avr1", true) + .Case("avr2", true) + .Case("avr25", true) + .Case("avr3", true) + .Case("avr31", true) + .Case("avr35", true) + .Case("avr4", true) + .Case("avr5", true) + .Case("avr51", true) + .Case("avr6", true) + .Case("avrxmega1", true) + .Case("avrxmega2", true) + .Case("avrxmega3", true) + .Case("avrxmega4", true) + .Case("avrxmega5", true) + .Case("avrxmega6", true) + .Case("avrxmega7", true) + .Case("avrtiny", true) + .Default(false); + + bool IsMCU = + std::find_if(AVRMcus.begin(), AVRMcus.end(), [&](const MCUInfo &Info) { + return Info.Name == Name; + }) != AVRMcus.end(); + return IsFamily || IsMCU; +} + +void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("AVR"); + Builder.defineMacro("__AVR"); + Builder.defineMacro("__AVR__"); + + if (!this->CPU.empty()) { + auto It = + std::find_if(AVRMcus.begin(), AVRMcus.end(), [&](const MCUInfo &Info) { + return Info.Name == this->CPU; + }); + + if (It != AVRMcus.end()) + Builder.defineMacro(It->DefineName); + } +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.h b/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.h new file mode 100644 index 0000000000000..3dfb84f756684 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/AVR.h @@ -0,0 +1,184 @@ +//===--- AVR.h - Declare AVR target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares AVR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// AVR Target +class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { +public: + AVRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + PointerWidth = 16; + PointerAlign = 8; + IntWidth = 16; + IntAlign = 8; + LongWidth = 32; + LongAlign = 8; + LongLongWidth = 64; + LongLongAlign = 8; + SuitableAlign = 8; + DefaultAlignForAttributeAligned = 8; + HalfWidth = 16; + HalfAlign = 8; + FloatWidth = 32; + FloatAlign = 8; + DoubleWidth = 32; + DoubleAlign = 8; + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleWidth = 32; + LongDoubleAlign = 8; + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + Char16Type = UnsignedInt; + WIntType = SignedInt; + Char32Type = UnsignedLong; + SigAtomicType = SignedChar; + resetDataLayout("e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", "r25", "X", "Y", "Z", "SP" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override { + static const TargetInfo::AddlRegName AddlRegNames[] = { + {{"r26", "r27"}, 26}, + {{"r28", "r29"}, 27}, + {{"r30", "r31"}, 28}, + {{"SPL", "SPH"}, 29}, + }; + return llvm::makeArrayRef(AddlRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + // There aren't any multi-character AVR specific constraints. + if (StringRef(Name).size() > 1) + return false; + + switch (*Name) { + default: + return false; + case 'a': // Simple upper registers + case 'b': // Base pointer registers pairs + case 'd': // Upper register + case 'l': // Lower registers + case 'e': // Pointer register pairs + case 'q': // Stack pointer register + case 'r': // Any register + case 'w': // Special upper register pairs + case 't': // Temporary register + case 'x': + case 'X': // Pointer register pair X + case 'y': + case 'Y': // Pointer register pair Y + case 'z': + case 'Z': // Pointer register pair Z + Info.setAllowsRegister(); + return true; + case 'I': // 6-bit positive integer constant + Info.setRequiresImmediate(0, 63); + return true; + case 'J': // 6-bit negative integer constant + Info.setRequiresImmediate(-63, 0); + return true; + case 'K': // Integer constant (Range: 2) + Info.setRequiresImmediate(2); + return true; + case 'L': // Integer constant (Range: 0) + Info.setRequiresImmediate(0); + return true; + case 'M': // 8-bit integer constant + Info.setRequiresImmediate(0, 0xff); + return true; + case 'N': // Integer constant (Range: -1) + Info.setRequiresImmediate(-1); + return true; + case 'O': // Integer constant (Range: 8, 16, 24) + Info.setRequiresImmediate({8, 16, 24}); + return true; + case 'P': // Integer constant (Range: 1) + Info.setRequiresImmediate(1); + return true; + case 'R': // Integer constant (Range: -6 to 5) + Info.setRequiresImmediate(-6, 5); + return true; + case 'G': // Floating point constant + case 'Q': // A memory address based on Y or Z pointer with displacement. + return true; + } + + return false; + } + + IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // AVR prefers int for 16-bit integers. + return BitWidth == 16 ? (IsSigned ? SignedInt : UnsignedInt) + : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); + } + + IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // AVR uses int for int_least16_t and int_fast16_t. + return BitWidth == 16 + ? (IsSigned ? SignedInt : UnsignedInt) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } + + bool isValidCPUName(StringRef Name) const override; + bool setCPU(const std::string &Name) override { + bool isValid = isValidCPUName(Name); + if (isValid) + CPU = Name; + return isValid; + } + +protected: + std::string CPU; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.cpp new file mode 100644 index 0000000000000..54e34f15532da --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.cpp @@ -0,0 +1,25 @@ +//===--- BPF.cpp - Implement BPF target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements BPF TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "bpf", Opts); + Builder.defineMacro("__BPF__"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.h b/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.h new file mode 100644 index 0000000000000..4dd9cbd9d2219 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/BPF.h @@ -0,0 +1,94 @@ +//===--- BPF.h - Declare BPF target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares BPF TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { +public: + BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + IntMaxType = SignedLong; + Int64Type = SignedLong; + RegParmMax = 5; + if (Triple.getArch() == llvm::Triple::bpfeb) { + resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128"); + } else { + resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); + } + MaxAtomicPromoteWidth = 64; + MaxAtomicInlineWidth = 64; + TLSSupported = false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { return Feature == "bpf"; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + const char *getClobbers() const override { return ""; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + } + } + + bool isValidCPUName(StringRef Name) const override { + if (Name == "generic" || Name == "v1" || + Name == "v2" || Name == "probe") + return true; + return false; + } + + bool setCPU(const std::string &Name) override { + StringRef CPUName(Name); + return isValidCPUName(CPUName); + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.cpp new file mode 100644 index 0000000000000..71d4c1e0f1611 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.cpp @@ -0,0 +1,158 @@ +//===--- Hexagon.cpp - Implement Hexagon target feature support -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Hexagon TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Hexagon.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__qdsp6__", "1"); + Builder.defineMacro("__hexagon__", "1"); + + if (CPU == "hexagonv4") { + Builder.defineMacro("__HEXAGON_V4__"); + Builder.defineMacro("__HEXAGON_ARCH__", "4"); + if (Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V4__"); + Builder.defineMacro("__QDSP6_ARCH__", "4"); + } + } else if (CPU == "hexagonv5") { + Builder.defineMacro("__HEXAGON_V5__"); + Builder.defineMacro("__HEXAGON_ARCH__", "5"); + if (Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V5__"); + Builder.defineMacro("__QDSP6_ARCH__", "5"); + } + } else if (CPU == "hexagonv55") { + Builder.defineMacro("__HEXAGON_V55__"); + Builder.defineMacro("__HEXAGON_ARCH__", "55"); + Builder.defineMacro("__QDSP6_V55__"); + Builder.defineMacro("__QDSP6_ARCH__", "55"); + } else if (CPU == "hexagonv60") { + Builder.defineMacro("__HEXAGON_V60__"); + Builder.defineMacro("__HEXAGON_ARCH__", "60"); + Builder.defineMacro("__QDSP6_V60__"); + Builder.defineMacro("__QDSP6_ARCH__", "60"); + } else if (CPU == "hexagonv62") { + Builder.defineMacro("__HEXAGON_V62__"); + Builder.defineMacro("__HEXAGON_ARCH__", "62"); + } else if (CPU == "hexagonv65") { + Builder.defineMacro("__HEXAGON_V65__"); + Builder.defineMacro("__HEXAGON_ARCH__", "65"); + } + + if (hasFeature("hvx-length64b")) { + Builder.defineMacro("__HVX__"); + Builder.defineMacro("__HVX_ARCH__", HVXVersion); + Builder.defineMacro("__HVX_LENGTH__", "64"); + } + + if (hasFeature("hvx-length128b")) { + Builder.defineMacro("__HVX__"); + Builder.defineMacro("__HVX_ARCH__", HVXVersion); + Builder.defineMacro("__HVX_LENGTH__", "128"); + // FIXME: This macro is deprecated. + Builder.defineMacro("__HVXDBL__"); + } +} + +bool HexagonTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + Features["hvx-double"] = false; + Features["long-calls"] = false; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (auto &F : Features) { + if (F == "+hvx-length64b") + HasHVX = HasHVX64B = true; + else if (F == "+hvx-length128b") + HasHVX = HasHVX128B = true; + else if (F.find("+hvxv") != std::string::npos) { + HasHVX = true; + HVXVersion = F.substr(std::string("+hvxv").length()); + } else if (F == "-hvx") + HasHVX = HasHVX64B = HasHVX128B = false; + else if (F == "+long-calls") + UseLongCalls = true; + else if (F == "-long-calls") + UseLongCalls = false; + } + return true; +} + +const char *const HexagonTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", + "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", + "r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3", + "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" +}; + +ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { + {{"sp"}, "r29"}, + {{"fp"}, "r30"}, + {{"lr"}, "r31"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsHexagon.def" +}; + +bool HexagonTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("hexagon", true) + .Case("hvx", HasHVX) + .Case("hvx-length64b", HasHVX64B) + .Case("hvx-length128b", HasHVX128B) + .Case("long-calls", UseLongCalls) + .Default(false); +} + +const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) { + return llvm::StringSwitch<const char *>(Name) + .Case("hexagonv4", "4") + .Case("hexagonv5", "5") + .Case("hexagonv55", "55") + .Case("hexagonv60", "60") + .Case("hexagonv62", "62") + .Case("hexagonv65", "65") + .Default(nullptr); +} + +ArrayRef<Builtin::Info> HexagonTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.h new file mode 100644 index 0000000000000..7b0966457c4bf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Hexagon.h @@ -0,0 +1,128 @@ +//===--- Hexagon.h - Declare Hexagon target feature support -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Hexagon TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// Hexagon abstract base class +class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; + std::string HVXVersion; + bool HasHVX = false; + bool HasHVX64B = false; + bool HasHVX128B = false; + bool UseLongCalls = false; + +public: + HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + // Specify the vector alignment explicitly. For v512x1, the calculated + // alignment would be 512*alignment(i1), which is 512 bytes, instead of + // the required minimum of 64 bytes. + resetDataLayout( + "e-m:e-p:32:32:32-a:0-n16:32-" + "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-" + "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + + // {} in inline assembly are packet specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + LargeArrayMinWidth = 64; + LargeArrayAlign = 64; + UseBitFieldTypeAlignment = true; + ZeroLengthBitfieldBoundary = 32; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + case 'v': + case 'q': + if (HasHVX) { + Info.setAllowsRegister(); + return true; + } + break; + case 'a': // Modifier register m0-m1. + Info.setAllowsRegister(); + return true; + case 's': + // Relocatable constant. + return true; + } + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isCLZForZeroUndef() const override { return false; } + + bool hasFeature(StringRef Feature) const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + const char *getClobbers() const override { return ""; } + + static const char *getHexagonCPUSuffix(StringRef Name); + + bool isValidCPUName(StringRef Name) const override { + return getHexagonCPUSuffix(Name); + } + + bool setCPU(const std::string &Name) override { + if (!isValidCPUName(Name)) + return false; + CPU = Name; + return true; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + return RegNo < 2 ? RegNo : -1; + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.cpp new file mode 100644 index 0000000000000..1d8314af99fbe --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.cpp @@ -0,0 +1,67 @@ +//===--- Lanai.cpp - Implement Lanai target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Lanai TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const char *const LanaiTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", + "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = { + {{"pc"}, "r2"}, {{"sp"}, "r4"}, {{"fp"}, "r5"}, {{"rv"}, "r8"}, + {{"rr1"}, "r10"}, {{"rr2"}, "r11"}, {{"rca"}, "r15"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool LanaiTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name).Case("v11", true).Default(false); +} + +bool LanaiTargetInfo::setCPU(const std::string &Name) { + CPU = llvm::StringSwitch<CPUKind>(Name).Case("v11", CK_V11).Default(CK_NONE); + + return CPU != CK_NONE; +} + +bool LanaiTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false); +} + +void LanaiTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Define __lanai__ when building for target lanai. + Builder.defineMacro("__lanai__"); + + // Set define for the CPU specified. + switch (CPU) { + case CK_V11: + Builder.defineMacro("__LANAI_V11__"); + break; + case CK_NONE: + llvm_unreachable("Unhandled target CPU"); + } +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.h new file mode 100644 index 0000000000000..5f99c17a53447 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Lanai.h @@ -0,0 +1,92 @@ +//===--- Lanai.h - Declare Lanai target feature support ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Lanai TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY LanaiTargetInfo : public TargetInfo { + // Class for Lanai (32-bit). + // The CPU profiles supported by the Lanai backend + enum CPUKind { + CK_NONE, + CK_V11, + } CPU; + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + +public: + LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + // Description string has to be kept in sync with backend. + resetDataLayout("E" // Big endian + "-m:e" // ELF name manging + "-p:32:32" // 32 bit pointers, 32 bit aligned + "-i64:64" // 64 bit integers, 64 bit aligned + "-a:0:32" // 32 bit alignment of objects of aggregate type + "-n32" // 32 bit native integer width + "-S64" // 64 bit natural stack alignment + ); + + // Setting RegParmMax equal to what mregparm was set to in the old + // toolchain + RegParmMax = 4; + + // Set the default CPU to V11 + CPU = CK_V11; + + // Temporary approach to make everything at least word-aligned and allow for + // safely casting between pointers with different alignment requirements. + // TODO: Remove this when there are no more cast align warnings on the + // firmware. + MinGlobalAlign = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isValidCPUName(StringRef Name) const override; + + bool setCPU(const std::string &Name) override; + + bool hasFeature(StringRef Feature) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return false; + } + + const char *getClobbers() const override { return ""; } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.cpp new file mode 100644 index 0000000000000..5a1c1c88e7e3d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.cpp @@ -0,0 +1,39 @@ +//===--- Le64.cpp - Implement Le64 target feature support -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Le64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Le64.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsLe64.def" +}; + +ArrayRef<Builtin::Info> Le64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Le64::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +void Le64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "unix", Opts); + defineCPUMacros(Builder, "le64", /*Tuning=*/false); + Builder.defineMacro("__ELF__"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.h new file mode 100644 index 0000000000000..5e18d04986415 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Le64.h @@ -0,0 +1,64 @@ +//===--- Le64.h - Declare Le64 target feature support -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Le64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY Le64TargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + +public: + Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + bool hasProtectedVisibility() const override { return false; } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp new file mode 100644 index 0000000000000..86f85a398f142 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp @@ -0,0 +1,34 @@ +//===--- MSP430.cpp - Implement MSP430 target feature support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements MSP430 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +const char *const MSP430TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +void MSP430TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("MSP430"); + Builder.defineMacro("__MSP430__"); + // FIXME: defines for different 'flavours' of MCU +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.h b/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.h new file mode 100644 index 0000000000000..72aafb9459bdb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/MSP430.h @@ -0,0 +1,92 @@ +//===--- MSP430.h - Declare MSP430 target feature support -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares MSP430 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + +public: + MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + IntWidth = 16; + IntAlign = 16; + LongWidth = 32; + LongLongWidth = 64; + LongAlign = LongLongAlign = 16; + PointerWidth = 16; + PointerAlign = 16; + SuitableAlign = 16; + SizeType = UnsignedInt; + IntMaxType = SignedLongLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + SigAtomicType = SignedLong; + resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"); + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + // FIXME: Implement. + return None; + } + + bool hasFeature(StringRef Feature) const override { + return Feature == "msp430"; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + // FIXME: implement + switch (*Name) { + case 'K': // the constant 1 + case 'L': // constant -1^20 .. 1^19 + case 'M': // constant 1-4: + return true; + } + // No target constraints for now. + return false; + } + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // FIXME: implement + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.cpp new file mode 100644 index 0000000000000..a8a1bcc363618 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.cpp @@ -0,0 +1,252 @@ +//===--- Mips.cpp - Implement Mips target feature support -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Mips TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "Targets.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info MipsTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsMips.def" +}; + +bool MipsTargetInfo::processorSupportsGPR64() const { + return llvm::StringSwitch<bool>(CPU) + .Case("mips3", true) + .Case("mips4", true) + .Case("mips5", true) + .Case("mips64", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Default(false); + return false; +} + +bool MipsTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) + .Case("mips1", true) + .Case("mips2", true) + .Case("mips3", true) + .Case("mips4", true) + .Case("mips5", true) + .Case("mips32", true) + .Case("mips32r2", true) + .Case("mips32r3", true) + .Case("mips32r5", true) + .Case("mips32r6", true) + .Case("mips64", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Case("p5600", true) + .Default(false); +} + +void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (BigEndian) { + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + } else { + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + } + + Builder.defineMacro("__mips__"); + Builder.defineMacro("_mips"); + if (Opts.GNUMode) + Builder.defineMacro("mips"); + + if (ABI == "o32") { + Builder.defineMacro("__mips", "32"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); + } else { + Builder.defineMacro("__mips", "64"); + Builder.defineMacro("__mips64"); + Builder.defineMacro("__mips64__"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); + } + + const std::string ISARev = llvm::StringSwitch<std::string>(getCPU()) + .Cases("mips32", "mips64", "1") + .Cases("mips32r2", "mips64r2", "2") + .Cases("mips32r3", "mips64r3", "3") + .Cases("mips32r5", "mips64r5", "5") + .Cases("mips32r6", "mips64r6", "6") + .Default(""); + if (!ISARev.empty()) + Builder.defineMacro("__mips_isa_rev", ISARev); + + if (ABI == "o32") { + Builder.defineMacro("__mips_o32"); + Builder.defineMacro("_ABIO32", "1"); + Builder.defineMacro("_MIPS_SIM", "_ABIO32"); + } else if (ABI == "n32") { + Builder.defineMacro("__mips_n32"); + Builder.defineMacro("_ABIN32", "2"); + Builder.defineMacro("_MIPS_SIM", "_ABIN32"); + } else if (ABI == "n64") { + Builder.defineMacro("__mips_n64"); + Builder.defineMacro("_ABI64", "3"); + Builder.defineMacro("_MIPS_SIM", "_ABI64"); + } else + llvm_unreachable("Invalid ABI."); + + if (!IsNoABICalls) { + Builder.defineMacro("__mips_abicalls"); + if (CanUseBSDABICalls) + Builder.defineMacro("__ABICALLS__"); + } + + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + switch (FloatABI) { + case HardFloat: + Builder.defineMacro("__mips_hard_float", Twine(1)); + break; + case SoftFloat: + Builder.defineMacro("__mips_soft_float", Twine(1)); + break; + } + + if (IsSingleFloat) + Builder.defineMacro("__mips_single_float", Twine(1)); + + Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); + Builder.defineMacro("_MIPS_FPSET", + Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); + + if (IsMips16) + Builder.defineMacro("__mips16", Twine(1)); + + if (IsMicromips) + Builder.defineMacro("__mips_micromips", Twine(1)); + + if (IsNan2008) + Builder.defineMacro("__mips_nan2008", Twine(1)); + + if (IsAbs2008) + Builder.defineMacro("__mips_abs2008", Twine(1)); + + switch (DspRev) { + default: + break; + case DSP1: + Builder.defineMacro("__mips_dsp_rev", Twine(1)); + Builder.defineMacro("__mips_dsp", Twine(1)); + break; + case DSP2: + Builder.defineMacro("__mips_dsp_rev", Twine(2)); + Builder.defineMacro("__mips_dspr2", Twine(1)); + Builder.defineMacro("__mips_dsp", Twine(1)); + break; + } + + if (HasMSA) + Builder.defineMacro("__mips_msa", Twine(1)); + + if (DisableMadd4) + Builder.defineMacro("__mips_no_madd4", Twine(1)); + + Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); + Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); + Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); + + Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); + Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + + // These shouldn't be defined for MIPS-I but there's no need to check + // for that since MIPS-I isn't supported. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + + // 32-bit MIPS processors don't have the necessary lld/scd instructions + // found in 64-bit processors. In the case of O32 on a 64-bit processor, + // the instructions exist but using them violates the ABI since they + // require 64-bit GPRs and O32 only supports 32-bit GPRs. + if (ABI == "n32" || ABI == "n64") + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +} + +bool MipsTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("mips", true) + .Case("fp64", HasFP64) + .Default(false); +} + +ArrayRef<Builtin::Info> MipsTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const { + // microMIPS64R6 backend was removed. + if ((getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el) && + IsMicromips && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_cpu_for_micromips) << CPU; + return false; + } + // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle + // this yet. It's better to fail here than on the backend assertion. + if (processorSupportsGPR64() && ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // 64-bit ABI's require 64-bit CPU's. + if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if ((getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el) && + ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if ((getTriple().getArch() == llvm::Triple::mips || + getTriple().getArch() == llvm::Triple::mipsel) && + (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + return true; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.h new file mode 100644 index 0000000000000..28900f21f86ba --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Mips.h @@ -0,0 +1,397 @@ +//===--- Mips.h - Declare Mips target feature support -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Mips TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { + void setDataLayout() { + StringRef Layout; + + if (ABI == "o32") + Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; + else if (ABI == "n32") + Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else if (ABI == "n64") + Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else + llvm_unreachable("Invalid ABI"); + + if (BigEndian) + resetDataLayout(("E-" + Layout).str()); + else + resetDataLayout(("e-" + Layout).str()); + } + + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + bool IsMips16; + bool IsMicromips; + bool IsNan2008; + bool IsAbs2008; + bool IsSingleFloat; + bool IsNoABICalls; + bool CanUseBSDABICalls; + enum MipsFloatABI { HardFloat, SoftFloat } FloatABI; + enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; + bool HasMSA; + bool DisableMadd4; + +protected: + bool HasFP64; + std::string ABI; + +public: + MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), IsMips16(false), IsMicromips(false), + IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), + IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), + DspRev(NoDSP), HasMSA(false), DisableMadd4(false), HasFP64(false) { + TheCXXABI.set(TargetCXXABI::GenericMIPS); + + setABI((getTriple().getArch() == llvm::Triple::mips || + getTriple().getArch() == llvm::Triple::mipsel) + ? "o32" + : "n64"); + + CPU = ABI == "o32" ? "mips32r2" : "mips64r2"; + + CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD || + Triple.getOS() == llvm::Triple::OpenBSD; + } + + bool isIEEE754_2008Default() const { + return CPU == "mips32r6" || CPU == "mips64r6"; + } + + bool isFP64Default() const { + return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; + } + + bool isNan2008() const override { return IsNan2008; } + + bool processorSupportsGPR64() const; + + StringRef getABI() const override { return ABI; } + + bool setABI(const std::string &Name) override { + if (Name == "o32") { + setO32ABITypes(); + ABI = Name; + return true; + } + + if (Name == "n32") { + setN32ABITypes(); + ABI = Name; + return true; + } + if (Name == "n64") { + setN64ABITypes(); + ABI = Name; + return true; + } + return false; + } + + void setO32ABITypes() { + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + LongDoubleWidth = LongDoubleAlign = 64; + LongWidth = LongAlign = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + PointerWidth = PointerAlign = 32; + PtrDiffType = SignedInt; + SizeType = UnsignedInt; + SuitableAlign = 64; + } + + void setN32N64ABITypes() { + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + if (getTriple().getOS() == llvm::Triple::FreeBSD) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + SuitableAlign = 128; + } + + void setN64ABITypes() { + setN32N64ABITypes(); + if (getTriple().getOS() == llvm::Triple::OpenBSD) { + Int64Type = SignedLongLong; + } else { + Int64Type = SignedLong; + } + IntMaxType = Int64Type; + LongWidth = LongAlign = 64; + PointerWidth = PointerAlign = 64; + PtrDiffType = SignedLong; + SizeType = UnsignedLong; + } + + void setN32ABITypes() { + setN32N64ABITypes(); + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + LongWidth = LongAlign = 32; + PointerWidth = PointerAlign = 32; + PtrDiffType = SignedInt; + SizeType = UnsignedInt; + } + + bool isValidCPUName(StringRef Name) const override; + + bool setCPU(const std::string &Name) override { + CPU = Name; + return isValidCPUName(Name); + } + + const std::string &getCPU() const { return CPU; } + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + if (CPU.empty()) + CPU = getCPU(); + if (CPU == "octeon") + Features["mips64r2"] = Features["cnmips"] = true; + else + Features[CPU] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool hasFeature(StringRef Feature) const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // CPU register names + // Must match second column of GCCRegAliases + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", + "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", + "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", + "$31", + // Floating point register names + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", + "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", + "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", + "$f28", "$f29", "$f30", "$f31", + // Hi/lo and condition register names + "hi", "lo", "", "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", + "$fcc6", "$fcc7", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo", "$ac3hi", + "$ac3lo", + // MSA register names + "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9", + "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18", + "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27", + "$w28", "$w29", "$w30", "$w31", + // MSA control register names + "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", + "$msarequest", "$msamap", "$msaunmap" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backward compatibility only. + case 'f': // floating-point registers. + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + Info.setAllowsRegister(); + return true; + case 'I': // Signed 16-bit constant + case 'J': // Integer 0 + case 'K': // Unsigned 16-bit constant + case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) + case 'M': // Constants not loadable via lui, addiu, or ori + case 'N': // Constant -1 to -65535 + case 'O': // A signed 15-bit constant + case 'P': // A constant between 1 go 65535 + return true; + case 'R': // An address that can be used in a non-macro load or store + Info.setAllowsMemory(); + return true; + case 'Z': + if (Name[1] == 'C') { // An address usable by ll, and sc. + Info.setAllowsMemory(); + Name++; // Skip over 'Z'. + return true; + } + return false; + } + } + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'Z': // Two-character constraint; add "^" hint for later parsing. + if (Constraint[1] == 'C') { + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + return R; + } + break; + } + return TargetInfo::convertConstraint(Constraint); + } + + const char *getClobbers() const override { + // In GCC, $1 is not widely used in generated code (it's used only in a few + // specific situations), so there is no real need for users to add it to + // the clobbers list if they want to use it in their inline assembly code. + // + // In LLVM, $1 is treated as a normal GPR and is always allocatable during + // code generation, so using it in inline assembly without adding it to the + // clobbers list can cause conflicts between the inline assembly code and + // the surrounding generated code. + // + // Another problem is that LLVM is allowed to choose $1 for inline assembly + // operands, which will conflict with the ".set at" assembler option (which + // we use only for inline assembly, in order to maintain compatibility with + // GCC) and will also conflict with the user's usage of $1. + // + // The easiest way to avoid these conflicts and keep $1 as an allocatable + // register for generated code is to automatically clobber $1 for all inline + // assembly code. + // + // FIXME: We should automatically clobber $1 only for inline assembly code + // which actually uses it. This would allow LLVM to use $1 for inline + // assembly operands if the user's assembly code doesn't use it. + return "~{$1}"; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + IsMips16 = false; + IsMicromips = false; + IsNan2008 = isIEEE754_2008Default(); + IsAbs2008 = isIEEE754_2008Default(); + IsSingleFloat = false; + FloatABI = HardFloat; + DspRev = NoDSP; + HasFP64 = isFP64Default(); + + for (const auto &Feature : Features) { + if (Feature == "+single-float") + IsSingleFloat = true; + else if (Feature == "+soft-float") + FloatABI = SoftFloat; + else if (Feature == "+mips16") + IsMips16 = true; + else if (Feature == "+micromips") + IsMicromips = true; + else if (Feature == "+dsp") + DspRev = std::max(DspRev, DSP1); + else if (Feature == "+dspr2") + DspRev = std::max(DspRev, DSP2); + else if (Feature == "+msa") + HasMSA = true; + else if (Feature == "+nomadd4") + DisableMadd4 = true; + else if (Feature == "+fp64") + HasFP64 = true; + else if (Feature == "-fp64") + HasFP64 = false; + else if (Feature == "+nan2008") + IsNan2008 = true; + else if (Feature == "-nan2008") + IsNan2008 = false; + else if (Feature == "+abs2008") + IsAbs2008 = true; + else if (Feature == "-abs2008") + IsAbs2008 = false; + else if (Feature == "+noabicalls") + IsNoABICalls = true; + } + + setDataLayout(); + + return true; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 4; + if (RegNo == 1) + return 5; + return -1; + } + + bool isCLZForZeroUndef() const override { return false; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + static const TargetInfo::GCCRegAlias O32RegAliases[] = { + {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, + {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, + {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"}, + {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"}, + {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"}, + {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, + {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, + {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, + {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, + {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, + {{"ra"}, "$31"} + }; + static const TargetInfo::GCCRegAlias NewABIRegAliases[] = { + {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, + {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, + {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"}, + {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"}, + {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"}, + {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, + {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, + {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, + {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, + {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, + {{"ra"}, "$31"} + }; + if (ABI == "o32") + return llvm::makeArrayRef(O32RegAliases); + return llvm::makeArrayRef(NewABIRegAliases); + } + + bool hasInt128Type() const override { return ABI == "n32" || ABI == "n64"; } + + bool validateTarget(DiagnosticsEngine &Diags) const override; +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.cpp new file mode 100644 index 0000000000000..add3b318aeb6d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.cpp @@ -0,0 +1,199 @@ +//===--- NVPTX.cpp - Implement NVPTX target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements NVPTX TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "NVPTX.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsNVPTX.def" +}; + +const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; + +NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts, + unsigned TargetPointerWidth) + : TargetInfo(Triple) { + assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) && + "NVPTX only supports 32- and 64-bit modes."); + + TLSSupported = false; + VLASupported = false; + AddrSpaceMap = &NVPTXAddrSpaceMap; + UseAddrSpaceMapMangling = true; + + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + GPU = CudaArch::SM_20; + + if (TargetPointerWidth == 32) + resetDataLayout("e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); + else + resetDataLayout("e-i64:64-i128:128-v16:16-v32:32-n16:32:64"); + + // If possible, get a TargetInfo for our host triple, so we can match its + // types. + llvm::Triple HostTriple(Opts.HostTriple); + if (!HostTriple.isNVPTX()) + HostTarget.reset(AllocateTarget(llvm::Triple(Opts.HostTriple), Opts)); + + // If no host target, make some guesses about the data layout and return. + if (!HostTarget) { + LongWidth = LongAlign = TargetPointerWidth; + PointerWidth = PointerAlign = TargetPointerWidth; + switch (TargetPointerWidth) { + case 32: + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = TargetInfo::SignedInt; + IntPtrType = TargetInfo::SignedInt; + break; + case 64: + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = TargetInfo::SignedLong; + IntPtrType = TargetInfo::SignedLong; + break; + default: + llvm_unreachable("TargetPointerWidth must be 32 or 64"); + } + return; + } + + // Copy properties from host target. + PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0); + PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0); + BoolWidth = HostTarget->getBoolWidth(); + BoolAlign = HostTarget->getBoolAlign(); + IntWidth = HostTarget->getIntWidth(); + IntAlign = HostTarget->getIntAlign(); + HalfWidth = HostTarget->getHalfWidth(); + HalfAlign = HostTarget->getHalfAlign(); + FloatWidth = HostTarget->getFloatWidth(); + FloatAlign = HostTarget->getFloatAlign(); + DoubleWidth = HostTarget->getDoubleWidth(); + DoubleAlign = HostTarget->getDoubleAlign(); + LongWidth = HostTarget->getLongWidth(); + LongAlign = HostTarget->getLongAlign(); + LongLongWidth = HostTarget->getLongLongWidth(); + LongLongAlign = HostTarget->getLongLongAlign(); + MinGlobalAlign = HostTarget->getMinGlobalAlign(); + NewAlign = HostTarget->getNewAlign(); + DefaultAlignForAttributeAligned = + HostTarget->getDefaultAlignForAttributeAligned(); + SizeType = HostTarget->getSizeType(); + IntMaxType = HostTarget->getIntMaxType(); + PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0); + IntPtrType = HostTarget->getIntPtrType(); + WCharType = HostTarget->getWCharType(); + WIntType = HostTarget->getWIntType(); + Char16Type = HostTarget->getChar16Type(); + Char32Type = HostTarget->getChar32Type(); + Int64Type = HostTarget->getInt64Type(); + SigAtomicType = HostTarget->getSigAtomicType(); + ProcessIDType = HostTarget->getProcessIDType(); + + UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); + UseZeroLengthBitfieldAlignment = HostTarget->useZeroLengthBitfieldAlignment(); + UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); + ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); + + // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and + // we need those macros to be identical on host and device, because (among + // other things) they affect which standard library classes are defined, and + // we need all classes to be defined on both the host and device. + MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); + + // Properties intentionally not copied from host: + // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the + // host/device boundary. + // - SuitableAlign: Not visible across the host/device boundary, and may + // correctly be different on host/device, e.g. if host has wider vector + // types than device. + // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same + // as its double type, but that's not necessarily true on the host. + // TODO: nvcc emits a warning when using long double on device; we should + // do the same. +} + +ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +bool NVPTXTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Cases("ptx", "nvptx", true) + .Case("satom", GPU >= CudaArch::SM_60) // Atomics w/ scope. + .Default(false); +} + +void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__PTX__"); + Builder.defineMacro("__NVPTX__"); + if (Opts.CUDAIsDevice) { + // Set __CUDA_ARCH__ for the GPU specified. + std::string CUDAArchCode = [this] { + switch (GPU) { + case CudaArch::UNKNOWN: + assert(false && "No GPU arch when compiling CUDA device code."); + return ""; + case CudaArch::SM_20: + return "200"; + case CudaArch::SM_21: + return "210"; + case CudaArch::SM_30: + return "300"; + case CudaArch::SM_32: + return "320"; + case CudaArch::SM_35: + return "350"; + case CudaArch::SM_37: + return "370"; + case CudaArch::SM_50: + return "500"; + case CudaArch::SM_52: + return "520"; + case CudaArch::SM_53: + return "530"; + case CudaArch::SM_60: + return "600"; + case CudaArch::SM_61: + return "610"; + case CudaArch::SM_62: + return "620"; + case CudaArch::SM_70: + return "700"; + } + llvm_unreachable("unhandled CudaArch"); + }(); + Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); + } +} + +ArrayRef<Builtin::Info> NVPTXTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.h b/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.h new file mode 100644 index 0000000000000..a84870763f545 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/NVPTX.h @@ -0,0 +1,132 @@ +//===--- NVPTX.h - Declare NVPTX target feature support ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares NVPTX TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H + +#include "clang/Basic/Cuda.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +static const unsigned NVPTXAddrSpaceMap[] = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 4, // opencl_constant + 0, // opencl_private + // FIXME: generic has to be added to the target + 0, // opencl_generic + 1, // cuda_device + 4, // cuda_constant + 3, // cuda_shared +}; + +class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; + CudaArch GPU; + std::unique_ptr<TargetInfo> HostTarget; + +public: + NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts, + unsigned TargetPointerWidth); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + Features["satom"] = GPU >= CudaArch::SM_60; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool hasFeature(StringRef Feature) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'c': + case 'h': + case 'r': + case 'l': + case 'f': + case 'd': + Info.setAllowsRegister(); + return true; + } + } + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // FIXME: implement + return TargetInfo::CharPtrBuiltinVaList; + } + + bool isValidCPUName(StringRef Name) const override { + return StringToCudaArch(Name) != CudaArch::UNKNOWN; + } + + bool setCPU(const std::string &Name) override { + GPU = StringToCudaArch(Name); + return GPU != CudaArch::UNKNOWN; + } + + void setSupportedOpenCLOpts() override { + auto &Opts = getSupportedOpenCLOpts(); + Opts.support("cl_clang_storage_class_specifiers"); + Opts.support("cl_khr_gl_sharing"); + Opts.support("cl_khr_icd"); + + Opts.support("cl_khr_fp64"); + Opts.support("cl_khr_byte_addressable_store"); + Opts.support("cl_khr_global_int32_base_atomics"); + Opts.support("cl_khr_global_int32_extended_atomics"); + Opts.support("cl_khr_local_int32_base_atomics"); + Opts.support("cl_khr_local_int32_extended_atomics"); + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // CUDA compilations support all of the host's calling conventions. + // + // TODO: We should warn if you apply a non-default CC to anything other than + // a host function. + if (HostTarget) + return HostTarget->checkCallingConvention(CC); + return CCCR_Warning; + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.cpp new file mode 100644 index 0000000000000..48f662dd98c1d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.cpp @@ -0,0 +1,56 @@ +//===--- Nios2.cpp - Implement Nios2 target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Nios2 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Nios2.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsNios2.def" +}; + +bool Nios2TargetInfo::isFeatureSupportedByCPU(StringRef Feature, + StringRef CPU) const { + const bool isR2 = CPU == "nios2r2"; + return llvm::StringSwitch<bool>(Feature) + .Case("nios2r2mandatory", isR2) + .Case("nios2r2bmx", isR2) + .Case("nios2r2mpx", isR2) + .Case("nios2r2cdx", isR2) + .Default(false); +} + +void Nios2TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "nios2", Opts); + DefineStd(Builder, "NIOS2", Opts); + + Builder.defineMacro("__nios2"); + Builder.defineMacro("__NIOS2"); + Builder.defineMacro("__nios2__"); + Builder.defineMacro("__NIOS2__"); +} + +ArrayRef<Builtin::Info> Nios2TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.h new file mode 100644 index 0000000000000..aa02f8f6262fe --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Nios2.h @@ -0,0 +1,147 @@ +//===--- Nios2.h - Declare Nios2 target feature support ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Nios2 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY Nios2TargetInfo : public TargetInfo { + void setDataLayout() { + if (BigEndian) + resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32"); + else + resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32"); + } + + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + std::string ABI; + +public: + Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts) + : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + setDataLayout(); + } + + StringRef getABI() const override { return ABI; } + bool setABI(const std::string &Name) override { + if (Name == "o32" || Name == "eabi") { + ABI = Name; + return true; + } + return false; + } + + bool isValidCPUName(StringRef Name) const override { + return Name == "nios2r1" || Name == "nios2r2"; + } + + bool setCPU(const std::string &Name) override { + if (isValidCPUName(Name)) { + CPU = Name; + return true; + } + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeatureVec) const override { + static const char *allFeatures[] = {"nios2r2mandatory", "nios2r2bmx", + "nios2r2mpx", "nios2r2cdx" + }; + for (const char *feature : allFeatures) { + Features[feature] = isFeatureSupportedByCPU(feature, CPU); + } + return true; + } + + bool hasFeature(StringRef Feature) const override { + return isFeatureSupportedByCPU(Feature, CPU); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // CPU register names + // Must match second column of GCCRegAliases + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", + "r31", + // Floating point register names + "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8", + "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backwards compatibility only. + case 'f': // floating-point registers. + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + Info.setAllowsRegister(); + return true; + } + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + static const TargetInfo::GCCRegAlias aliases[] = { + {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"}, + {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"}, + {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"}, + {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"}, + {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"}, + {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"}, + {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"}, + {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"}, + }; + return llvm::makeArrayRef(aliases); + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.cpp new file mode 100644 index 0000000000000..50abd4ce0c8c3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.cpp @@ -0,0 +1,139 @@ +//===--- OSTargets.cpp - Implement OS target feature support --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements OS specific TargetInfo types. +//===----------------------------------------------------------------------===// + +#include "OSTargets.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple, StringRef &PlatformName, + VersionTuple &PlatformMinVersion) { + Builder.defineMacro("__APPLE_CC__", "6000"); + Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__STDC_NO_THREADS__"); + Builder.defineMacro("OBJC_NEW_PROPERTIES"); + // AddressSanitizer doesn't play well with source fortification, which is on + // by default on Darwin. + if (Opts.Sanitize.has(SanitizerKind::Address)) + Builder.defineMacro("_FORTIFY_SOURCE", "0"); + + // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. + if (!Opts.ObjC1) { + // __weak is always defined, for use in blocks and with objc pointers. + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + Builder.defineMacro("__strong", ""); + Builder.defineMacro("__unsafe_unretained", ""); + } + + if (Opts.Static) + Builder.defineMacro("__STATIC__"); + else + Builder.defineMacro("__DYNAMIC__"); + + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + + // Get the platform type and version number from the triple. + unsigned Maj, Min, Rev; + if (Triple.isMacOSX()) { + Triple.getMacOSXVersion(Maj, Min, Rev); + PlatformName = "macos"; + } else { + Triple.getOSVersion(Maj, Min, Rev); + PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + } + + // If -target arch-pc-win32-macho option specified, we're + // generating code for Win32 ABI. No need to emit + // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. + if (PlatformName == "win32") { + PlatformMinVersion = VersionTuple(Maj, Min, Rev); + return; + } + + // Set the appropriate OS version define. + if (Triple.isiOS()) { + assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[7]; + if (Maj < 10) { + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + } else { + // Handle versions >= 10. + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + (Min / 10); + Str[3] = '0' + (Min % 10); + Str[4] = '0' + (Rev / 10); + Str[5] = '0' + (Rev % 10); + Str[6] = '\0'; + } + if (Triple.isTvOS()) + Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); + else + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + Str); + + } else if (Triple.isWatchOS()) { + assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[6]; + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); + } else if (Triple.isMacOSX()) { + // Note that the Driver allows versions which aren't representable in the + // define (because we only get a single digit for the minor and micro + // revision numbers). So, we limit them to the maximum representable + // version. + assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[7]; + if (Maj < 10 || (Maj == 10 && Min < 10)) { + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + std::min(Min, 9U); + Str[3] = '0' + std::min(Rev, 9U); + Str[4] = '\0'; + } else { + // Handle versions > 10.9. + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + (Min / 10); + Str[3] = '0' + (Min % 10); + Str[4] = '0' + (Rev / 10); + Str[5] = '0' + (Rev % 10); + Str[6] = '\0'; + } + Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); + } + + // Tell users about the kernel if there is one. + if (Triple.isOSDarwin()) + Builder.defineMacro("__MACH__"); + + PlatformMinVersion = VersionTuple(Maj, Min, Rev); +} +} // namespace targets +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.h b/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.h new file mode 100644 index 0000000000000..5af63615dc5ec --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/OSTargets.h @@ -0,0 +1,725 @@ +//===--- OSTargets.h - Declare OS target feature support --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares OS specific TargetInfo types. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H + +#include "Targets.h" +#include "llvm/MC/MCSectionMachO.h" + +namespace clang { +namespace targets { + +template <typename TgtInfo> +class LLVM_LIBRARY_VISIBILITY OSTargetInfo : public TgtInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const = 0; + +public: + OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TgtInfo(Triple, Opts) {} + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + TgtInfo::getTargetDefines(Opts, Builder); + getOSDefines(Opts, TgtInfo::getTriple(), Builder); + } +}; + +// CloudABI Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY CloudABITargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__CloudABI__"); + Builder.defineMacro("__ELF__"); + + // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. + Builder.defineMacro("__STDC_ISO_10646__", "201206L"); + Builder.defineMacro("__STDC_UTF_16__"); + Builder.defineMacro("__STDC_UTF_32__"); + } + +public: + CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Ananas target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY AnanasTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Ananas defines + Builder.defineMacro("__Ananas__"); + Builder.defineMacro("__ELF__"); + } + +public: + AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple, StringRef &PlatformName, + VersionTuple &PlatformMinVersion); + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY DarwinTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + getDarwinDefines(Builder, Opts, Triple, this->PlatformName, + this->PlatformMinVersion); + } + +public: + DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + // By default, no TLS, and we whitelist permitted architecture/OS + // combinations. + this->TLSSupported = false; + + if (Triple.isMacOSX()) + this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7); + else if (Triple.isiOS()) { + // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards. + if (Triple.getArch() == llvm::Triple::x86_64 || + Triple.getArch() == llvm::Triple::aarch64) + this->TLSSupported = !Triple.isOSVersionLT(8); + else if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) + this->TLSSupported = !Triple.isOSVersionLT(9); + } else if (Triple.isWatchOS()) + this->TLSSupported = !Triple.isOSVersionLT(2); + + this->MCountName = "\01mcount"; + } + + std::string isValidSectionSpecifier(StringRef SR) const override { + // Let MCSectionMachO validate this. + StringRef Segment, Section; + unsigned TAA, StubSize; + bool HasTAA; + return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, + TAA, HasTAA, StubSize); + } + + const char *getStaticInitSectionSpecifier() const override { + // FIXME: We should return 0 when building kexts. + return "__TEXT,__StaticInit,regular,pure_instructions"; + } + + /// Darwin does not support protected visibility. Darwin's "default" + /// is very similar to ELF's "protected"; Darwin requires a "weak" + /// attribute on declarations that can be dynamically replaced. + bool hasProtectedVisibility() const override { return false; } +}; + +// DragonFlyBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY DragonFlyBSDTargetInfo + : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // DragonFly defines; list based off of gcc output + Builder.defineMacro("__DragonFly__"); + Builder.defineMacro("__DragonFly_cc_version", "100001"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + Builder.defineMacro("__tune_i386__"); + DefineStd(Builder, "unix", Opts); + } + +public: + DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + } + } +}; + +#ifndef FREEBSD_CC_VERSION +#define FREEBSD_CC_VERSION 0U +#endif + +// FreeBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY FreeBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // FreeBSD defines; list based off of gcc output + + unsigned Release = Triple.getOSMajorVersion(); + if (Release == 0U) + Release = 8U; + unsigned CCVersion = FREEBSD_CC_VERSION; + if (CCVersion == 0U) + CCVersion = Release * 100000U + 1U; + + Builder.defineMacro("__FreeBSD__", Twine(Release)); + Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion)); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + + // On FreeBSD, wchar_t contains the number of the code point as + // used by the character set of the locale. These character sets are + // not necessarily a superset of ASCII. + // + // FIXME: This is wrong; the macro refers to the numerical values + // of wchar_t *literals*, which are not locale-dependent. However, + // FreeBSD systems apparently depend on us getting this wrong, and + // setting this to 1 is conforming even if all the basic source + // character literals have the same encoding as char and wchar_t. + Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1"); + } + +public: + FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + case llvm::Triple::arm: + this->MCountName = "__mcount"; + break; + } + } +}; + +// GNU/kFreeBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY KFreeBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // GNU/kFreeBSD defines; list based off of gcc output + + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__FreeBSD_kernel__"); + Builder.defineMacro("__GLIBC__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Haiku Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY HaikuTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Haiku defines; list based off of gcc output + Builder.defineMacro("__HAIKU__"); + Builder.defineMacro("__ELF__"); + DefineStd(Builder, "unix", Opts); + } + +public: + HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->SizeType = TargetInfo::UnsignedLong; + this->IntPtrType = TargetInfo::SignedLong; + this->PtrDiffType = TargetInfo::SignedLong; + this->ProcessIDType = TargetInfo::SignedLong; + this->TLSSupported = false; + } +}; + +// Minix Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY MinixTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Minix defines + + Builder.defineMacro("__minix", "3"); + Builder.defineMacro("_EM_WSIZE", "4"); + Builder.defineMacro("_EM_PSIZE", "4"); + Builder.defineMacro("_EM_SSIZE", "2"); + Builder.defineMacro("_EM_LSIZE", "4"); + Builder.defineMacro("_EM_FSIZE", "4"); + Builder.defineMacro("_EM_DSIZE", "8"); + Builder.defineMacro("__ELF__"); + DefineStd(Builder, "unix", Opts); + } + +public: + MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Linux target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY LinuxTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Linux defines; list based off of gcc output + DefineStd(Builder, "unix", Opts); + DefineStd(Builder, "linux", Opts); + Builder.defineMacro("__gnu_linux__"); + Builder.defineMacro("__ELF__"); + if (Triple.isAndroid()) { + Builder.defineMacro("__ANDROID__", "1"); + unsigned Maj, Min, Rev; + Triple.getEnvironmentVersion(Maj, Min, Rev); + this->PlatformName = "android"; + this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); + if (Maj) + Builder.defineMacro("__ANDROID_API__", Twine(Maj)); + } + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WIntType = TargetInfo::UnsignedInt; + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + case llvm::Triple::systemz: + this->HasFloat128 = true; + break; + } + } + + const char *getStaticInitSectionSpecifier() const override { + return ".text.startup"; + } +}; + +// NetBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY NetBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // NetBSD defines; list based off of gcc output + Builder.defineMacro("__NetBSD__"); + Builder.defineMacro("__unix__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + } + +public: + NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "_mcount"; + } +}; + +// OpenBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY OpenBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // OpenBSD defines; list based off of gcc output + + Builder.defineMacro("__OpenBSD__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + // FALLTHROUGH + default: + this->MCountName = "__mcount"; + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::sparcv9: + this->MCountName = "_mcount"; + break; + } + } +}; + +// PSP Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PSPTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // PSP defines; list based on the output of the pspdev gcc toolchain. + Builder.defineMacro("PSP"); + Builder.defineMacro("_PSP"); + Builder.defineMacro("__psp__"); + Builder.defineMacro("__ELF__"); + } + +public: + PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {} +}; + +// PS3 PPU Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PS3PPUTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // PS3 PPU defines. + Builder.defineMacro("__PPC__"); + Builder.defineMacro("__PPU__"); + Builder.defineMacro("__CELLOS_LV2__"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__LP32__"); + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("__powerpc64__"); + } + +public: + PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->LongWidth = this->LongAlign = 32; + this->PointerWidth = this->PointerAlign = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->SizeType = TargetInfo::UnsignedInt; + this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64"); + } +}; + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PS4OSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__FreeBSD__", "9"); + Builder.defineMacro("__FreeBSD_cc_version", "900001"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__ORBIS__"); + } + +public: + PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + + // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). + this->MaxTLSAlign = 256; + + // On PS4, do not honor explicit bit field alignment, + // as in "__attribute__((aligned(2))) int b : 1;". + this->UseExplicitBitFieldAlignment = false; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + } + } +}; + +// RTEMS Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY RTEMSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // RTEMS defines; list based off of gcc output + + Builder.defineMacro("__rtems__"); + Builder.defineMacro("__ELF__"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + // this->MCountName = ".mcount"; + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + // this->MCountName = "_mcount"; + break; + case llvm::Triple::arm: + // this->MCountName = "__mcount"; + break; + } + } +}; + +// Solaris target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY SolarisTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); + // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and + // newer, but to 500 for everything else. feature_test.h has a check to + // ensure that you are not using C99 with an old version of X/Open or C89 + // with a new version. + if (Opts.C99) + Builder.defineMacro("_XOPEN_SOURCE", "600"); + else + Builder.defineMacro("_XOPEN_SOURCE", "500"); + if (Opts.CPlusPlus) + Builder.defineMacro("__C99FEATURES__"); + Builder.defineMacro("_LARGEFILE_SOURCE"); + Builder.defineMacro("_LARGEFILE64_SOURCE"); + Builder.defineMacro("__EXTENSIONS__"); + Builder.defineMacro("_REENTRANT"); + } + +public: + SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + // FIXME: WIntType should be SignedLong + } +}; + +// Windows target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY WindowsTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("_WIN32"); + if (Triple.isArch64Bit()) + Builder.defineMacro("_WIN64"); + if (Triple.isWindowsGNUEnvironment()) + addMinGWDefines(Triple, Opts, Builder); + + } + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (Opts.CPlusPlus) { + if (Opts.RTTIData) + Builder.defineMacro("_CPPRTTI"); + + if (Opts.CXXExceptions) + Builder.defineMacro("_CPPUNWIND"); + } + + if (Opts.Bool) + Builder.defineMacro("__BOOL_DEFINED"); + + if (!Opts.CharIsSigned) + Builder.defineMacro("_CHAR_UNSIGNED"); + + // FIXME: POSIXThreads isn't exactly the option this should be defined for, + // but it works for now. + if (Opts.POSIXThreads) + Builder.defineMacro("_MT"); + + if (Opts.MSCompatibilityVersion) { + Builder.defineMacro("_MSC_VER", + Twine(Opts.MSCompatibilityVersion / 100000)); + Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); + // FIXME We cannot encode the revision information into 32-bits + Builder.defineMacro("_MSC_BUILD", Twine(1)); + + if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); + + if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { + if (Opts.CPlusPlus17) + Builder.defineMacro("_MSVC_LANG", "201403L"); + else if (Opts.CPlusPlus14) + Builder.defineMacro("_MSVC_LANG", "201402L"); + } + } + + if (Opts.MicrosoftExt) { + Builder.defineMacro("_MSC_EXTENSIONS"); + + if (Opts.CPlusPlus11) { + Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED"); + Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED"); + Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED"); + } + } + + Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); + } + +public: + WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + } +}; + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY NaClTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__native_client__"); + } + +public: + NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->LongLongWidth = 64; + this->LongLongAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + // RegParmMax is inherited from the underlying architecture. + this->LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + if (Triple.getArch() == llvm::Triple::arm) { + // Handled in ARM's setABI(). + } else if (Triple.getArch() == llvm::Triple::x86) { + this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128"); + } else if (Triple.getArch() == llvm::Triple::x86_64) { + this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128"); + } else if (Triple.getArch() == llvm::Triple::mipsel) { + // Handled on mips' setDataLayout. + } else { + assert(Triple.getArch() == llvm::Triple::le32); + this->resetDataLayout("e-p:32:32-i64:64"); + } + } +}; + +// Fuchsia Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY FuchsiaTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__Fuchsia__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Required by the libc++ locale support. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + } +}; + +// WebAssembly target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo + : public OSTargetInfo<Target> { + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const final { + // A common platform macro. + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Follow g++ convention and predefine _GNU_SOURCE for C++. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + this->TheCXXABI.set(TargetCXXABI::WebAssembly); + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.cpp new file mode 100644 index 0000000000000..b9128c2716e87 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.cpp @@ -0,0 +1,30 @@ +//===--- PNaCl.cpp - Implement PNaCl target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements PNaCl TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "PNaCl.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { return None; } + +ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const { + return None; +} + +void PNaClTargetInfo::getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__le32__"); + Builder.defineMacro("__pnacl__"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.h b/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.h new file mode 100644 index 0000000000000..922944e85ca29 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/PNaCl.h @@ -0,0 +1,87 @@ +//===--- PNaCl.h - Declare PNaCl target feature support ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares PNaCl TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H + +#include "Mips.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY PNaClTargetInfo : public TargetInfo { +public: + PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TargetInfo(Triple) { + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + this->RegParmMax = 0; // Disallow regparm + } + + void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const; + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + getArchDefines(Opts, Builder); + } + + bool hasFeature(StringRef Feature) const override { + return Feature == "pnacl"; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + const char *getClobbers() const override { return ""; } +}; + +// We attempt to use PNaCl (le32) frontend and Mips32EL backend. +class LLVM_LIBRARY_VISIBILITY NaClMips32TargetInfo : public MipsTargetInfo { +public: + NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : MipsTargetInfo(Triple, Opts) {} + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.cpp new file mode 100644 index 0000000000000..a44aa0cd96f06 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.cpp @@ -0,0 +1,544 @@ +//===--- PPC.cpp - Implement PPC target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements PPC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "PPC.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsPPC.def" +}; + +/// handleTargetFeatures - Perform initialization based on the user +/// configured set of features. +bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+altivec") { + HasAltivec = true; + } else if (Feature == "+vsx") { + HasVSX = true; + } else if (Feature == "+bpermd") { + HasBPERMD = true; + } else if (Feature == "+extdiv") { + HasExtDiv = true; + } else if (Feature == "+power8-vector") { + HasP8Vector = true; + } else if (Feature == "+crypto") { + HasP8Crypto = true; + } else if (Feature == "+direct-move") { + HasDirectMove = true; + } else if (Feature == "+qpx") { + HasQPX = true; + } else if (Feature == "+htm") { + HasHTM = true; + } else if (Feature == "+float128") { + HasFloat128 = true; + } else if (Feature == "+power9-vector") { + HasP9Vector = true; + } + // TODO: Finish this list and add an assert that we've handled them + // all. + } + + return true; +} + +/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific +/// #defines that are not tied to a specific subtarget. +void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__ppc__"); + Builder.defineMacro("__PPC__"); + Builder.defineMacro("_ARCH_PPC"); + Builder.defineMacro("__powerpc__"); + Builder.defineMacro("__POWERPC__"); + if (PointerWidth == 64) { + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("__powerpc64__"); + Builder.defineMacro("__ppc64__"); + Builder.defineMacro("__PPC64__"); + } + + // Target properties. + if (getTriple().getArch() == llvm::Triple::ppc64le) { + Builder.defineMacro("_LITTLE_ENDIAN"); + } else { + if (getTriple().getOS() != llvm::Triple::NetBSD && + getTriple().getOS() != llvm::Triple::OpenBSD) + Builder.defineMacro("_BIG_ENDIAN"); + } + + // ABI options. + if (ABI == "elfv1" || ABI == "elfv1-qpx") + Builder.defineMacro("_CALL_ELF", "1"); + if (ABI == "elfv2") + Builder.defineMacro("_CALL_ELF", "2"); + + // This typically is only for a new enough linker (bfd >= 2.16.2 or gold), but + // our suppport post-dates this and it should work on all 64-bit ppc linux + // platforms. It is guaranteed to work on all elfv2 platforms. + if (getTriple().getOS() == llvm::Triple::Linux && PointerWidth == 64) + Builder.defineMacro("_CALL_LINUX", "1"); + + // Subtarget options. + Builder.defineMacro("__NATURAL_ALIGNMENT__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // FIXME: Should be controlled by command line option. + if (LongDoubleWidth == 128) { + Builder.defineMacro("__LONG_DOUBLE_128__"); + Builder.defineMacro("__LONGDOUBLE128"); + } + + // Define this for elfv2 (64-bit only) or 64-bit darwin. + if (ABI == "elfv2" || + (getTriple().getOS() == llvm::Triple::Darwin && PointerWidth == 64)) + Builder.defineMacro("__STRUCT_PARM_ALIGN__", "16"); + + // CPU identification. + ArchDefineTypes defs = + (ArchDefineTypes)llvm::StringSwitch<int>(CPU) + .Case("440", ArchDefineName) + .Case("450", ArchDefineName | ArchDefine440) + .Case("601", ArchDefineName) + .Case("602", ArchDefineName | ArchDefinePpcgr) + .Case("603", ArchDefineName | ArchDefinePpcgr) + .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) + .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) + .Case("604", ArchDefineName | ArchDefinePpcgr) + .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) + .Case("620", ArchDefineName | ArchDefinePpcgr) + .Case("630", ArchDefineName | ArchDefinePpcgr) + .Case("7400", ArchDefineName | ArchDefinePpcgr) + .Case("7450", ArchDefineName | ArchDefinePpcgr) + .Case("750", ArchDefineName | ArchDefinePpcgr) + .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("a2", ArchDefineA2) + .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) + .Case("pwr3", ArchDefinePpcgr) + .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 | + ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x | + ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr9", ArchDefineName | ArchDefinePwr8 | ArchDefinePwr7 | + ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("power3", ArchDefinePpcgr) + .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | + ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | + ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power9", ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | + ArchDefinePwr6x | ArchDefinePwr6 | + ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + // powerpc64le automatically defaults to at least power8. + .Case("ppc64le", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | + ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Default(ArchDefineNone); + + if (defs & ArchDefineName) + Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); + if (defs & ArchDefinePpcgr) + Builder.defineMacro("_ARCH_PPCGR"); + if (defs & ArchDefinePpcsq) + Builder.defineMacro("_ARCH_PPCSQ"); + if (defs & ArchDefine440) + Builder.defineMacro("_ARCH_440"); + if (defs & ArchDefine603) + Builder.defineMacro("_ARCH_603"); + if (defs & ArchDefine604) + Builder.defineMacro("_ARCH_604"); + if (defs & ArchDefinePwr4) + Builder.defineMacro("_ARCH_PWR4"); + if (defs & ArchDefinePwr5) + Builder.defineMacro("_ARCH_PWR5"); + if (defs & ArchDefinePwr5x) + Builder.defineMacro("_ARCH_PWR5X"); + if (defs & ArchDefinePwr6) + Builder.defineMacro("_ARCH_PWR6"); + if (defs & ArchDefinePwr6x) + Builder.defineMacro("_ARCH_PWR6X"); + if (defs & ArchDefinePwr7) + Builder.defineMacro("_ARCH_PWR7"); + if (defs & ArchDefinePwr8) + Builder.defineMacro("_ARCH_PWR8"); + if (defs & ArchDefinePwr9) + Builder.defineMacro("_ARCH_PWR9"); + if (defs & ArchDefineA2) + Builder.defineMacro("_ARCH_A2"); + if (defs & ArchDefineA2q) { + Builder.defineMacro("_ARCH_A2Q"); + Builder.defineMacro("_ARCH_QP"); + } + + if (getTriple().getVendor() == llvm::Triple::BGQ) { + Builder.defineMacro("__bg__"); + Builder.defineMacro("__THW_BLUEGENE__"); + Builder.defineMacro("__bgq__"); + Builder.defineMacro("__TOS_BGQ__"); + } + + if (HasAltivec) { + Builder.defineMacro("__VEC__", "10206"); + Builder.defineMacro("__ALTIVEC__"); + } + if (HasVSX) + Builder.defineMacro("__VSX__"); + if (HasP8Vector) + Builder.defineMacro("__POWER8_VECTOR__"); + if (HasP8Crypto) + Builder.defineMacro("__CRYPTO__"); + if (HasHTM) + Builder.defineMacro("__HTM__"); + if (HasFloat128) + Builder.defineMacro("__FLOAT128__"); + if (HasP9Vector) + Builder.defineMacro("__POWER9_VECTOR__"); + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + if (PointerWidth == 64) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + // We have support for the bswap intrinsics so we can define this. + Builder.defineMacro("__HAVE_BSWAP__", "1"); + + // FIXME: The following are not yet generated here by Clang, but are + // generated by GCC: + // + // _SOFT_FLOAT_ + // __RECIP_PRECISION__ + // __APPLE_ALTIVEC__ + // __RECIP__ + // __RECIPF__ + // __RSQRTE__ + // __RSQRTEF__ + // _SOFT_DOUBLE_ + // __NO_LWSYNC__ + // __CMODEL_MEDIUM__ + // __CMODEL_LARGE__ + // _CALL_SYSV + // _CALL_DARWIN + // __NO_FPRS__ +} + +// Handle explicit options being passed to the compiler here: if we've +// explicitly turned off vsx and turned on any of: +// - power8-vector +// - direct-move +// - float128 +// - power9-vector +// then go ahead and error since the customer has expressed an incompatible +// set of options. +static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, + const std::vector<std::string> &FeaturesVec) { + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") != + FeaturesVec.end()) { + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" + << "-mno-vsx"; + return false; + } + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" + << "-mno-vsx"; + return false; + } + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" + << "-mno-vsx"; + return false; + } + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power9-vector") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector" + << "-mno-vsx"; + return false; + } + } + + return true; +} + +bool PPCTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + Features["altivec"] = llvm::StringSwitch<bool>(CPU) + .Case("7400", true) + .Case("g4", true) + .Case("7450", true) + .Case("g4+", true) + .Case("970", true) + .Case("g5", true) + .Case("pwr6", true) + .Case("pwr7", true) + .Case("pwr8", true) + .Case("pwr9", true) + .Case("ppc64", true) + .Case("ppc64le", true) + .Default(false); + + Features["qpx"] = (CPU == "a2q"); + Features["power9-vector"] = (CPU == "pwr9"); + Features["crypto"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["power8-vector"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["bpermd"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["extdiv"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["direct-move"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["vsx"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["htm"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + + if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) + return false; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +bool PPCTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("powerpc", true) + .Case("altivec", HasAltivec) + .Case("vsx", HasVSX) + .Case("power8-vector", HasP8Vector) + .Case("crypto", HasP8Crypto) + .Case("direct-move", HasDirectMove) + .Case("qpx", HasQPX) + .Case("htm", HasHTM) + .Case("bpermd", HasBPERMD) + .Case("extdiv", HasExtDiv) + .Case("float128", HasFloat128) + .Case("power9-vector", HasP9Vector) + .Default(false); +} + +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + if (Enabled) { + // If we're enabling any of the vsx based features then enable vsx and + // altivec. We'll diagnose any problems later. + bool FeatureHasVSX = llvm::StringSwitch<bool>(Name) + .Case("vsx", true) + .Case("direct-move", true) + .Case("power8-vector", true) + .Case("power9-vector", true) + .Case("float128", true) + .Default(false); + if (FeatureHasVSX) + Features["vsx"] = Features["altivec"] = true; + if (Name == "power9-vector") + Features["power8-vector"] = true; + Features[Name] = true; + } else { + // If we're disabling altivec or vsx go ahead and disable all of the vsx + // features. + if ((Name == "altivec") || (Name == "vsx")) + Features["vsx"] = Features["direct-move"] = Features["power8-vector"] = + Features["float128"] = Features["power9-vector"] = false; + if (Name == "power8-vector") + Features["power9-vector"] = false; + Features[Name] = false; + } +} + +const char *const PPCTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", + "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", + "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3", + "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", + "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", + "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", + "f31", "mq", "lr", "ctr", "ap", "cr0", "cr1", "cr2", "cr3", + "cr4", "cr5", "cr6", "cr7", "xer", "v0", "v1", "v2", "v3", + "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", + "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", + "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", + "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp" +}; + +ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { + // While some of these aliases do map to different registers + // they still share the same register name. + {{"0"}, "r0"}, {{"1"}, "r1"}, {{"2"}, "r2"}, {{"3"}, "r3"}, + {{"4"}, "r4"}, {{"5"}, "r5"}, {{"6"}, "r6"}, {{"7"}, "r7"}, + {{"8"}, "r8"}, {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"}, + {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, {{"15"}, "r15"}, + {{"16"}, "r16"}, {{"17"}, "r17"}, {{"18"}, "r18"}, {{"19"}, "r19"}, + {{"20"}, "r20"}, {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"}, + {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, {{"27"}, "r27"}, + {{"28"}, "r28"}, {{"29"}, "r29"}, {{"30"}, "r30"}, {{"31"}, "r31"}, + {{"fr0"}, "f0"}, {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"}, + {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, {{"fr7"}, "f7"}, + {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, {{"fr10"}, "f10"}, {{"fr11"}, "f11"}, + {{"fr12"}, "f12"}, {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"}, + {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, {{"fr19"}, "f19"}, + {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, {{"fr22"}, "f22"}, {{"fr23"}, "f23"}, + {{"fr24"}, "f24"}, {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"}, + {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, {{"fr31"}, "f31"}, + {{"cc"}, "cr0"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool PPCTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) + .Case("generic", true) + .Case("440", true) + .Case("450", true) + .Case("601", true) + .Case("602", true) + .Case("603", true) + .Case("603e", true) + .Case("603ev", true) + .Case("604", true) + .Case("604e", true) + .Case("620", true) + .Case("630", true) + .Case("g3", true) + .Case("7400", true) + .Case("g4", true) + .Case("7450", true) + .Case("g4+", true) + .Case("750", true) + .Case("970", true) + .Case("g5", true) + .Case("a2", true) + .Case("a2q", true) + .Case("e500mc", true) + .Case("e5500", true) + .Case("power3", true) + .Case("pwr3", true) + .Case("power4", true) + .Case("pwr4", true) + .Case("power5", true) + .Case("pwr5", true) + .Case("power5x", true) + .Case("pwr5x", true) + .Case("power6", true) + .Case("pwr6", true) + .Case("power6x", true) + .Case("pwr6x", true) + .Case("power7", true) + .Case("pwr7", true) + .Case("power8", true) + .Case("pwr8", true) + .Case("power9", true) + .Case("pwr9", true) + .Case("powerpc", true) + .Case("ppc", true) + .Case("powerpc64", true) + .Case("ppc64", true) + .Case("powerpc64le", true) + .Case("ppc64le", true) + .Default(false); +} + +void PPCTargetInfo::adjust(LangOptions &Opts) { + if (HasAltivec) + Opts.AltiVec = 1; + TargetInfo::adjust(Opts); +} + +ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.h b/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.h new file mode 100644 index 0000000000000..04bef258e3865 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/PPC.h @@ -0,0 +1,368 @@ +//===--- PPC.h - Declare PPC target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares PPC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// PPC abstract base class +class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; + + // Target cpu features. + bool HasAltivec; + bool HasVSX; + bool HasP8Vector; + bool HasP8Crypto; + bool HasDirectMove; + bool HasQPX; + bool HasHTM; + bool HasBPERMD; + bool HasExtDiv; + bool HasP9Vector; + +protected: + std::string ABI; + +public: + PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), HasAltivec(false), HasVSX(false), + HasP8Vector(false), HasP8Crypto(false), HasDirectMove(false), + HasQPX(false), HasHTM(false), HasBPERMD(false), HasExtDiv(false), + HasP9Vector(false) { + SuitableAlign = 128; + SimdDefaultAlign = 128; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); + } + + /// \brief Flags for architecture specific defines. + typedef enum { + ArchDefineNone = 0, + ArchDefineName = 1 << 0, // <name> is substituted for arch name. + ArchDefinePpcgr = 1 << 1, + ArchDefinePpcsq = 1 << 2, + ArchDefine440 = 1 << 3, + ArchDefine603 = 1 << 4, + ArchDefine604 = 1 << 5, + ArchDefinePwr4 = 1 << 6, + ArchDefinePwr5 = 1 << 7, + ArchDefinePwr5x = 1 << 8, + ArchDefinePwr6 = 1 << 9, + ArchDefinePwr6x = 1 << 10, + ArchDefinePwr7 = 1 << 11, + ArchDefinePwr8 = 1 << 12, + ArchDefinePwr9 = 1 << 13, + ArchDefineA2 = 1 << 14, + ArchDefineA2q = 1 << 15 + } ArchDefineTypes; + + // Set the language option for altivec based on our value. + void adjust(LangOptions &Opts) override; + + // Note: GCC recognizes the following additional cpus: + // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, + // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, + // titan, rs64. + bool isValidCPUName(StringRef Name) const override; + + bool setCPU(const std::string &Name) override { + bool CPUKnown = isValidCPUName(Name); + if (CPUKnown) + CPU = Name; + return CPUKnown; + } + + StringRef getABI() const override { return ABI; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool isCLZForZeroUndef() const override { return false; } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + bool hasFeature(StringRef Feature) const override; + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'O': // Zero + break; + case 'b': // Base register + case 'f': // Floating point register + Info.setAllowsRegister(); + break; + // FIXME: The following are added to allow parsing. + // I just took a guess at what the actions should be. + // Also, is more specific checking needed? I.e. specific registers? + case 'd': // Floating point register (containing 64-bit value) + case 'v': // Altivec vector register + Info.setAllowsRegister(); + break; + case 'w': + switch (Name[1]) { + case 'd': // VSX vector register to hold vector double data + case 'f': // VSX vector register to hold vector float data + case 's': // VSX vector register to hold scalar float data + case 'a': // Any VSX register + case 'c': // An individual CR bit + break; + default: + return false; + } + Info.setAllowsRegister(); + Name++; // Skip over 'w'. + break; + case 'h': // `MQ', `CTR', or `LINK' register + case 'q': // `MQ' register + case 'c': // `CTR' register + case 'l': // `LINK' register + case 'x': // `CR' register (condition register) number 0 + case 'y': // `CR' register (condition register) + case 'z': // `XER[CA]' carry bit (part of the XER register) + Info.setAllowsRegister(); + break; + case 'I': // Signed 16-bit constant + case 'J': // Unsigned 16-bit constant shifted left 16 bits + // (use `L' instead for SImode constants) + case 'K': // Unsigned 16-bit constant + case 'L': // Signed 16-bit constant shifted left 16 bits + case 'M': // Constant larger than 31 + case 'N': // Exact power of 2 + case 'P': // Constant whose negation is a signed 16-bit constant + case 'G': // Floating point constant that can be loaded into a + // register with one instruction per word + case 'H': // Integer/Floating point constant that can be loaded + // into a register using three instructions + break; + case 'm': // Memory operand. Note that on PowerPC targets, m can + // include addresses that update the base register. It + // is therefore only safe to use `m' in an asm statement + // if that asm statement accesses the operand exactly once. + // The asm statement must also use `%U<opno>' as a + // placeholder for the "update" flag in the corresponding + // load or store instruction. For example: + // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); + // is correct but: + // asm ("st %1,%0" : "=m" (mem) : "r" (val)); + // is not. Use es rather than m if you don't want the base + // register to be updated. + case 'e': + if (Name[1] != 's') + return false; + // es: A "stable" memory operand; that is, one which does not + // include any automodification of the base register. Unlike + // `m', this constraint can be used in asm statements that + // might access the operand several times, or that might not + // access it at all. + Info.setAllowsMemory(); + Name++; // Skip over 'e'. + break; + case 'Q': // Memory operand that is an offset from a register (it is + // usually better to use `m' or `es' in asm statements) + case 'Z': // Memory operand that is an indexed or indirect from a + // register (it is usually better to use `m' or `es' in + // asm statements) + Info.setAllowsMemory(); + Info.setAllowsRegister(); + break; + case 'R': // AIX TOC entry + case 'a': // Address operand that is an indexed or indirect from a + // register (`p' is preferable for asm statements) + case 'S': // Constant suitable as a 64-bit mask operand + case 'T': // Constant suitable as a 32-bit mask operand + case 'U': // System V Release 4 small data area reference + case 't': // AND masks that can be performed by two rldic{l, r} + // instructions + case 'W': // Vector constant that does not require memory + case 'j': // Vector constant that is all zeros. + break; + // End FIXME. + } + return true; + } + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'e': + case 'w': + // Two-character constraint; add "^" hint for later parsing. + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + break; + default: + return TargetInfo::convertConstraint(Constraint); + } + return R; + } + + const char *getClobbers() const override { return ""; } + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 3; + if (RegNo == 1) + return 4; + return -1; + } + + bool hasSjLjLowering() const override { return true; } + + bool useFloat128ManglingForLongDouble() const override { + return LongDoubleWidth == 128 && + LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() && + getTriple().isOSBinFormatELF(); + } +}; + +class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo { +public: + PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : PPCTargetInfo(Triple, Opts) { + resetDataLayout("E-m:e-p:32:32-i64:64-n32"); + + switch (getTriple().getOS()) { + case llvm::Triple::Linux: + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + break; + default: + break; + } + + if (getTriple().getOS() == llvm::Triple::FreeBSD) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + // PPC32 supports atomics up to 4 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // This is the ELF definition, and is overridden by the Darwin sub-target + return TargetInfo::PowerABIBuiltinVaList; + } +}; + +// Note: ABI differences may eventually require us to have a separate +// TargetInfo for little endian. +class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { +public: + PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : PPCTargetInfo(Triple, Opts) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + Int64Type = SignedLong; + + if ((Triple.getArch() == llvm::Triple::ppc64le)) { + resetDataLayout("e-m:e-i64:64-n32:64"); + ABI = "elfv2"; + } else { + resetDataLayout("E-m:e-i64:64-n32:64"); + ABI = "elfv1"; + } + + switch (getTriple().getOS()) { + case llvm::Triple::FreeBSD: + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + break; + case llvm::Triple::NetBSD: + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + break; + default: + break; + } + + // PPC64 supports atomics up to 8 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + // PPC64 Linux-specific ABI options. + bool setABI(const std::string &Name) override { + if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { + ABI = Name; + return true; + } + return false; + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC32TargetInfo + : public DarwinTargetInfo<PPC32TargetInfo> { +public: + DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + BoolWidth = BoolAlign = 32; // XXX support -mone-byte-bool? + PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 + LongLongAlign = 32; + resetDataLayout("E-m:o-p:32:32-f64:32:64-n32"); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC64TargetInfo + : public DarwinTargetInfo<PPC64TargetInfo> { +public: + DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + resetDataLayout("E-m:o-i64:64-n32:64"); + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.cpp new file mode 100644 index 0000000000000..304d904368ca6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.cpp @@ -0,0 +1,33 @@ +//===--- SPIR.cpp - Implement SPIR target feature support -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements SPIR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "SPIR.h" +#include "Targets.h" + +using namespace clang; +using namespace clang::targets; + +void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIR", Opts); +} + +void SPIR32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIR32", Opts); +} + +void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIR64", Opts); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.h b/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.h new file mode 100644 index 0000000000000..c384d4260ca9e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/SPIR.h @@ -0,0 +1,127 @@ +//===--- SPIR.h - Declare SPIR target feature support -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares SPIR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +static const unsigned SPIRAddrSpaceMap[] = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared +}; + +class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { +public: + SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR target must use unknown environment type"); + TLSSupported = false; + VLASupported = false; + LongWidth = LongAlign = 64; + AddrSpaceMap = &SPIRAddrSpaceMap; + UseAddrSpaceMapMangling = true; + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spir"; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK + : CCCR_Warning; + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return CC_SpirFunction; + } + + void setSupportedOpenCLOpts() override { + // Assume all OpenCL extensions and optional core features are supported + // for SPIR since it is a generic target. + getSupportedOpenCLOpts().supportAll(); + } +}; +class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { +public: + SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRTargetInfo(Triple, Opts) { + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo { +public: + SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRTargetInfo(Triple, Opts) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.cpp new file mode 100644 index 0000000000000..429c1ee3a23c5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.cpp @@ -0,0 +1,197 @@ +//===--- Sparc.cpp - Implement Sparc target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Sparc TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Sparc.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const char *const SparcTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", + "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { + {{"g0"}, "r0"}, {{"g1"}, "r1"}, {{"g2"}, "r2"}, {{"g3"}, "r3"}, + {{"g4"}, "r4"}, {{"g5"}, "r5"}, {{"g6"}, "r6"}, {{"g7"}, "r7"}, + {{"o0"}, "r8"}, {{"o1"}, "r9"}, {{"o2"}, "r10"}, {{"o3"}, "r11"}, + {{"o4"}, "r12"}, {{"o5"}, "r13"}, {{"o6", "sp"}, "r14"}, {{"o7"}, "r15"}, + {{"l0"}, "r16"}, {{"l1"}, "r17"}, {{"l2"}, "r18"}, {{"l3"}, "r19"}, + {{"l4"}, "r20"}, {{"l5"}, "r21"}, {{"l6"}, "r22"}, {{"l7"}, "r23"}, + {{"i0"}, "r24"}, {{"i1"}, "r25"}, {{"i2"}, "r26"}, {{"i3"}, "r27"}, + {{"i4"}, "r28"}, {{"i5"}, "r29"}, {{"i6", "fp"}, "r30"}, {{"i7"}, "r31"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool SparcTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("softfloat", SoftFloat) + .Case("sparc", true) + .Default(false); +} + +SparcTargetInfo::CPUKind SparcTargetInfo::getCPUKind(StringRef Name) const { + return llvm::StringSwitch<CPUKind>(Name) + .Case("v8", CK_V8) + .Case("supersparc", CK_SUPERSPARC) + .Case("sparclite", CK_SPARCLITE) + .Case("f934", CK_F934) + .Case("hypersparc", CK_HYPERSPARC) + .Case("sparclite86x", CK_SPARCLITE86X) + .Case("sparclet", CK_SPARCLET) + .Case("tsc701", CK_TSC701) + .Case("v9", CK_V9) + .Case("ultrasparc", CK_ULTRASPARC) + .Case("ultrasparc3", CK_ULTRASPARC3) + .Case("niagara", CK_NIAGARA) + .Case("niagara2", CK_NIAGARA2) + .Case("niagara3", CK_NIAGARA3) + .Case("niagara4", CK_NIAGARA4) + .Case("ma2100", CK_MYRIAD2100) + .Case("ma2150", CK_MYRIAD2150) + .Case("ma2155", CK_MYRIAD2155) + .Case("ma2450", CK_MYRIAD2450) + .Case("ma2455", CK_MYRIAD2455) + .Case("ma2x5x", CK_MYRIAD2x5x) + .Case("ma2080", CK_MYRIAD2080) + .Case("ma2085", CK_MYRIAD2085) + .Case("ma2480", CK_MYRIAD2480) + .Case("ma2485", CK_MYRIAD2485) + .Case("ma2x8x", CK_MYRIAD2x8x) + // FIXME: the myriad2[.n] spellings are obsolete, + // but a grace period is needed to allow updating dependent builds. + .Case("myriad2", CK_MYRIAD2x5x) + .Case("myriad2.1", CK_MYRIAD2100) + .Case("myriad2.2", CK_MYRIAD2x5x) + .Case("myriad2.3", CK_MYRIAD2x8x) + .Case("leon2", CK_LEON2) + .Case("at697e", CK_LEON2_AT697E) + .Case("at697f", CK_LEON2_AT697F) + .Case("leon3", CK_LEON3) + .Case("ut699", CK_LEON3_UT699) + .Case("gr712rc", CK_LEON3_GR712RC) + .Case("leon4", CK_LEON4) + .Case("gr740", CK_LEON4_GR740) + .Default(CK_GENERIC); +} + +void SparcTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "sparc", Opts); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + if (SoftFloat) + Builder.defineMacro("SOFT_FLOAT", "1"); +} + +void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + switch (getCPUGeneration(CPU)) { + case CG_V8: + Builder.defineMacro("__sparcv8"); + if (getTriple().getOS() != llvm::Triple::Solaris) + Builder.defineMacro("__sparcv8__"); + break; + case CG_V9: + Builder.defineMacro("__sparcv9"); + if (getTriple().getOS() != llvm::Triple::Solaris) { + Builder.defineMacro("__sparcv9__"); + Builder.defineMacro("__sparc_v9__"); + } + break; + } + if (getTriple().getVendor() == llvm::Triple::Myriad) { + std::string MyriadArchValue, Myriad2Value; + Builder.defineMacro("__sparc_v8__"); + Builder.defineMacro("__leon__"); + switch (CPU) { + case CK_MYRIAD2100: + MyriadArchValue = "__ma2100"; + Myriad2Value = "1"; + break; + case CK_MYRIAD2150: + MyriadArchValue = "__ma2150"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2155: + MyriadArchValue = "__ma2155"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2450: + MyriadArchValue = "__ma2450"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2455: + MyriadArchValue = "__ma2455"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2x5x: + Myriad2Value = "2"; + break; + case CK_MYRIAD2080: + MyriadArchValue = "__ma2080"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2085: + MyriadArchValue = "__ma2085"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2480: + MyriadArchValue = "__ma2480"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2485: + MyriadArchValue = "__ma2485"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2x8x: + Myriad2Value = "3"; + break; + default: + MyriadArchValue = "__ma2100"; + Myriad2Value = "1"; + break; + } + if (!MyriadArchValue.empty()) { + Builder.defineMacro(MyriadArchValue, "1"); + Builder.defineMacro(MyriadArchValue + "__", "1"); + } + Builder.defineMacro("__myriad2__", Myriad2Value); + Builder.defineMacro("__myriad2", Myriad2Value); + } +} + +void SparcV9TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv9"); + Builder.defineMacro("__arch64__"); + // Solaris doesn't need these variants, but the BSDs do. + if (getTriple().getOS() != llvm::Triple::Solaris) { + Builder.defineMacro("__sparc64__"); + Builder.defineMacro("__sparc_v9__"); + Builder.defineMacro("__sparcv9__"); + } +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.h b/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.h new file mode 100644 index 0000000000000..aacc26119dfbd --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/Sparc.h @@ -0,0 +1,270 @@ +//===--- Sparc.h - Declare Sparc target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Sparc TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +namespace clang { +namespace targets { +// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). +class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + bool SoftFloat; + +public: + SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), SoftFloat(false) {} + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 24; + if (RegNo == 1) + return 25; + return -1; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + // Check if software floating point is enabled + auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); + if (Feature != Features.end()) { + SoftFloat = true; + } + return true; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override; + + bool hasSjLjLowering() const override { return true; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + // FIXME: Implement! + return None; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + // FIXME: Implement! + switch (*Name) { + case 'I': // Signed 13-bit constant + case 'J': // Zero + case 'K': // 32-bit constant with the low 12 bits clear + case 'L': // A constant in the range supported by movcc (11-bit signed imm) + case 'M': // A constant in the range supported by movrcc (19-bit signed imm) + case 'N': // Same as 'K' but zext (required for SIMode) + case 'O': // The constant 4096 + return true; + + case 'f': + case 'e': + info.setAllowsRegister(); + return true; + } + return false; + } + const char *getClobbers() const override { + // FIXME: Implement! + return ""; + } + + // No Sparc V7 for now, the backend doesn't support it anyway. + enum CPUKind { + CK_GENERIC, + CK_V8, + CK_SUPERSPARC, + CK_SPARCLITE, + CK_F934, + CK_HYPERSPARC, + CK_SPARCLITE86X, + CK_SPARCLET, + CK_TSC701, + CK_V9, + CK_ULTRASPARC, + CK_ULTRASPARC3, + CK_NIAGARA, + CK_NIAGARA2, + CK_NIAGARA3, + CK_NIAGARA4, + CK_MYRIAD2100, + CK_MYRIAD2150, + CK_MYRIAD2155, + CK_MYRIAD2450, + CK_MYRIAD2455, + CK_MYRIAD2x5x, + CK_MYRIAD2080, + CK_MYRIAD2085, + CK_MYRIAD2480, + CK_MYRIAD2485, + CK_MYRIAD2x8x, + CK_LEON2, + CK_LEON2_AT697E, + CK_LEON2_AT697F, + CK_LEON3, + CK_LEON3_UT699, + CK_LEON3_GR712RC, + CK_LEON4, + CK_LEON4_GR740 + } CPU = CK_GENERIC; + + enum CPUGeneration { + CG_V8, + CG_V9, + }; + + CPUGeneration getCPUGeneration(CPUKind Kind) const { + switch (Kind) { + case CK_GENERIC: + case CK_V8: + case CK_SUPERSPARC: + case CK_SPARCLITE: + case CK_F934: + case CK_HYPERSPARC: + case CK_SPARCLITE86X: + case CK_SPARCLET: + case CK_TSC701: + case CK_MYRIAD2100: + case CK_MYRIAD2150: + case CK_MYRIAD2155: + case CK_MYRIAD2450: + case CK_MYRIAD2455: + case CK_MYRIAD2x5x: + case CK_MYRIAD2080: + case CK_MYRIAD2085: + case CK_MYRIAD2480: + case CK_MYRIAD2485: + case CK_MYRIAD2x8x: + case CK_LEON2: + case CK_LEON2_AT697E: + case CK_LEON2_AT697F: + case CK_LEON3: + case CK_LEON3_UT699: + case CK_LEON3_GR712RC: + case CK_LEON4: + case CK_LEON4_GR740: + return CG_V8; + case CK_V9: + case CK_ULTRASPARC: + case CK_ULTRASPARC3: + case CK_NIAGARA: + case CK_NIAGARA2: + case CK_NIAGARA3: + case CK_NIAGARA4: + return CG_V9; + } + llvm_unreachable("Unexpected CPU kind"); + } + + CPUKind getCPUKind(StringRef Name) const; + + bool isValidCPUName(StringRef Name) const override { + return getCPUKind(Name) != CK_GENERIC; + } + + bool setCPU(const std::string &Name) override { + CPU = getCPUKind(Name); + return CPU != CK_GENERIC; + } +}; + +// SPARC v8 is the 32-bit mode selected by Triple::sparc. +class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo { +public: + SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcTargetInfo(Triple, Opts) { + resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); + // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. + switch (getTriple().getOS()) { + default: + SizeType = UnsignedInt; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + break; + case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + break; + } + // Up to 32 bits are lock-free atomic, but we're willing to do atomic ops + // on up to 64 bits. + MaxAtomicPromoteWidth = 64; + MaxAtomicInlineWidth = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasSjLjLowering() const override { return true; } +}; + +// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. +class LLVM_LIBRARY_VISIBILITY SparcV8elTargetInfo : public SparcV8TargetInfo { +public: + SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcV8TargetInfo(Triple, Opts) { + resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64"); + } +}; + +// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. +class LLVM_LIBRARY_VISIBILITY SparcV9TargetInfo : public SparcTargetInfo { +public: + SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcTargetInfo(Triple, Opts) { + // FIXME: Support Sparc quad-precision long double? + resetDataLayout("E-m:e-i64:64-n32:64-S128"); + // This is an LP64 platform. + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + + // OpenBSD uses long long for int64_t and intmax_t. + if (getTriple().getOS() == llvm::Triple::OpenBSD) + IntMaxType = SignedLongLong; + else + IntMaxType = SignedLong; + Int64Type = IntMaxType; + + // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit + // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isValidCPUName(StringRef Name) const override { + return getCPUGeneration(SparcTargetInfo::getCPUKind(Name)) == CG_V9; + } + + bool setCPU(const std::string &Name) override { + if (!SparcTargetInfo::setCPU(Name)) + return false; + return getCPUGeneration(CPU) == CG_V9; + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.cpp new file mode 100644 index 0000000000000..98f3ae2f72b47 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.cpp @@ -0,0 +1,118 @@ +//===--- SystemZ.cpp - Implement SystemZ target feature support -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements SystemZ TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsSystemZ.def" +}; + +const char *const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "f0", "f2", "f4", "f6", "f1", "f3", + "f5", "f7", "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" +}; + +ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +bool SystemZTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + Info.setAllowsRegister(); + return true; + + case 'I': // Unsigned 8-bit constant + case 'J': // Unsigned 12-bit constant + case 'K': // Signed 16-bit constant + case 'L': // Signed 20-bit displacement (on all targets we support) + case 'M': // 0x7fffffff + return true; + + case 'Q': // Memory with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Memory with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + Info.setAllowsMemory(); + return true; + } +} + +int SystemZTargetInfo::getISARevision(const StringRef &Name) const { + return llvm::StringSwitch<int>(Name) + .Cases("arch8", "z10", 8) + .Cases("arch9", "z196", 9) + .Cases("arch10", "zEC12", 10) + .Cases("arch11", "z13", 11) + .Cases("arch12", "z14", 12) + .Default(-1); +} + +bool SystemZTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("systemz", true) + .Case("arch8", ISARevision >= 8) + .Case("arch9", ISARevision >= 9) + .Case("arch10", ISARevision >= 10) + .Case("arch11", ISARevision >= 11) + .Case("arch12", ISARevision >= 12) + .Case("htm", HasTransactionalExecution) + .Case("vx", HasVector) + .Default(false); +} + +void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + Builder.defineMacro("__zarch__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); + + Builder.defineMacro("__ARCH__", Twine(ISARevision)); + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + if (HasTransactionalExecution) + Builder.defineMacro("__HTM__"); + if (HasVector) + Builder.defineMacro("__VX__"); + if (Opts.ZVector) + Builder.defineMacro("__VEC__", "10302"); +} + +ArrayRef<Builtin::Info> SystemZTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.h b/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.h new file mode 100644 index 0000000000000..3023c1d2ea262 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/SystemZ.h @@ -0,0 +1,145 @@ +//===--- SystemZ.h - Declare SystemZ target feature support -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares SystemZ TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + std::string CPU; + int ISARevision; + bool HasTransactionalExecution; + bool HasVector; + +public: + SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), CPU("z10"), ISARevision(8), + HasTransactionalExecution(false), HasVector(false) { + IntMaxType = SignedLong; + Int64Type = SignedLong; + TLSSupported = true; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + DefaultAlignForAttributeAligned = 64; + MinGlobalAlign = 16; + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::SystemZBuiltinVaList; + } + + int getISARevision(const StringRef &Name) const; + + bool isValidCPUName(StringRef Name) const override { + return getISARevision(Name) != -1; + } + + bool setCPU(const std::string &Name) override { + CPU = Name; + ISARevision = getISARevision(CPU); + return ISARevision != -1; + } + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + int ISARevision = getISARevision(CPU); + if (ISARevision >= 10) + Features["transactional-execution"] = true; + if (ISARevision >= 11) + Features["vector"] = true; + if (ISARevision >= 12) + Features["vector-enhancements-1"] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + HasTransactionalExecution = false; + HasVector = false; + for (const auto &Feature : Features) { + if (Feature == "+transactional-execution") + HasTransactionalExecution = true; + else if (Feature == "+vector") + HasVector = true; + } + // If we use the vector ABI, vector types are 64-bit aligned. + if (HasVector) { + MaxVectorAlign = 64; + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" + "-v128:64-a:8:16-n32:64"); + } + return true; + } + + bool hasFeature(StringRef Feature) const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } + + StringRef getABI() const override { + if (HasVector) + return "vector"; + return ""; + } + + bool useFloat128ManglingForLongDouble() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.cpp new file mode 100644 index 0000000000000..bf89c1dc549eb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.cpp @@ -0,0 +1,35 @@ +//===--- TCE.cpp - Implement TCE target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements TCE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "TCE.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +void TCETargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "tce", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); +} + +void TCELETargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "tcele", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); + Builder.defineMacro("__TCELE__"); + Builder.defineMacro("__TCELE_V1__"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.h b/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.h new file mode 100644 index 0000000000000..be43bed98d80b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/TCE.h @@ -0,0 +1,123 @@ +//===--- TCE.h - Declare TCE target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares TCE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// llvm and clang cannot be used directly to output native binaries for +// target, but is used to compile C code to llvm bitcode with correct +// type and alignment information. +// +// TCE uses the llvm bitcode as input and uses it for generating customized +// target processor and program binary. TCE co-design environment is +// publicly available in http://tce.cs.tut.fi + +static const unsigned TCEOpenCLAddrSpaceMap[] = { + 0, // Default + 3, // opencl_global + 4, // opencl_local + 5, // opencl_constant + 0, // opencl_private + // FIXME: generic has to be added to the target + 0, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared +}; + +class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo { +public: + TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + IntWidth = 32; + LongWidth = LongLongWidth = 32; + PointerWidth = 32; + IntAlign = 32; + LongAlign = LongLongAlign = 32; + PointerAlign = 32; + SuitableAlign = 32; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 32; + DoubleAlign = 32; + LongDoubleWidth = 32; + LongDoubleAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle(); + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + resetDataLayout("E-p:32:32:32-i1:8:8-i8:8:32-" + "i16:16:32-i32:32:32-i64:32:32-" + "f32:32:32-f64:32:32-v64:32:32-" + "v128:32:32-v256:32:32-v512:32:32-" + "v1024:32:32-a0:0:32-n32"); + AddrSpaceMap = &TCEOpenCLAddrSpaceMap; + UseAddrSpaceMapMangling = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + const char *getClobbers() const override { return ""; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } +}; + +class LLVM_LIBRARY_VISIBILITY TCELETargetInfo : public TCETargetInfo { +public: + TCELETargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TCETargetInfo(Triple, Opts) { + BigEndian = false; + + resetDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-" + "i16:16:32-i32:32:32-i64:32:32-" + "f32:32:32-f64:32:32-v64:32:32-" + "v128:32:32-v256:32:32-v512:32:32-" + "v1024:32:32-a0:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.cpp new file mode 100644 index 0000000000000..915aad4b563b4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.cpp @@ -0,0 +1,96 @@ +//===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements WebAssembly TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsWebAssembly.def" +}; + +bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("simd128", SIMDLevel >= SIMD128) + .Case("nontrapping-fptoint", HasNontrappingFPToInt) + .Default(false); +} + +bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) + .Case("mvp", true) + .Case("bleeding-edge", true) + .Case("generic", true) + .Default(false); +} + +void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + defineCPUMacros(Builder, "wasm", /*Tuning=*/false); + if (SIMDLevel >= SIMD128) + Builder.defineMacro("__wasm_simd128__"); +} + +bool WebAssemblyTargetInfo::handleTargetFeatures( + std::vector<std::string> &Features, DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+simd128") { + SIMDLevel = std::max(SIMDLevel, SIMD128); + continue; + } + if (Feature == "-simd128") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); + continue; + } + if (Feature == "+nontrapping-fptoint") { + HasNontrappingFPToInt = true; + continue; + } + if (Feature == "-nontrapping-fptoint") { + HasNontrappingFPToInt = false; + continue; + } + + Diags.Report(diag::err_opt_not_valid_with_opt) + << Feature << "-target-feature"; + return false; + } + return true; +} + +ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); +} + +void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.h b/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.h new file mode 100644 index 0000000000000..ee0073d081e0a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/WebAssembly.h @@ -0,0 +1,148 @@ +//=== WebAssembly.h - Declare WebAssembly target feature support *- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares WebAssembly TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + + enum SIMDEnum { + NoSIMD, + SIMD128, + } SIMDLevel; + + bool HasNontrappingFPToInt; + +public: + explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &) + : TargetInfo(T), SIMDLevel(NoSIMD), HasNontrappingFPToInt(false) { + NoAsmVariants = true; + SuitableAlign = 128; + LargeArrayMinWidth = 128; + LargeArrayAlign = 128; + SimdDefaultAlign = 128; + SigAtomicType = SignedLong; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + +private: + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + if (CPU == "bleeding-edge") { + Features["simd128"] = true; + Features["nontrapping-fptoint"] = true; + } + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool hasFeature(StringRef Feature) const final; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) final; + + bool isValidCPUName(StringRef Name) const final; + + bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } + + ArrayRef<Builtin::Info> getTargetBuiltins() const final; + + BuiltinVaListKind getBuiltinVaListKind() const final { + return VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const final { return None; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const final { + return false; + } + + const char *getClobbers() const final { return ""; } + + bool isCLZForZeroUndef() const final { return false; } + + bool hasInt128Type() const final { return true; } + + IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // WebAssembly prefers long long for explicitly 64-bit integers. + return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); + } + + IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // WebAssembly uses long long for int_least64_t and int_fast64_t. + return BitWidth == 64 + ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } +}; +class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo + : public WebAssemblyTargetInfo { +public: + explicit WebAssembly32TargetInfo(const llvm::Triple &T, + const TargetOptions &Opts) + : WebAssemblyTargetInfo(T, Opts) { + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128"); + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY WebAssembly64TargetInfo + : public WebAssemblyTargetInfo { +public: + explicit WebAssembly64TargetInfo(const llvm::Triple &T, + const TargetOptions &Opts) + : WebAssemblyTargetInfo(T, Opts) { + LongAlign = LongWidth = 64; + PointerAlign = PointerWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/X86.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/X86.cpp new file mode 100644 index 0000000000000..7fd9fd0478181 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/X86.cpp @@ -0,0 +1,1518 @@ +//===--- X86.cpp - Implement X86 target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements X86 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +namespace clang { +namespace targets { + +const Builtin::Info BuiltinInfoX86[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsX86.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsX86_64.def" +}; + +static const char *const GCCRegNames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1", + "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", + "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9", + "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1", + "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", + "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "xmm16", "xmm17", + "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25", + "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm16", "ymm17", + "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", "ymm24", "ymm25", + "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", "zmm1", + "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", + "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", + "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", + "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", "k0", "k1", + "k2", "k3", "k4", "k5", "k6", "k7", + "cr0", "cr2", "cr3", "cr4", "cr8", + "dr0", "dr1", "dr2", "dr3", "dr6", "dr7", + "bnd0", "bnd1", "bnd2", "bnd3", +}; + +const TargetInfo::AddlRegName AddlRegNames[] = { + {{"al", "ah", "eax", "rax"}, 0}, + {{"bl", "bh", "ebx", "rbx"}, 3}, + {{"cl", "ch", "ecx", "rcx"}, 2}, + {{"dl", "dh", "edx", "rdx"}, 1}, + {{"esi", "rsi"}, 4}, + {{"edi", "rdi"}, 5}, + {{"esp", "rsp"}, 7}, + {{"ebp", "rbp"}, 6}, + {{"r8d", "r8w", "r8b"}, 38}, + {{"r9d", "r9w", "r9b"}, 39}, + {{"r10d", "r10w", "r10b"}, 40}, + {{"r11d", "r11w", "r11b"}, 41}, + {{"r12d", "r12w", "r12b"}, 42}, + {{"r13d", "r13w", "r13b"}, 43}, + {{"r14d", "r14w", "r14b"}, 44}, + {{"r15d", "r15w", "r15b"}, 45}, +}; + +} // namespace targets +} // namespace clang + +using namespace clang; +using namespace clang::targets; + +bool X86TargetInfo::setFPMath(StringRef Name) { + if (Name == "387") { + FPMath = FP_387; + return true; + } + if (Name == "sse") { + FPMath = FP_SSE; + return true; + } + return false; +} + +bool X86TargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + // FIXME: This *really* should not be here. + // X86_64 always has SSE2. + if (getTriple().getArch() == llvm::Triple::x86_64) + setFeatureEnabledImpl(Features, "sse2", true); + + const CPUKind Kind = getCPUKind(CPU); + + // Enable X87 for all X86 processors but Lakemont. + if (Kind != CK_Lakemont) + setFeatureEnabledImpl(Features, "x87", true); + + switch (Kind) { + case CK_Generic: + case CK_i386: + case CK_i486: + case CK_i586: + case CK_Pentium: + case CK_PentiumPro: + case CK_Lakemont: + break; + + case CK_PentiumMMX: + case CK_Pentium2: + case CK_K6: + case CK_WinChipC6: + setFeatureEnabledImpl(Features, "mmx", true); + break; + + case CK_Icelake: + // TODO: Add icelake features here. + LLVM_FALLTHROUGH; + case CK_Cannonlake: + setFeatureEnabledImpl(Features, "avx512ifma", true); + setFeatureEnabledImpl(Features, "avx512vbmi", true); + setFeatureEnabledImpl(Features, "sha", true); + LLVM_FALLTHROUGH; + case CK_SkylakeServer: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512dq", true); + setFeatureEnabledImpl(Features, "avx512bw", true); + setFeatureEnabledImpl(Features, "avx512vl", true); + setFeatureEnabledImpl(Features, "pku", true); + setFeatureEnabledImpl(Features, "clwb", true); + LLVM_FALLTHROUGH; + case CK_SkylakeClient: + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); + setFeatureEnabledImpl(Features, "mpx", true); + setFeatureEnabledImpl(Features, "sgx", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "rtm", true); + LLVM_FALLTHROUGH; + case CK_Broadwell: + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + LLVM_FALLTHROUGH; + case CK_Haswell: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "movbe", true); + LLVM_FALLTHROUGH; + case CK_IvyBridge: + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + LLVM_FALLTHROUGH; + case CK_SandyBridge: + setFeatureEnabledImpl(Features, "avx", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + LLVM_FALLTHROUGH; + case CK_Westmere: + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + LLVM_FALLTHROUGH; + case CK_Nehalem: + setFeatureEnabledImpl(Features, "sse4.2", true); + LLVM_FALLTHROUGH; + case CK_Penryn: + setFeatureEnabledImpl(Features, "sse4.1", true); + LLVM_FALLTHROUGH; + case CK_Core2: + setFeatureEnabledImpl(Features, "ssse3", true); + LLVM_FALLTHROUGH; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: + setFeatureEnabledImpl(Features, "sse3", true); + setFeatureEnabledImpl(Features, "cx16", true); + LLVM_FALLTHROUGH; + case CK_PentiumM: + case CK_Pentium4: + case CK_x86_64: + setFeatureEnabledImpl(Features, "sse2", true); + LLVM_FALLTHROUGH; + case CK_Pentium3: + case CK_C3_2: + setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "fxsr", true); + break; + + case CK_Goldmont: + setFeatureEnabledImpl(Features, "sha", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "mpx", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + LLVM_FALLTHROUGH; + case CK_Silvermont: + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "sse4.2", true); + LLVM_FALLTHROUGH; + case CK_Bonnell: + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + + case CK_KNM: + // TODO: Add avx5124fmaps/avx5124vnniw. + setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); + LLVM_FALLTHROUGH; + case CK_KNL: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512er", true); + setFeatureEnabledImpl(Features, "avx512pf", true); + setFeatureEnabledImpl(Features, "prefetchwt1", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "rtm", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "movbe", true); + break; + + case CK_K6_2: + case CK_K6_3: + case CK_WinChip2: + case CK_C3: + setFeatureEnabledImpl(Features, "3dnow", true); + break; + + case CK_AMDFAM10: + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "popcnt", true); + LLVM_FALLTHROUGH; + case CK_K8SSE3: + setFeatureEnabledImpl(Features, "sse3", true); + LLVM_FALLTHROUGH; + case CK_K8: + setFeatureEnabledImpl(Features, "sse2", true); + LLVM_FALLTHROUGH; + case CK_AthlonXP: + setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "fxsr", true); + LLVM_FALLTHROUGH; + case CK_Athlon: + case CK_Geode: + setFeatureEnabledImpl(Features, "3dnowa", true); + break; + + case CK_BTVER2: + setFeatureEnabledImpl(Features, "avx", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "movbe", true); + LLVM_FALLTHROUGH; + case CK_BTVER1: + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "popcnt", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + break; + + case CK_ZNVER1: + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "clzero", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "mwaitx", true); + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "popcnt", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "sha", true); + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsaves", true); + break; + + case CK_BDVER4: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "mwaitx", true); + LLVM_FALLTHROUGH; + case CK_BDVER3: + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + LLVM_FALLTHROUGH; + case CK_BDVER2: + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "tbm", true); + LLVM_FALLTHROUGH; + case CK_BDVER1: + // xop implies avx, sse4a and fma4. + setFeatureEnabledImpl(Features, "xop", true); + setFeatureEnabledImpl(Features, "lwp", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "xsave", true); + break; + } + if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) + return false; + + // Can't do this earlier because we need to be able to explicitly enable + // or disable these features and the things that they depend upon. + + // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. + auto I = Features.find("sse4.2"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") == + FeaturesVec.end()) + Features["popcnt"] = true; + + // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. + I = Features.find("3dnow"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") == + FeaturesVec.end()) + Features["prfchw"] = true; + + // Additionally, if SSE is enabled and mmx is not explicitly disabled, + // then enable MMX. + I = Features.find("sse"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") == + FeaturesVec.end()) + Features["mmx"] = true; + + return true; +} + +void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, + X86SSEEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AVX512F: + Features["avx512f"] = true; + LLVM_FALLTHROUGH; + case AVX2: + Features["avx2"] = true; + LLVM_FALLTHROUGH; + case AVX: + Features["avx"] = true; + Features["xsave"] = true; + LLVM_FALLTHROUGH; + case SSE42: + Features["sse4.2"] = true; + LLVM_FALLTHROUGH; + case SSE41: + Features["sse4.1"] = true; + LLVM_FALLTHROUGH; + case SSSE3: + Features["ssse3"] = true; + LLVM_FALLTHROUGH; + case SSE3: + Features["sse3"] = true; + LLVM_FALLTHROUGH; + case SSE2: + Features["sse2"] = true; + LLVM_FALLTHROUGH; + case SSE1: + Features["sse"] = true; + LLVM_FALLTHROUGH; + case NoSSE: + break; + } + return; + } + + switch (Level) { + case NoSSE: + case SSE1: + Features["sse"] = false; + LLVM_FALLTHROUGH; + case SSE2: + Features["sse2"] = Features["pclmul"] = Features["aes"] = Features["sha"] = + false; + LLVM_FALLTHROUGH; + case SSE3: + Features["sse3"] = false; + setXOPLevel(Features, NoXOP, false); + LLVM_FALLTHROUGH; + case SSSE3: + Features["ssse3"] = false; + LLVM_FALLTHROUGH; + case SSE41: + Features["sse4.1"] = false; + LLVM_FALLTHROUGH; + case SSE42: + Features["sse4.2"] = false; + LLVM_FALLTHROUGH; + case AVX: + Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = + Features["xsaveopt"] = false; + setXOPLevel(Features, FMA4, false); + LLVM_FALLTHROUGH; + case AVX2: + Features["avx2"] = false; + LLVM_FALLTHROUGH; + case AVX512F: + Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = + Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = + Features["avx512vl"] = Features["avx512vbmi"] = + Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; + break; + } +} + +void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, + MMX3DNowEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AMD3DNowAthlon: + Features["3dnowa"] = true; + LLVM_FALLTHROUGH; + case AMD3DNow: + Features["3dnow"] = true; + LLVM_FALLTHROUGH; + case MMX: + Features["mmx"] = true; + LLVM_FALLTHROUGH; + case NoMMX3DNow: + break; + } + return; + } + + switch (Level) { + case NoMMX3DNow: + case MMX: + Features["mmx"] = false; + LLVM_FALLTHROUGH; + case AMD3DNow: + Features["3dnow"] = false; + LLVM_FALLTHROUGH; + case AMD3DNowAthlon: + Features["3dnowa"] = false; + break; + } +} + +void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, + bool Enabled) { + if (Enabled) { + switch (Level) { + case XOP: + Features["xop"] = true; + LLVM_FALLTHROUGH; + case FMA4: + Features["fma4"] = true; + setSSELevel(Features, AVX, true); + LLVM_FALLTHROUGH; + case SSE4A: + Features["sse4a"] = true; + setSSELevel(Features, SSE3, true); + LLVM_FALLTHROUGH; + case NoXOP: + break; + } + return; + } + + switch (Level) { + case NoXOP: + case SSE4A: + Features["sse4a"] = false; + LLVM_FALLTHROUGH; + case FMA4: + Features["fma4"] = false; + LLVM_FALLTHROUGH; + case XOP: + Features["xop"] = false; + break; + } +} + +void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) { + // This is a bit of a hack to deal with the sse4 target feature when used + // as part of the target attribute. We handle sse4 correctly everywhere + // else. See below for more information on how we handle the sse4 options. + if (Name != "sse4") + Features[Name] = Enabled; + + if (Name == "mmx") { + setMMXLevel(Features, MMX, Enabled); + } else if (Name == "sse") { + setSSELevel(Features, SSE1, Enabled); + } else if (Name == "sse2") { + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "sse3") { + setSSELevel(Features, SSE3, Enabled); + } else if (Name == "ssse3") { + setSSELevel(Features, SSSE3, Enabled); + } else if (Name == "sse4.2") { + setSSELevel(Features, SSE42, Enabled); + } else if (Name == "sse4.1") { + setSSELevel(Features, SSE41, Enabled); + } else if (Name == "3dnow") { + setMMXLevel(Features, AMD3DNow, Enabled); + } else if (Name == "3dnowa") { + setMMXLevel(Features, AMD3DNowAthlon, Enabled); + } else if (Name == "aes") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "pclmul") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "avx") { + setSSELevel(Features, AVX, Enabled); + } else if (Name == "avx2") { + setSSELevel(Features, AVX2, Enabled); + } else if (Name == "avx512f") { + setSSELevel(Features, AVX512F, Enabled); + } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" || + Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" || + Name == "avx512vbmi" || Name == "avx512ifma" || + Name == "avx512vpopcntdq") { + if (Enabled) + setSSELevel(Features, AVX512F, Enabled); + // Enable BWI instruction if VBMI is being enabled. + if (Name == "avx512vbmi" && Enabled) + Features["avx512bw"] = true; + // Also disable VBMI if BWI is being disabled. + if (Name == "avx512bw" && !Enabled) + Features["avx512vbmi"] = false; + } else if (Name == "fma") { + if (Enabled) + setSSELevel(Features, AVX, Enabled); + } else if (Name == "fma4") { + setXOPLevel(Features, FMA4, Enabled); + } else if (Name == "xop") { + setXOPLevel(Features, XOP, Enabled); + } else if (Name == "sse4a") { + setXOPLevel(Features, SSE4A, Enabled); + } else if (Name == "f16c") { + if (Enabled) + setSSELevel(Features, AVX, Enabled); + } else if (Name == "sha") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "sse4") { + // We can get here via the __target__ attribute since that's not controlled + // via the -msse4/-mno-sse4 command line alias. Handle this the same way + // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if + // disabled. + if (Enabled) + setSSELevel(Features, SSE42, Enabled); + else + setSSELevel(Features, SSE41, Enabled); + } else if (Name == "xsave") { + if (!Enabled) + Features["xsaveopt"] = false; + } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { + if (Enabled) + Features["xsave"] = true; + } +} + +/// handleTargetFeatures - Perform initialization based on the user +/// configured set of features. +bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature[0] != '+') + continue; + + if (Feature == "+aes") { + HasAES = true; + } else if (Feature == "+pclmul") { + HasPCLMUL = true; + } else if (Feature == "+lzcnt") { + HasLZCNT = true; + } else if (Feature == "+rdrnd") { + HasRDRND = true; + } else if (Feature == "+fsgsbase") { + HasFSGSBASE = true; + } else if (Feature == "+bmi") { + HasBMI = true; + } else if (Feature == "+bmi2") { + HasBMI2 = true; + } else if (Feature == "+popcnt") { + HasPOPCNT = true; + } else if (Feature == "+rtm") { + HasRTM = true; + } else if (Feature == "+prfchw") { + HasPRFCHW = true; + } else if (Feature == "+rdseed") { + HasRDSEED = true; + } else if (Feature == "+adx") { + HasADX = true; + } else if (Feature == "+tbm") { + HasTBM = true; + } else if (Feature == "+lwp") { + HasLWP = true; + } else if (Feature == "+fma") { + HasFMA = true; + } else if (Feature == "+f16c") { + HasF16C = true; + } else if (Feature == "+avx512cd") { + HasAVX512CD = true; + } else if (Feature == "+avx512vpopcntdq") { + HasAVX512VPOPCNTDQ = true; + } else if (Feature == "+avx512er") { + HasAVX512ER = true; + } else if (Feature == "+avx512pf") { + HasAVX512PF = true; + } else if (Feature == "+avx512dq") { + HasAVX512DQ = true; + } else if (Feature == "+avx512bw") { + HasAVX512BW = true; + } else if (Feature == "+avx512vl") { + HasAVX512VL = true; + } else if (Feature == "+avx512vbmi") { + HasAVX512VBMI = true; + } else if (Feature == "+avx512ifma") { + HasAVX512IFMA = true; + } else if (Feature == "+sha") { + HasSHA = true; + } else if (Feature == "+mpx") { + HasMPX = true; + } else if (Feature == "+shstk") { + HasSHSTK = true; + } else if (Feature == "+ibt") { + HasIBT = true; + } else if (Feature == "+movbe") { + HasMOVBE = true; + } else if (Feature == "+sgx") { + HasSGX = true; + } else if (Feature == "+cx16") { + HasCX16 = true; + } else if (Feature == "+fxsr") { + HasFXSR = true; + } else if (Feature == "+xsave") { + HasXSAVE = true; + } else if (Feature == "+xsaveopt") { + HasXSAVEOPT = true; + } else if (Feature == "+xsavec") { + HasXSAVEC = true; + } else if (Feature == "+xsaves") { + HasXSAVES = true; + } else if (Feature == "+mwaitx") { + HasMWAITX = true; + } else if (Feature == "+pku") { + HasPKU = true; + } else if (Feature == "+clflushopt") { + HasCLFLUSHOPT = true; + } else if (Feature == "+clwb") { + HasCLWB = true; + } else if (Feature == "+prefetchwt1") { + HasPREFETCHWT1 = true; + } else if (Feature == "+clzero") { + HasCLZERO = true; + } + + X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature) + .Case("+avx512f", AVX512F) + .Case("+avx2", AVX2) + .Case("+avx", AVX) + .Case("+sse4.2", SSE42) + .Case("+sse4.1", SSE41) + .Case("+ssse3", SSSE3) + .Case("+sse3", SSE3) + .Case("+sse2", SSE2) + .Case("+sse", SSE1) + .Default(NoSSE); + SSELevel = std::max(SSELevel, Level); + + MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch<MMX3DNowEnum>(Feature) + .Case("+3dnowa", AMD3DNowAthlon) + .Case("+3dnow", AMD3DNow) + .Case("+mmx", MMX) + .Default(NoMMX3DNow); + MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); + + XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature) + .Case("+xop", XOP) + .Case("+fma4", FMA4) + .Case("+sse4a", SSE4A) + .Default(NoXOP); + XOPLevel = std::max(XOPLevel, XLevel); + } + + // LLVM doesn't have a separate switch for fpmath, so only accept it if it + // matches the selected sse level. + if ((FPMath == FP_SSE && SSELevel < SSE1) || + (FPMath == FP_387 && SSELevel >= SSE1)) { + Diags.Report(diag::err_target_unsupported_fpmath) + << (FPMath == FP_SSE ? "sse" : "387"); + return false; + } + + SimdDefaultAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; +} + +/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro +/// definitions for this particular subtarget. +void X86TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + if (getTriple().getArch() == llvm::Triple::x86_64) { + Builder.defineMacro("__amd64__"); + Builder.defineMacro("__amd64"); + Builder.defineMacro("__x86_64"); + Builder.defineMacro("__x86_64__"); + if (getTriple().getArchName() == "x86_64h") { + Builder.defineMacro("__x86_64h"); + Builder.defineMacro("__x86_64h__"); + } + } else { + DefineStd(Builder, "i386", Opts); + } + + // Subtarget options. + // FIXME: We are hard-coding the tune parameters based on the CPU, but they + // truly should be based on -mtune options. + switch (CPU) { + case CK_Generic: + break; + case CK_i386: + // The rest are coming from the i386 define above. + Builder.defineMacro("__tune_i386__"); + break; + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + defineCPUMacros(Builder, "i486"); + break; + case CK_PentiumMMX: + Builder.defineMacro("__pentium_mmx__"); + Builder.defineMacro("__tune_pentium_mmx__"); + LLVM_FALLTHROUGH; + case CK_i586: + case CK_Pentium: + defineCPUMacros(Builder, "i586"); + defineCPUMacros(Builder, "pentium"); + break; + case CK_Pentium3: + case CK_PentiumM: + Builder.defineMacro("__tune_pentium3__"); + LLVM_FALLTHROUGH; + case CK_Pentium2: + case CK_C3_2: + Builder.defineMacro("__tune_pentium2__"); + LLVM_FALLTHROUGH; + case CK_PentiumPro: + defineCPUMacros(Builder, "i686"); + defineCPUMacros(Builder, "pentiumpro"); + break; + case CK_Pentium4: + defineCPUMacros(Builder, "pentium4"); + break; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: + defineCPUMacros(Builder, "nocona"); + break; + case CK_Core2: + case CK_Penryn: + defineCPUMacros(Builder, "core2"); + break; + case CK_Bonnell: + defineCPUMacros(Builder, "atom"); + break; + case CK_Silvermont: + defineCPUMacros(Builder, "slm"); + break; + case CK_Goldmont: + defineCPUMacros(Builder, "goldmont"); + break; + case CK_Nehalem: + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_SkylakeClient: + case CK_SkylakeServer: + case CK_Cannonlake: + case CK_Icelake: + // FIXME: Historically, we defined this legacy name, it would be nice to + // remove it at some point. We've never exposed fine-grained names for + // recent primary x86 CPUs, and we should keep it that way. + defineCPUMacros(Builder, "corei7"); + break; + case CK_KNL: + defineCPUMacros(Builder, "knl"); + break; + case CK_KNM: + break; + case CK_Lakemont: + defineCPUMacros(Builder, "i586", /*Tuning*/false); + defineCPUMacros(Builder, "pentium", /*Tuning*/false); + Builder.defineMacro("__tune_lakemont__"); + break; + case CK_K6_2: + Builder.defineMacro("__k6_2__"); + Builder.defineMacro("__tune_k6_2__"); + LLVM_FALLTHROUGH; + case CK_K6_3: + if (CPU != CK_K6_2) { // In case of fallthrough + // FIXME: GCC may be enabling these in cases where some other k6 + // architecture is specified but -m3dnow is explicitly provided. The + // exact semantics need to be determined and emulated here. + Builder.defineMacro("__k6_3__"); + Builder.defineMacro("__tune_k6_3__"); + } + LLVM_FALLTHROUGH; + case CK_K6: + defineCPUMacros(Builder, "k6"); + break; + case CK_Athlon: + case CK_AthlonXP: + defineCPUMacros(Builder, "athlon"); + if (SSELevel != NoSSE) { + Builder.defineMacro("__athlon_sse__"); + Builder.defineMacro("__tune_athlon_sse__"); + } + break; + case CK_K8: + case CK_K8SSE3: + case CK_x86_64: + defineCPUMacros(Builder, "k8"); + break; + case CK_AMDFAM10: + defineCPUMacros(Builder, "amdfam10"); + break; + case CK_BTVER1: + defineCPUMacros(Builder, "btver1"); + break; + case CK_BTVER2: + defineCPUMacros(Builder, "btver2"); + break; + case CK_BDVER1: + defineCPUMacros(Builder, "bdver1"); + break; + case CK_BDVER2: + defineCPUMacros(Builder, "bdver2"); + break; + case CK_BDVER3: + defineCPUMacros(Builder, "bdver3"); + break; + case CK_BDVER4: + defineCPUMacros(Builder, "bdver4"); + break; + case CK_ZNVER1: + defineCPUMacros(Builder, "znver1"); + break; + case CK_Geode: + defineCPUMacros(Builder, "geode"); + break; + } + + // Target properties. + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline + // functions in glibc header files that use FP Stack inline asm which the + // backend can't deal with (PR879). + Builder.defineMacro("__NO_MATH_INLINES"); + + if (HasAES) + Builder.defineMacro("__AES__"); + + if (HasPCLMUL) + Builder.defineMacro("__PCLMUL__"); + + if (HasLZCNT) + Builder.defineMacro("__LZCNT__"); + + if (HasRDRND) + Builder.defineMacro("__RDRND__"); + + if (HasFSGSBASE) + Builder.defineMacro("__FSGSBASE__"); + + if (HasBMI) + Builder.defineMacro("__BMI__"); + + if (HasBMI2) + Builder.defineMacro("__BMI2__"); + + if (HasPOPCNT) + Builder.defineMacro("__POPCNT__"); + + if (HasRTM) + Builder.defineMacro("__RTM__"); + + if (HasPRFCHW) + Builder.defineMacro("__PRFCHW__"); + + if (HasRDSEED) + Builder.defineMacro("__RDSEED__"); + + if (HasADX) + Builder.defineMacro("__ADX__"); + + if (HasTBM) + Builder.defineMacro("__TBM__"); + + if (HasLWP) + Builder.defineMacro("__LWP__"); + + if (HasMWAITX) + Builder.defineMacro("__MWAITX__"); + + switch (XOPLevel) { + case XOP: + Builder.defineMacro("__XOP__"); + LLVM_FALLTHROUGH; + case FMA4: + Builder.defineMacro("__FMA4__"); + LLVM_FALLTHROUGH; + case SSE4A: + Builder.defineMacro("__SSE4A__"); + LLVM_FALLTHROUGH; + case NoXOP: + break; + } + + if (HasFMA) + Builder.defineMacro("__FMA__"); + + if (HasF16C) + Builder.defineMacro("__F16C__"); + + if (HasAVX512CD) + Builder.defineMacro("__AVX512CD__"); + if (HasAVX512VPOPCNTDQ) + Builder.defineMacro("__AVX512VPOPCNTDQ__"); + if (HasAVX512ER) + Builder.defineMacro("__AVX512ER__"); + if (HasAVX512PF) + Builder.defineMacro("__AVX512PF__"); + if (HasAVX512DQ) + Builder.defineMacro("__AVX512DQ__"); + if (HasAVX512BW) + Builder.defineMacro("__AVX512BW__"); + if (HasAVX512VL) + Builder.defineMacro("__AVX512VL__"); + if (HasAVX512VBMI) + Builder.defineMacro("__AVX512VBMI__"); + if (HasAVX512IFMA) + Builder.defineMacro("__AVX512IFMA__"); + + if (HasSHA) + Builder.defineMacro("__SHA__"); + + if (HasFXSR) + Builder.defineMacro("__FXSR__"); + if (HasXSAVE) + Builder.defineMacro("__XSAVE__"); + if (HasXSAVEOPT) + Builder.defineMacro("__XSAVEOPT__"); + if (HasXSAVEC) + Builder.defineMacro("__XSAVEC__"); + if (HasXSAVES) + Builder.defineMacro("__XSAVES__"); + if (HasPKU) + Builder.defineMacro("__PKU__"); + if (HasCX16) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); + if (HasCLFLUSHOPT) + Builder.defineMacro("__CLFLUSHOPT__"); + if (HasCLWB) + Builder.defineMacro("__CLWB__"); + if (HasMPX) + Builder.defineMacro("__MPX__"); + if (HasSHSTK) + Builder.defineMacro("__SHSTK__"); + if (HasSGX) + Builder.defineMacro("__SGX__"); + if (HasPREFETCHWT1) + Builder.defineMacro("__PREFETCHWT1__"); + if (HasCLZERO) + Builder.defineMacro("__CLZERO__"); + + // Each case falls through to the previous one here. + switch (SSELevel) { + case AVX512F: + Builder.defineMacro("__AVX512F__"); + LLVM_FALLTHROUGH; + case AVX2: + Builder.defineMacro("__AVX2__"); + LLVM_FALLTHROUGH; + case AVX: + Builder.defineMacro("__AVX__"); + LLVM_FALLTHROUGH; + case SSE42: + Builder.defineMacro("__SSE4_2__"); + LLVM_FALLTHROUGH; + case SSE41: + Builder.defineMacro("__SSE4_1__"); + LLVM_FALLTHROUGH; + case SSSE3: + Builder.defineMacro("__SSSE3__"); + LLVM_FALLTHROUGH; + case SSE3: + Builder.defineMacro("__SSE3__"); + LLVM_FALLTHROUGH; + case SSE2: + Builder.defineMacro("__SSE2__"); + Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; + case SSE1: + Builder.defineMacro("__SSE__"); + Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; + case NoSSE: + break; + } + + if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { + switch (SSELevel) { + case AVX512F: + case AVX2: + case AVX: + case SSE42: + case SSE41: + case SSSE3: + case SSE3: + case SSE2: + Builder.defineMacro("_M_IX86_FP", Twine(2)); + break; + case SSE1: + Builder.defineMacro("_M_IX86_FP", Twine(1)); + break; + default: + Builder.defineMacro("_M_IX86_FP", Twine(0)); + break; + } + } + + // Each case falls through to the previous one here. + switch (MMX3DNowLevel) { + case AMD3DNowAthlon: + Builder.defineMacro("__3dNOW_A__"); + LLVM_FALLTHROUGH; + case AMD3DNow: + Builder.defineMacro("__3dNOW__"); + LLVM_FALLTHROUGH; + case MMX: + Builder.defineMacro("__MMX__"); + LLVM_FALLTHROUGH; + case NoMMX3DNow: + break; + } + + if (CPU >= CK_i486) { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + } + if (CPU >= CK_i586) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + if (HasFloat128) + Builder.defineMacro("__SIZEOF_FLOAT128__", "16"); +} + +bool X86TargetInfo::isValidFeatureName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) + .Case("3dnow", true) + .Case("3dnowa", true) + .Case("aes", true) + .Case("avx", true) + .Case("avx2", true) + .Case("avx512f", true) + .Case("avx512cd", true) + .Case("avx512vpopcntdq", true) + .Case("avx512er", true) + .Case("avx512pf", true) + .Case("avx512dq", true) + .Case("avx512bw", true) + .Case("avx512vl", true) + .Case("avx512vbmi", true) + .Case("avx512ifma", true) + .Case("bmi", true) + .Case("bmi2", true) + .Case("clflushopt", true) + .Case("clwb", true) + .Case("clzero", true) + .Case("cx16", true) + .Case("f16c", true) + .Case("fma", true) + .Case("fma4", true) + .Case("fsgsbase", true) + .Case("fxsr", true) + .Case("lwp", true) + .Case("lzcnt", true) + .Case("mmx", true) + .Case("movbe", true) + .Case("mpx", true) + .Case("pclmul", true) + .Case("pku", true) + .Case("popcnt", true) + .Case("prefetchwt1", true) + .Case("prfchw", true) + .Case("rdrnd", true) + .Case("rdseed", true) + .Case("rtm", true) + .Case("sgx", true) + .Case("sha", true) + .Case("sse", true) + .Case("sse2", true) + .Case("sse3", true) + .Case("ssse3", true) + .Case("sse4", true) + .Case("sse4.1", true) + .Case("sse4.2", true) + .Case("sse4a", true) + .Case("tbm", true) + .Case("x87", true) + .Case("xop", true) + .Case("xsave", true) + .Case("xsavec", true) + .Case("xsaves", true) + .Case("xsaveopt", true) + .Default(false); +} + +bool X86TargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("aes", HasAES) + .Case("avx", SSELevel >= AVX) + .Case("avx2", SSELevel >= AVX2) + .Case("avx512f", SSELevel >= AVX512F) + .Case("avx512cd", HasAVX512CD) + .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) + .Case("avx512er", HasAVX512ER) + .Case("avx512pf", HasAVX512PF) + .Case("avx512dq", HasAVX512DQ) + .Case("avx512bw", HasAVX512BW) + .Case("avx512vl", HasAVX512VL) + .Case("avx512vbmi", HasAVX512VBMI) + .Case("avx512ifma", HasAVX512IFMA) + .Case("bmi", HasBMI) + .Case("bmi2", HasBMI2) + .Case("clflushopt", HasCLFLUSHOPT) + .Case("clwb", HasCLWB) + .Case("clzero", HasCLZERO) + .Case("cx16", HasCX16) + .Case("f16c", HasF16C) + .Case("fma", HasFMA) + .Case("fma4", XOPLevel >= FMA4) + .Case("fsgsbase", HasFSGSBASE) + .Case("fxsr", HasFXSR) + .Case("lwp", HasLWP) + .Case("lzcnt", HasLZCNT) + .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) + .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) + .Case("mmx", MMX3DNowLevel >= MMX) + .Case("movbe", HasMOVBE) + .Case("mpx", HasMPX) + .Case("shstk", HasSHSTK) + .Case("ibt", HasIBT) + .Case("pclmul", HasPCLMUL) + .Case("pku", HasPKU) + .Case("popcnt", HasPOPCNT) + .Case("prefetchwt1", HasPREFETCHWT1) + .Case("prfchw", HasPRFCHW) + .Case("rdrnd", HasRDRND) + .Case("rdseed", HasRDSEED) + .Case("rtm", HasRTM) + .Case("sgx", HasSGX) + .Case("sha", HasSHA) + .Case("sse", SSELevel >= SSE1) + .Case("sse2", SSELevel >= SSE2) + .Case("sse3", SSELevel >= SSE3) + .Case("ssse3", SSELevel >= SSSE3) + .Case("sse4.1", SSELevel >= SSE41) + .Case("sse4.2", SSELevel >= SSE42) + .Case("sse4a", XOPLevel >= SSE4A) + .Case("tbm", HasTBM) + .Case("x86", true) + .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) + .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) + .Case("xop", XOPLevel >= XOP) + .Case("xsave", HasXSAVE) + .Case("xsavec", HasXSAVEC) + .Case("xsaves", HasXSAVES) + .Case("xsaveopt", HasXSAVEOPT) + .Default(false); +} + +// We can't use a generic validation scheme for the features accepted here +// versus subtarget features accepted in the target attribute because the +// bitfield structure that's initialized in the runtime only supports the +// below currently rather than the full range of subtarget features. (See +// X86TargetInfo::hasFeature for a somewhat comprehensive list). +bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { + return llvm::StringSwitch<bool>(FeatureStr) +#define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, true) +#include "llvm/Support/X86TargetParser.def" + .Default(false); +} + +// We can't use a generic validation scheme for the cpus accepted here +// versus subtarget cpus accepted in the target attribute because the +// variables intitialized by the runtime only support the below currently +// rather than the full range of cpus. +bool X86TargetInfo::validateCpuIs(StringRef FeatureStr) const { + return llvm::StringSwitch<bool>(FeatureStr) +#define X86_VENDOR(ENUM, STRING) .Case(STRING, true) +#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) \ + .Cases(STR, ALIAS, true) +#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) .Case(STR, true) +#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) .Case(STR, true) +#include "llvm/Support/X86TargetParser.def" + .Default(false); +} + +bool X86TargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + // Constant constraints. + case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 + // instructions. + case 'Z': // 32-bit unsigned integer constant for use with zero-extending + // x86_64 instructions. + case 's': + Info.setRequiresImmediate(); + return true; + case 'I': + Info.setRequiresImmediate(0, 31); + return true; + case 'J': + Info.setRequiresImmediate(0, 63); + return true; + case 'K': + Info.setRequiresImmediate(-128, 127); + return true; + case 'L': + Info.setRequiresImmediate({int(0xff), int(0xffff), int(0xffffffff)}); + return true; + case 'M': + Info.setRequiresImmediate(0, 3); + return true; + case 'N': + Info.setRequiresImmediate(0, 255); + return true; + case 'O': + Info.setRequiresImmediate(0, 127); + return true; + // Register constraints. + case 'Y': // 'Y' is the first character for several 2-character constraints. + // Shift the pointer to the second character of the constraint. + Name++; + switch (*Name) { + default: + return false; + case 'z': + case '0': // First SSE register. + case '2': + case 't': // Any SSE register, when SSE2 is enabled. + case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. + case 'm': // Any MMX register, when inter-unit moves enabled. + case 'k': // AVX512 arch mask registers: k1-k7. + Info.setAllowsRegister(); + return true; + } + case 'f': // Any x87 floating point stack register. + // Constraint 'f' cannot be used for output operands. + if (Info.ConstraintStr[0] == '=') + return false; + Info.setAllowsRegister(); + return true; + case 'a': // eax. + case 'b': // ebx. + case 'c': // ecx. + case 'd': // edx. + case 'S': // esi. + case 'D': // edi. + case 'A': // edx:eax. + case 't': // Top of floating point stack. + case 'u': // Second from top of floating point stack. + case 'q': // Any register accessible as [r]l: a, b, c, and d. + case 'y': // Any MMX register. + case 'v': // Any {X,Y,Z}MM register (Arch & context dependent) + case 'x': // Any SSE register. + case 'k': // Any AVX512 mask register (same as Yk, additionaly allows k0 + // for intermideate k reg operations). + case 'Q': // Any register accessible as [r]h: a, b, c, and d. + case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. + case 'l': // "Index" registers: any general register that can be used as an + // index in a base+index memory access. + Info.setAllowsRegister(); + return true; + // Floating point constant constraints. + case 'C': // SSE floating point constant. + case 'G': // x87 floating point constant. + return true; + } +} + +bool X86TargetInfo::validateOutputSize(StringRef Constraint, + unsigned Size) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + return validateOperandSize(Constraint, Size); +} + +bool X86TargetInfo::validateInputSize(StringRef Constraint, + unsigned Size) const { + return validateOperandSize(Constraint, Size); +} + +bool X86TargetInfo::validateOperandSize(StringRef Constraint, + unsigned Size) const { + switch (Constraint[0]) { + default: + break; + case 'k': + // Registers k0-k7 (AVX512) size limit is 64 bit. + case 'y': + return Size <= 64; + case 'f': + case 't': + case 'u': + return Size <= 128; + case 'Y': + // 'Y' is the first character for several 2-character constraints. + switch (Constraint[1]) { + default: + return false; + case 'm': + // 'Ym' is synonymous with 'y'. + case 'k': + return Size <= 64; + case 'z': + case '0': + // XMM0 + if (SSELevel >= SSE1) + return Size <= 128U; + return false; + case 'i': + case 't': + case '2': + // 'Yi','Yt','Y2' are synonymous with 'x' when SSE2 is enabled. + if (SSELevel < SSE2) + return false; + break; + } + case 'v': + case 'x': + if (SSELevel >= AVX512F) + // 512-bit zmm registers can be used if target supports AVX512F. + return Size <= 512U; + else if (SSELevel >= AVX) + // 256-bit ymm registers can be used if target supports AVX. + return Size <= 256U; + return Size <= 128U; + + } + + return true; +} + +std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { + switch (*Constraint) { + case 'a': + return std::string("{ax}"); + case 'b': + return std::string("{bx}"); + case 'c': + return std::string("{cx}"); + case 'd': + return std::string("{dx}"); + case 'S': + return std::string("{si}"); + case 'D': + return std::string("{di}"); + case 'p': // address + return std::string("im"); + case 't': // top of floating point stack. + return std::string("{st}"); + case 'u': // second from top of floating point stack. + return std::string("{st(1)}"); // second from top of floating point stack. + case 'Y': + switch (Constraint[1]) { + default: + // Break from inner switch and fall through (copy single char), + // continue parsing after copying the current constraint into + // the return string. + break; + case 'k': + case 'm': + case 'i': + case 't': + case 'z': + case '0': + case '2': + // "^" hints llvm that this is a 2 letter constraint. + // "Constraint++" is used to promote the string iterator + // to the next constraint. + return std::string("^") + std::string(Constraint++, 2); + } + LLVM_FALLTHROUGH; + default: + return std::string(1, *Constraint); + } +} + +bool X86TargetInfo::checkCPUKind(CPUKind Kind) const { + // Perform any per-CPU checks necessary to determine if this CPU is + // acceptable. + // FIXME: This results in terrible diagnostics. Clang just says the CPU is + // invalid without explaining *why*. + switch (Kind) { + case CK_Generic: + // No processor selected! + return false; +#define PROC(ENUM, STRING, IS64BIT) \ + case CK_##ENUM: \ + return IS64BIT || getTriple().getArch() == llvm::Triple::x86; +#include "clang/Basic/X86Target.def" + } + llvm_unreachable("Unhandled CPU kind"); +} + +X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const { + return llvm::StringSwitch<CPUKind>(CPU) +#define PROC(ENUM, STRING, IS64BIT) .Case(STRING, CK_##ENUM) +#define PROC_ALIAS(ENUM, ALIAS) .Case(ALIAS, CK_##ENUM) +#include "clang/Basic/X86Target.def" + .Default(CK_Generic); +} + +ArrayRef<const char *> X86TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef<TargetInfo::AddlRegName> X86TargetInfo::getGCCAddlRegNames() const { + return llvm::makeArrayRef(AddlRegNames); +} + +ArrayRef<Builtin::Info> X86_32TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin - + Builtin::FirstTSBuiltin + 1); +} + +ArrayRef<Builtin::Info> X86_64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfoX86, + X86::LastTSBuiltin - Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/X86.h b/contrib/llvm/tools/clang/lib/Basic/Targets/X86.h new file mode 100644 index 0000000000000..b1811593545e7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/X86.h @@ -0,0 +1,801 @@ +//===--- X86.h - Declare X86 target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares X86 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_X86_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_X86_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// X86 target abstract base class; x86-32 and x86-64 are very close, so +// most of the implementation can be shared. +class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { + + enum X86SSEEnum { + NoSSE, + SSE1, + SSE2, + SSE3, + SSSE3, + SSE41, + SSE42, + AVX, + AVX2, + AVX512F + } SSELevel = NoSSE; + enum MMX3DNowEnum { + NoMMX3DNow, + MMX, + AMD3DNow, + AMD3DNowAthlon + } MMX3DNowLevel = NoMMX3DNow; + enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP; + + bool HasAES = false; + bool HasPCLMUL = false; + bool HasLZCNT = false; + bool HasRDRND = false; + bool HasFSGSBASE = false; + bool HasBMI = false; + bool HasBMI2 = false; + bool HasPOPCNT = false; + bool HasRTM = false; + bool HasPRFCHW = false; + bool HasRDSEED = false; + bool HasADX = false; + bool HasTBM = false; + bool HasLWP = false; + bool HasFMA = false; + bool HasF16C = false; + bool HasAVX512CD = false; + bool HasAVX512VPOPCNTDQ = false; + bool HasAVX512ER = false; + bool HasAVX512PF = false; + bool HasAVX512DQ = false; + bool HasAVX512BW = false; + bool HasAVX512VL = false; + bool HasAVX512VBMI = false; + bool HasAVX512IFMA = false; + bool HasSHA = false; + bool HasMPX = false; + bool HasSHSTK = false; + bool HasIBT = false; + bool HasSGX = false; + bool HasCX16 = false; + bool HasFXSR = false; + bool HasXSAVE = false; + bool HasXSAVEOPT = false; + bool HasXSAVEC = false; + bool HasXSAVES = false; + bool HasMWAITX = false; + bool HasCLZERO = false; + bool HasPKU = false; + bool HasCLFLUSHOPT = false; + bool HasCLWB = false; + bool HasMOVBE = false; + bool HasPREFETCHWT1 = false; + + /// \brief Enumeration of all of the X86 CPUs supported by Clang. + /// + /// Each enumeration represents a particular CPU supported by Clang. These + /// loosely correspond to the options passed to '-march' or '-mtune' flags. + enum CPUKind { + CK_Generic, +#define PROC(ENUM, STRING, IS64BIT) CK_##ENUM, +#include "clang/Basic/X86Target.def" + } CPU = CK_Generic; + + bool checkCPUKind(CPUKind Kind) const; + + CPUKind getCPUKind(StringRef CPU) const; + + enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default; + +public: + X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + } + + unsigned getFloatEvalMethod() const override { + // X87 evaluates with 80 bits "long double" precision. + return SSELevel == NoSSE ? 2 : 0; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + + bool validateCpuSupports(StringRef Name) const override; + + bool validateCpuIs(StringRef Name) const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + + bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, + bool &HasSizeMismatch) const override { + // esp and ebp are the only 32-bit registers the x86 backend can currently + // handle. + if (RegName.equals("esp") || RegName.equals("ebp")) { + // Check that the register size is 32-bit. + HasSizeMismatch = RegSize != 32; + return true; + } + + return false; + } + + bool validateOutputSize(StringRef Constraint, unsigned Size) const override; + + bool validateInputSize(StringRef Constraint, unsigned Size) const override; + + virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; + + std::string convertConstraint(const char *&Constraint) const override; + const char *getClobbers() const override { + return "~{dirflag},~{fpsr},~{flags}"; + } + + StringRef getConstraintRegister(const StringRef &Constraint, + const StringRef &Expression) const override { + StringRef::iterator I, E; + for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) { + if (isalpha(*I)) + break; + } + if (I == E) + return ""; + switch (*I) { + // For the register constraints, return the matching register name + case 'a': + return "ax"; + case 'b': + return "bx"; + case 'c': + return "cx"; + case 'd': + return "dx"; + case 'S': + return "si"; + case 'D': + return "di"; + // In case the constraint is 'r' we need to return Expression + case 'r': + return Expression; + // Double letters Y<x> constraints + case 'Y': + if ((++I != E) && ((*I == '0') || (*I == 'z'))) + return "xmm0"; + default: + break; + } + return ""; + } + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level, + bool Enabled); + + static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level, + bool Enabled); + + static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, + bool Enabled); + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override { + setFeatureEnabledImpl(Features, Name, Enabled); + } + + // This exists purely to cut down on the number of virtual calls in + // initFeatureMap which calls this repeatedly. + static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled); + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool isValidFeatureName(StringRef Name) const override; + + bool hasFeature(StringRef Feature) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + StringRef getABI() const override { + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F) + return "avx512"; + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) + return "avx"; + if (getTriple().getArch() == llvm::Triple::x86 && + MMX3DNowLevel == NoMMX3DNow) + return "no-mmx"; + return ""; + } + + bool isValidCPUName(StringRef Name) const override { + return checkCPUKind(getCPUKind(Name)); + } + + bool setCPU(const std::string &Name) override { + return checkCPUKind(CPU = getCPUKind(Name)); + } + + bool setFPMath(StringRef Name) override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // Most of the non-ARM calling conventions are i386 conventions. + switch (CC) { + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86StdCall: + case CC_X86VectorCall: + case CC_X86RegCall: + case CC_C: + case CC_Swift: + case CC_X86Pascal: + case CC_IntelOclBicc: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return MT == CCMT_Member ? CC_X86ThisCall : CC_C; + } + + bool hasSjLjLowering() const override { return true; } + + void setSupportedOpenCLOpts() override { + getSupportedOpenCLOpts().supportAll(); + } +}; + +// X86-32 generic target +class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo { +public: + X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86TargetInfo(Triple, Opts) { + DoubleAlign = LongLongAlign = 32; + LongDoubleWidth = 96; + LongDoubleAlign = 32; + SuitableAlign = 128; + resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + RegParmMax = 3; + + // Use fpret for all types. + RealTypeUsesObjCFPRet = + ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | + (1 << TargetInfo::LongDouble)); + + // x86-32 has atomics up to 8 bytes + // FIXME: Check that we actually have cmpxchg8b before setting + // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 2; + return -1; + } + + bool validateOperandSize(StringRef Constraint, unsigned Size) const override { + switch (Constraint[0]) { + default: + break; + case 'R': + case 'q': + case 'Q': + case 'a': + case 'b': + case 'c': + case 'd': + case 'S': + case 'D': + return Size <= 32; + case 'A': + return Size <= 64; + } + + return X86TargetInfo::validateOperandSize(Constraint, Size); + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; +}; + +class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo + : public NetBSDTargetInfo<X86_32TargetInfo> { +public: + NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {} + + unsigned getFloatEvalMethod() const override { + unsigned Major, Minor, Micro; + getTriple().getOSVersion(Major, Minor, Micro); + // New NetBSD uses the default rounding mode. + if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0) + return X86_32TargetInfo::getFloatEvalMethod(); + // NetBSD before 6.99.26 defaults to "double" rounding. + return 1; + } +}; + +class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo + : public OpenBSDTargetInfo<X86_32TargetInfo> { +public: + OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinI386TargetInfo + : public DarwinTargetInfo<X86_32TargetInfo> { +public: + DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + SuitableAlign = 128; + MaxVectorAlign = 256; + // The watchOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isWatchOS()) + UseSignedCharForObjCBool = false; + SizeType = UnsignedLong; + IntPtrType = SignedLong; + resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"); + HasAlignMac68kSupport = true; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; + } +}; + +// x86-32 Windows target +class LLVM_LIBRARY_VISIBILITY WindowsX86_32TargetInfo + : public WindowsTargetInfo<X86_32TargetInfo> { +public: + WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) { + DoubleAlign = LongLongAlign = 64; + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + resetDataLayout(IsWinCOFF + ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" + : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); + } +}; + +// x86-32 Windows Visual Studio target +class LLVM_LIBRARY_VISIBILITY MicrosoftX86_32TargetInfo + : public WindowsX86_32TargetInfo { +public: + MicrosoftX86_32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsX86_32TargetInfo(Triple, Opts) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder); + // The value of the following reflects processor type. + // 300=386, 400=486, 500=Pentium, 600=Blend (default) + // We lost the original triple, so we use the default. + Builder.defineMacro("_M_IX86", "600"); + } +}; + +// x86-32 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWX86_32TargetInfo + : public WindowsX86_32TargetInfo { +public: + MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsX86_32TargetInfo(Triple, Opts) { + HasFloat128 = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_X86_"); + } +}; + +// x86-32 Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinX86_32TargetInfo : public X86_32TargetInfo { +public: + CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + DoubleAlign = LongLongAlign = 64; + resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_X86_"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + addCygMingDefines(Opts, Builder); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; + +// x86-32 Haiku target +class LLVM_LIBRARY_VISIBILITY HaikuX86_32TargetInfo + : public HaikuTargetInfo<X86_32TargetInfo> { +public: + HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) {} + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + } +}; + +// X86-32 MCU target +class LLVM_LIBRARY_VISIBILITY MCUX86_32TargetInfo : public X86_32TargetInfo { +public: + MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32"); + WIntType = UnsignedInt; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // On MCU we support only C calling convention. + return CC == CC_C ? CCCR_OK : CCCR_Warning; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__iamcu"); + Builder.defineMacro("__iamcu__"); + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } +}; + +// x86-32 RTEMS target +class LLVM_LIBRARY_VISIBILITY RTEMSX86_32TargetInfo : public X86_32TargetInfo { +public: + RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__rtems__"); + } +}; + +// x86-64 generic target +class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { +public: + X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86TargetInfo(Triple, Opts) { + const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32; + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LargeArrayMinWidth = 128; + LargeArrayAlign = 128; + SuitableAlign = 128; + SizeType = IsX32 ? UnsignedInt : UnsignedLong; + PtrDiffType = IsX32 ? SignedInt : SignedLong; + IntPtrType = IsX32 ? SignedInt : SignedLong; + IntMaxType = IsX32 ? SignedLongLong : SignedLong; + Int64Type = IsX32 ? SignedLongLong : SignedLong; + RegParmMax = 6; + + // Pointers are 32-bit in x32. + resetDataLayout(IsX32 + ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" + : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" + : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"); + + // Use fpret only for long double. + RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); + + // Use fp2ret for _Complex long double. + ComplexLongDoubleUsesFP2Ret = true; + + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + + // x86-64 has atomics up to 16 bytes. + MaxAtomicPromoteWidth = 128; + MaxAtomicInlineWidth = 64; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::X86_64ABIBuiltinVaList; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_X86VectorCall: + case CC_IntelOclBicc: + case CC_Win64: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_X86RegCall: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return CC_C; + } + + // for x32 we need it here explicitly + bool hasInt128Type() const override { return true; } + + unsigned getUnwindWordWidth() const override { return 64; } + + unsigned getRegisterWidth() const override { return 64; } + + bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, + bool &HasSizeMismatch) const override { + // rsp and rbp are the only 64-bit registers the x86 backend can currently + // handle. + if (RegName.equals("rsp") || RegName.equals("rbp")) { + // Check that the register size is 64-bit. + HasSizeMismatch = RegSize != 64; + return true; + } + + // Check if the register is a 32-bit register the backend can handle. + return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, + HasSizeMismatch); + } + + void setMaxAtomicWidth() override { + if (hasFeature("cx16")) + MaxAtomicInlineWidth = 128; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; +}; + +// x86-64 Windows target +class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo + : public WindowsTargetInfo<X86_64TargetInfo> { +public: + WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) { + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + SizeType = UnsignedLongLong; + PtrDiffType = SignedLongLong; + IntPtrType = SignedLongLong; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + return CCCR_Ignore; + case CC_C: + case CC_X86VectorCall: + case CC_IntelOclBicc: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_X86_64SysV: + case CC_Swift: + case CC_X86RegCall: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } +}; + +// x86-64 Windows Visual Studio target +class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo + : public WindowsX86_64TargetInfo { +public: + MicrosoftX86_64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsX86_64TargetInfo(Triple, Opts) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); + Builder.defineMacro("_M_X64", "100"); + Builder.defineMacro("_M_AMD64", "100"); + } +}; + +// x86-64 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWX86_64TargetInfo + : public WindowsX86_64TargetInfo { +public: + MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsX86_64TargetInfo(Triple, Opts) { + // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks + // with x86 FP ops. Weird. + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + HasFloat128 = true; + } +}; + +// x86-64 Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinX86_64TargetInfo : public X86_64TargetInfo { +public: + CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_64TargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + TLSSupported = false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__x86_64__"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN64__"); + addCygMingDefines(Opts, Builder); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinX86_64TargetInfo + : public DarwinTargetInfo<X86_64TargetInfo> { +public: + DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) { + Int64Type = SignedLongLong; + // The 64-bit iOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isiOS()) + UseSignedCharForObjCBool = false; + resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128"); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; + } +}; + +class LLVM_LIBRARY_VISIBILITY OpenBSDX86_64TargetInfo + : public OpenBSDTargetInfo<X86_64TargetInfo> { +public: + OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) { + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + } +}; + +// x86_32 Android target +class LLVM_LIBRARY_VISIBILITY AndroidX86_32TargetInfo + : public LinuxTargetInfo<X86_32TargetInfo> { +public: + AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) { + SuitableAlign = 32; + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } +}; + +// x86_64 Android target +class LLVM_LIBRARY_VISIBILITY AndroidX86_64TargetInfo + : public LinuxTargetInfo<X86_64TargetInfo> { +public: + AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) { + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + } + + bool useFloat128ManglingForLongDouble() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_X86_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.cpp new file mode 100644 index 0000000000000..793dca702dae6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.cpp @@ -0,0 +1,38 @@ +//===--- XCore.cpp - Implement XCore target feature support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements XCore TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "XCore.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsXCore.def" +}; + +void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__XS1B__"); +} + +ArrayRef<Builtin::Info> XCoreTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.h b/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.h new file mode 100644 index 0000000000000..346e0eee15b3b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets/XCore.h @@ -0,0 +1,82 @@ +//===--- XCore.h - Declare XCore target feature support ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares XCore TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + +public: + XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + WCharType = UnsignedChar; + WIntType = UnsignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32" + "-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister + return (RegNo < 2) ? RegNo : -1; + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp index 2c569ff87d8ad..a1a67c2bc144d 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp @@ -36,7 +36,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final/lib/Basic/Version.cpp $"); + StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp index f5db717866a95..9d44597dc3fbb 100644 --- a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp @@ -59,6 +59,7 @@ Status Status::copyWithNewName(const file_status &In, StringRef NewName) { } bool Status::equivalent(const Status &Other) const { + assert(isStatusKnown() && Other.isStatusKnown()); return getUniqueID() == Other.getUniqueID(); } bool Status::isDirectory() const { @@ -243,7 +244,7 @@ public: RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) { if (!EC && Iter != llvm::sys::fs::directory_iterator()) { llvm::sys::fs::file_status S; - EC = Iter->status(S); + EC = llvm::sys::fs::status(Iter->path(), S, true); CurrentEntry = Status::copyWithNewName(S, Iter->path()); } } @@ -257,7 +258,7 @@ public: CurrentEntry = Status(); } else { llvm::sys::fs::file_status S; - EC = Iter->status(S); + EC = llvm::sys::fs::status(Iter->path(), S, true); CurrentEntry = Status::copyWithNewName(S, Iter->path()); } return EC; @@ -492,7 +493,11 @@ std::string InMemoryFileSystem::toString() const { } bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, - std::unique_ptr<llvm::MemoryBuffer> Buffer) { + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User, + Optional<uint32_t> Group, + Optional<llvm::sys::fs::file_type> Type, + Optional<llvm::sys::fs::perms> Perms) { SmallString<128> Path; P.toVector(Path); @@ -508,32 +513,42 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, return false; detail::InMemoryDirectory *Dir = Root.get(); - auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); + auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path); + const auto ResolvedUser = User.getValueOr(0); + const auto ResolvedGroup = Group.getValueOr(0); + const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file); + const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all); + // Any intermediate directories we create should be accessible by + // the owner, even if Perms says otherwise for the final path. + const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all; while (true) { StringRef Name = *I; detail::InMemoryNode *Node = Dir->getChild(Name); ++I; if (!Node) { if (I == E) { - // End of the path, create a new file. - // FIXME: expose the status details in the interface. + // End of the path, create a new file or directory. Status Stat(P.str(), getNextVirtualUniqueID(), - llvm::sys::toTimePoint(ModificationTime), 0, 0, - Buffer->getBufferSize(), - llvm::sys::fs::file_type::regular_file, - llvm::sys::fs::all_all); - Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>( - std::move(Stat), std::move(Buffer))); + llvm::sys::toTimePoint(ModificationTime), ResolvedUser, + ResolvedGroup, Buffer->getBufferSize(), ResolvedType, + ResolvedPerms); + std::unique_ptr<detail::InMemoryNode> Child; + if (ResolvedType == sys::fs::file_type::directory_file) { + Child.reset(new detail::InMemoryDirectory(std::move(Stat))); + } else { + Child.reset(new detail::InMemoryFile(std::move(Stat), + std::move(Buffer))); + } + Dir->addChild(Name, std::move(Child)); return true; } // Create a new directory. Use the path up to here. - // FIXME: expose the status details in the interface. Status Stat( StringRef(Path.str().begin(), Name.end() - Path.str().begin()), - getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), 0, - 0, Buffer->getBufferSize(), llvm::sys::fs::file_type::directory_file, - llvm::sys::fs::all_all); + getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), + ResolvedUser, ResolvedGroup, Buffer->getBufferSize(), + sys::fs::file_type::directory_file, NewDirectoryPerms); Dir = cast<detail::InMemoryDirectory>(Dir->addChild( Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat)))); continue; @@ -557,10 +572,16 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, } bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, - llvm::MemoryBuffer *Buffer) { + llvm::MemoryBuffer *Buffer, + Optional<uint32_t> User, + Optional<uint32_t> Group, + Optional<llvm::sys::fs::file_type> Type, + Optional<llvm::sys::fs::perms> Perms) { return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer( - Buffer->getBuffer(), Buffer->getBufferIdentifier())); + Buffer->getBuffer(), Buffer->getBufferIdentifier()), + std::move(User), std::move(Group), std::move(Type), + std::move(Perms)); } static ErrorOr<detail::InMemoryNode *> diff --git a/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp b/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp index 0a439c7af90df..462777d53400f 100644 --- a/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp @@ -26,11 +26,13 @@ XRayFunctionFilter::ImbueAttribute XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { // First apply the always instrument list, than if it isn't an "always" see // whether it's treated as a "never" instrument function. - if (AlwaysInstrument->inSection("fun", FunctionName, "arg1")) + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", FunctionName, + "arg1")) return ImbueAttribute::ALWAYS_ARG1; - if (AlwaysInstrument->inSection("fun", FunctionName)) + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", + FunctionName)) return ImbueAttribute::ALWAYS; - if (NeverInstrument->inSection("fun", FunctionName)) + if (NeverInstrument->inSection("xray_never_instrument", "fun", FunctionName)) return ImbueAttribute::NEVER; return ImbueAttribute::NONE; } @@ -38,9 +40,11 @@ XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { XRayFunctionFilter::ImbueAttribute XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename, StringRef Category) const { - if (AlwaysInstrument->inSection("src", Filename, Category)) + if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename, + Category)) return ImbueAttribute::ALWAYS; - if (NeverInstrument->inSection("src", Filename, Category)) + if (NeverInstrument->inSection("xray_never_instrument", "src", Filename, + Category)) return ImbueAttribute::NEVER; return ImbueAttribute::NONE; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp index 513896d986345..2c033e0f7c026 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp @@ -44,13 +44,14 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Transforms/Coroutines.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/BoundsChecking.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" @@ -168,7 +169,7 @@ static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder, static void addBoundsCheckingPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createBoundsCheckingPass()); + PM.add(createBoundsCheckingLegacyPass()); } static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, @@ -189,6 +190,8 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard; Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune; Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters; + Opts.PCTable = CGOpts.SanitizeCoveragePCTable; + Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth; PM.add(createSanitizerCoverageModulePass(Opts)); } @@ -234,6 +237,11 @@ static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder, /*Recover*/true)); } +static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM) { + PM.add(createHWAddressSanitizerPass()); +} + static void addMemorySanitizerPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { const PassManagerBuilderWrapper &BuilderWrapper = @@ -334,16 +342,18 @@ static CodeGenOpt::Level getCGOptLevel(const CodeGenOptions &CodeGenOpts) { } } -static llvm::CodeModel::Model getCodeModel(const CodeGenOptions &CodeGenOpts) { - unsigned CodeModel = - llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel) - .Case("small", llvm::CodeModel::Small) - .Case("kernel", llvm::CodeModel::Kernel) - .Case("medium", llvm::CodeModel::Medium) - .Case("large", llvm::CodeModel::Large) - .Case("default", llvm::CodeModel::Default) - .Default(~0u); +static Optional<llvm::CodeModel::Model> +getCodeModel(const CodeGenOptions &CodeGenOpts) { + unsigned CodeModel = llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel) + .Case("small", llvm::CodeModel::Small) + .Case("kernel", llvm::CodeModel::Kernel) + .Case("medium", llvm::CodeModel::Medium) + .Case("large", llvm::CodeModel::Large) + .Case("default", ~1u) + .Default(~0u); assert(CodeModel != ~0u && "invalid code model!"); + if (CodeModel == ~1u) + return None; return static_cast<llvm::CodeModel::Model>(CodeModel); } @@ -419,6 +429,10 @@ static void initTargetOptions(llvm::TargetOptions &Options, if (LangOpts.SjLjExceptions) Options.ExceptionModel = llvm::ExceptionHandling::SjLj; + if (LangOpts.SEHExceptions) + Options.ExceptionModel = llvm::ExceptionHandling::WinEH; + if (LangOpts.DWARFExceptions) + Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI; Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath; Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath; @@ -547,6 +561,13 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM, addKernelAddressSanitizerPasses); } + if (LangOpts.Sanitize.has(SanitizerKind::HWAddress)) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addHWAddressSanitizerPasses); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addHWAddressSanitizerPasses); + } + if (LangOpts.Sanitize.has(SanitizerKind::Memory)) { PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addMemorySanitizerPass); @@ -657,7 +678,7 @@ void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { return; } - llvm::CodeModel::Model CM = getCodeModel(CodeGenOpts); + Optional<llvm::CodeModel::Model> CM = getCodeModel(CodeGenOpts); std::string FeaturesStr = llvm::join(TargetOpts.Features.begin(), TargetOpts.Features.end(), ","); llvm::Reloc::Model RM = getRelocModel(CodeGenOpts); @@ -840,37 +861,44 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( return; TheModule->setDataLayout(TM->createDataLayout()); - PGOOptions PGOOpt; - - // -fprofile-generate. - PGOOpt.RunProfileGen = CodeGenOpts.hasProfileIRInstr(); - if (PGOOpt.RunProfileGen) - PGOOpt.ProfileGenFile = CodeGenOpts.InstrProfileOutput.empty() ? - DefaultProfileGenName : CodeGenOpts.InstrProfileOutput; - - // -fprofile-use. - if (CodeGenOpts.hasProfileIRUse()) - PGOOpt.ProfileUseFile = CodeGenOpts.ProfileInstrumentUsePath; + Optional<PGOOptions> PGOOpt; - if (!CodeGenOpts.SampleProfileFile.empty()) - PGOOpt.SampleProfileFile = CodeGenOpts.SampleProfileFile; + if (CodeGenOpts.hasProfileIRInstr()) + // -fprofile-generate. + PGOOpt = PGOOptions(CodeGenOpts.InstrProfileOutput.empty() + ? DefaultProfileGenName + : CodeGenOpts.InstrProfileOutput, + "", "", true, CodeGenOpts.DebugInfoForProfiling); + else if (CodeGenOpts.hasProfileIRUse()) + // -fprofile-use. + PGOOpt = PGOOptions("", CodeGenOpts.ProfileInstrumentUsePath, "", false, + CodeGenOpts.DebugInfoForProfiling); + else if (!CodeGenOpts.SampleProfileFile.empty()) + // -fprofile-sample-use + PGOOpt = PGOOptions("", "", CodeGenOpts.SampleProfileFile, false, + CodeGenOpts.DebugInfoForProfiling); + else if (CodeGenOpts.DebugInfoForProfiling) + // -fdebug-info-for-profiling + PGOOpt = PGOOptions("", "", "", false, true); - // Only pass a PGO options struct if -fprofile-generate or - // -fprofile-use were passed on the cmdline. - PassBuilder PB(TM.get(), - (PGOOpt.RunProfileGen || - !PGOOpt.ProfileUseFile.empty() || - !PGOOpt.SampleProfileFile.empty()) ? - Optional<PGOOptions>(PGOOpt) : None); + PassBuilder PB(TM.get(), PGOOpt); - LoopAnalysisManager LAM; - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; + LoopAnalysisManager LAM(CodeGenOpts.DebugPassManager); + FunctionAnalysisManager FAM(CodeGenOpts.DebugPassManager); + CGSCCAnalysisManager CGAM(CodeGenOpts.DebugPassManager); + ModuleAnalysisManager MAM(CodeGenOpts.DebugPassManager); // Register the AA manager first so that our version is the one used. FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); + // Register the target library analysis directly and give it a customized + // preset TLI. + Triple TargetTriple(TheModule->getTargetTriple()); + std::unique_ptr<TargetLibraryInfoImpl> TLII( + createTLII(TargetTriple, CodeGenOpts)); + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + MAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + // Register all the basic analyses with the managers. PB.registerModuleAnalyses(MAM); PB.registerCGSCCAnalyses(CGAM); @@ -888,6 +916,12 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // Build a minimal pipeline based on the semantics required by Clang, // which is just that always inlining occurs. MPM.addPass(AlwaysInlinerPass()); + + // At -O0 we directly run necessary sanitizer passes. + if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) + MPM.addPass(createModuleToFunctionPassAdaptor(BoundsCheckingPass())); + + // Lastly, add a semantically necessary pass for ThinLTO. if (IsThinLTO) MPM.addPass(NameAnonGlobalPass()); } else { @@ -895,6 +929,14 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // configure the pipeline. PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts); + // Register callbacks to schedule sanitizer passes at the appropriate part of + // the pipeline. + if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) + PB.registerScalarOptimizerLateEPCallback( + [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { + FPM.addPass(BoundsCheckingPass()); + }); + if (IsThinLTO) { MPM = PB.buildThinLTOPreLinkDefaultPipeline( Level, CodeGenOpts.DebugPassManager); @@ -1062,6 +1104,7 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts); Conf.SampleProfile = std::move(SampleProfile); Conf.UseNewPM = CGOpts.ExperimentalNewPassManager; + Conf.DebugPassManager = CGOpts.DebugPassManager; switch (Action) { case Backend_EmitNothing: Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp index a6e6fec206d57..d90c3a53a635d 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp @@ -15,8 +15,10 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Operator.h" @@ -94,9 +96,8 @@ namespace { BFI.StorageSize = AtomicSizeInBits; BFI.StorageOffset += OffsetInChars; LVal = LValue::MakeBitfield(Address(Addr, lvalue.getAlignment()), - BFI, lvalue.getType(), - lvalue.getBaseInfo()); - LVal.setTBAAInfo(lvalue.getTBAAInfo()); + BFI, lvalue.getType(), lvalue.getBaseInfo(), + lvalue.getTBAAInfo()); AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned); if (AtomicTy.isNull()) { llvm::APInt Size( @@ -359,13 +360,15 @@ static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak, Address Val1, Address Val2, uint64_t Size, llvm::AtomicOrdering SuccessOrder, - llvm::AtomicOrdering FailureOrder) { + llvm::AtomicOrdering FailureOrder, + llvm::SyncScope::ID Scope) { // Note that cmpxchg doesn't support weak cmpxchg, at least at the moment. llvm::Value *Expected = CGF.Builder.CreateLoad(Val1); llvm::Value *Desired = CGF.Builder.CreateLoad(Val2); llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg( - Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder); + Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder, + Scope); Pair->setVolatile(E->isVolatile()); Pair->setWeak(IsWeak); @@ -407,7 +410,8 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, Address Val1, Address Val2, llvm::Value *FailureOrderVal, uint64_t Size, - llvm::AtomicOrdering SuccessOrder) { + llvm::AtomicOrdering SuccessOrder, + llvm::SyncScope::ID Scope) { llvm::AtomicOrdering FailureOrder; if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) { auto FOS = FO->getSExtValue(); @@ -435,7 +439,7 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrder); } emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder, - FailureOrder); + FailureOrder, Scope); return; } @@ -460,13 +464,13 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, // doesn't fold to a constant for the ordering. CGF.Builder.SetInsertPoint(MonotonicBB); emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, - Size, SuccessOrder, llvm::AtomicOrdering::Monotonic); + Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope); CGF.Builder.CreateBr(ContBB); if (AcquireBB) { CGF.Builder.SetInsertPoint(AcquireBB); emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, - Size, SuccessOrder, llvm::AtomicOrdering::Acquire); + Size, SuccessOrder, llvm::AtomicOrdering::Acquire, Scope); CGF.Builder.CreateBr(ContBB); SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::consume), AcquireBB); @@ -476,7 +480,7 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, if (SeqCstBB) { CGF.Builder.SetInsertPoint(SeqCstBB); emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder, - llvm::AtomicOrdering::SequentiallyConsistent); + llvm::AtomicOrdering::SequentiallyConsistent, Scope); CGF.Builder.CreateBr(ContBB); SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst), SeqCstBB); @@ -488,27 +492,31 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, Address Ptr, Address Val1, Address Val2, llvm::Value *IsWeak, llvm::Value *FailureOrder, - uint64_t Size, llvm::AtomicOrdering Order) { + uint64_t Size, llvm::AtomicOrdering Order, + llvm::SyncScope::ID Scope) { llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add; llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: llvm_unreachable("Already handled!"); case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2, - FailureOrder, Size, Order); + FailureOrder, Size, Order, Scope); return; case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2, - FailureOrder, Size, Order); + FailureOrder, Size, Order, Scope); return; case AtomicExpr::AO__atomic_compare_exchange: case AtomicExpr::AO__atomic_compare_exchange_n: { if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) { emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr, - Val1, Val2, FailureOrder, Size, Order); + Val1, Val2, FailureOrder, Size, Order, Scope); } else { // Create all the relevant BB's llvm::BasicBlock *StrongBB = @@ -522,12 +530,12 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, CGF.Builder.SetInsertPoint(StrongBB); emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2, - FailureOrder, Size, Order); + FailureOrder, Size, Order, Scope); CGF.Builder.CreateBr(ContBB); CGF.Builder.SetInsertPoint(WeakBB); emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2, - FailureOrder, Size, Order); + FailureOrder, Size, Order, Scope); CGF.Builder.CreateBr(ContBB); CGF.Builder.SetInsertPoint(ContBB); @@ -535,26 +543,29 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, return; } case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: { llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr); - Load->setAtomic(Order); + Load->setAtomic(Order, Scope); Load->setVolatile(E->isVolatile()); CGF.Builder.CreateStore(Load, Dest); return; } case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: { llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr); - Store->setAtomic(Order); + Store->setAtomic(Order, Scope); Store->setVolatile(E->isVolatile()); return; } case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__atomic_exchange: Op = llvm::AtomicRMWInst::Xchg; @@ -564,6 +575,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Add; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: Op = llvm::AtomicRMWInst::Add; break; @@ -572,14 +584,26 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Sub; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_sub: Op = llvm::AtomicRMWInst::Sub; break; + case AtomicExpr::AO__opencl_atomic_fetch_min: + Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min + : llvm::AtomicRMWInst::UMin; + break; + + case AtomicExpr::AO__opencl_atomic_fetch_max: + Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max + : llvm::AtomicRMWInst::UMax; + break; + case AtomicExpr::AO__atomic_and_fetch: PostOp = llvm::Instruction::And; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: Op = llvm::AtomicRMWInst::And; break; @@ -588,6 +612,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Or; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: Op = llvm::AtomicRMWInst::Or; break; @@ -596,6 +621,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Xor; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_xor: Op = llvm::AtomicRMWInst::Xor; break; @@ -610,7 +636,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); llvm::AtomicRMWInst *RMWI = - CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order); + CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order, Scope); RMWI->setVolatile(E->isVolatile()); // For __atomic_*_fetch operations, perform the operation again to @@ -633,6 +659,61 @@ EmitValToTemp(CodeGenFunction &CGF, Expr *E) { return DeclPtr; } +static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest, + Address Ptr, Address Val1, Address Val2, + llvm::Value *IsWeak, llvm::Value *FailureOrder, + uint64_t Size, llvm::AtomicOrdering Order, + llvm::Value *Scope) { + auto ScopeModel = Expr->getScopeModel(); + + // LLVM atomic instructions always have synch scope. If clang atomic + // expression has no scope operand, use default LLVM synch scope. + if (!ScopeModel) { + EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size, + Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID("")); + return; + } + + // Handle constant scope. + if (auto SC = dyn_cast<llvm::ConstantInt>(Scope)) { + auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID( + ScopeModel->map(SC->getZExtValue()), CGF.CGM.getLLVMContext()); + EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size, + Order, SCID); + return; + } + + // Handle non-constant scope. + auto &Builder = CGF.Builder; + auto Scopes = ScopeModel->getRuntimeValues(); + llvm::DenseMap<unsigned, llvm::BasicBlock *> BB; + for (auto S : Scopes) + BB[S] = CGF.createBasicBlock(getAsString(ScopeModel->map(S)), CGF.CurFn); + + llvm::BasicBlock *ContBB = + CGF.createBasicBlock("atomic.scope.continue", CGF.CurFn); + + auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false); + // If unsupported synch scope is encountered at run time, assume a fallback + // synch scope value. + auto FallBack = ScopeModel->getFallBackValue(); + llvm::SwitchInst *SI = Builder.CreateSwitch(SC, BB[FallBack]); + for (auto S : Scopes) { + auto *B = BB[S]; + if (S != FallBack) + SI->addCase(Builder.getInt32(S), B); + + Builder.SetInsertPoint(B); + EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size, + Order, + CGF.getTargetHooks().getLLVMSyncScopeID(ScopeModel->map(S), + CGF.getLLVMContext())); + Builder.CreateBr(ContBB); + } + + Builder.SetInsertPoint(ContBB); +} + static void AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args, bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy, @@ -663,33 +744,38 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { QualType MemTy = AtomicTy; if (const AtomicType *AT = AtomicTy->getAs<AtomicType>()) MemTy = AT->getValueType(); - CharUnits sizeChars, alignChars; - std::tie(sizeChars, alignChars) = getContext().getTypeInfoInChars(AtomicTy); - uint64_t Size = sizeChars.getQuantity(); - unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth(); - bool UseLibcall = (sizeChars != alignChars || - getContext().toBits(sizeChars) > MaxInlineWidthInBits); - llvm::Value *IsWeak = nullptr, *OrderFail = nullptr; Address Val1 = Address::invalid(); Address Val2 = Address::invalid(); Address Dest = Address::invalid(); - Address Ptr(EmitScalarExpr(E->getPtr()), alignChars); + Address Ptr = EmitPointerWithAlignment(E->getPtr()); + + CharUnits sizeChars, alignChars; + std::tie(sizeChars, alignChars) = getContext().getTypeInfoInChars(AtomicTy); + uint64_t Size = sizeChars.getQuantity(); + unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth(); + bool UseLibcall = ((Ptr.getAlignment() % sizeChars) != 0 || + getContext().toBits(sizeChars) > MaxInlineWidthInBits); - if (E->getOp() == AtomicExpr::AO__c11_atomic_init) { + if (E->getOp() == AtomicExpr::AO__c11_atomic_init || + E->getOp() == AtomicExpr::AO__opencl_atomic_init) { LValue lvalue = MakeAddrLValue(Ptr, AtomicTy); EmitAtomicInit(E->getVal1(), lvalue); return RValue::get(nullptr); } llvm::Value *Order = EmitScalarExpr(E->getOrder()); + llvm::Value *Scope = + E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: llvm_unreachable("Already handled above with EmitAtomicInit!"); case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__atomic_load_n: break; @@ -708,6 +794,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: case AtomicExpr::AO__atomic_compare_exchange_n: case AtomicExpr::AO__atomic_compare_exchange: Val1 = EmitPointerWithAlignment(E->getVal1()); @@ -716,12 +804,15 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { else Val2 = EmitValToTemp(*this, E->getVal2()); OrderFail = EmitScalarExpr(E->getOrderFail()); - if (E->getNumSubExprs() == 6) + if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange_n || + E->getOp() == AtomicExpr::AO__atomic_compare_exchange) IsWeak = EmitScalarExpr(E->getWeak()); break; case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_sub: if (MemTy->isPointerType()) { // For pointer arithmetic, we're required to do a bit of math: // adding 1 to an int* is not the same as adding 1 to a uintptr_t. @@ -744,11 +835,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_store_n: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_xor: @@ -784,18 +882,26 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { bool UseOptimizedLibcall = false; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: llvm_unreachable("Already handled above with EmitAtomicInit!"); case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_nand: case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_xor: case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_and_fetch: @@ -812,6 +918,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__opencl_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: case AtomicExpr::AO__atomic_store_n: @@ -833,7 +944,24 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { getContext().getSizeType()); } // Atomic address is the first or second parameter - Args.add(RValue::get(EmitCastToVoidPtr(Ptr.getPointer())), + // The OpenCL atomic library functions only accept pointer arguments to + // generic address space. + auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) { + if (!E->isOpenCL()) + return V; + auto AS = PT->getAs<PointerType>()->getPointeeType().getAddressSpace(); + if (AS == LangAS::opencl_generic) + return V; + auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic); + auto T = V->getType(); + auto *DestType = T->getPointerElementType()->getPointerTo(DestAS); + + return getTargetHooks().performAddrSpaceCast( + *this, V, AS, LangAS::opencl_generic, DestType, false); + }; + + Args.add(RValue::get(CastToGenericAddrSpace( + EmitCastToVoidPtr(Ptr.getPointer()), E->getPtr()->getType())), getContext().VoidPtrTy); std::string LibCallName; @@ -844,6 +972,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: llvm_unreachable("Already handled!"); // There is only one libcall for compare an exchange, because there is no @@ -855,13 +984,17 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // int success, int failure) case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: case AtomicExpr::AO__atomic_compare_exchange: case AtomicExpr::AO__atomic_compare_exchange_n: LibCallName = "__atomic_compare_exchange"; RetTy = getContext().BoolTy; HaveRetTy = true; - Args.add(RValue::get(EmitCastToVoidPtr(Val1.getPointer())), - getContext().VoidPtrTy); + Args.add( + RValue::get(CastToGenericAddrSpace( + EmitCastToVoidPtr(Val1.getPointer()), E->getVal1()->getType())), + getContext().VoidPtrTy); AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2.getPointer(), MemTy, E->getExprLoc(), sizeChars); Args.add(RValue::get(Order), getContext().IntTy); @@ -871,6 +1004,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // int order) // T __atomic_exchange_N(T *mem, T val, int order) case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__atomic_exchange: LibCallName = "__atomic_exchange"; @@ -880,6 +1014,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // void __atomic_store(size_t size, void *mem, void *val, int order) // void __atomic_store_N(T *mem, T val, int order) case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: LibCallName = "__atomic_store"; @@ -891,6 +1026,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // void __atomic_load(size_t size, void *mem, void *return, int order) // T __atomic_load_N(T *mem, int order) case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__atomic_load: case AtomicExpr::AO__atomic_load_n: LibCallName = "__atomic_load"; @@ -901,6 +1037,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { PostOp = llvm::Instruction::Add; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: LibCallName = "__atomic_fetch_add"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -912,6 +1049,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { PostOp = llvm::Instruction::And; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: LibCallName = "__atomic_fetch_and"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -923,6 +1061,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { PostOp = llvm::Instruction::Or; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: LibCallName = "__atomic_fetch_or"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -934,6 +1073,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { PostOp = llvm::Instruction::Sub; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_sub: LibCallName = "__atomic_fetch_sub"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -945,11 +1085,26 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { PostOp = llvm::Instruction::Xor; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_xor: LibCallName = "__atomic_fetch_xor"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), MemTy, E->getExprLoc(), sizeChars); break; + case AtomicExpr::AO__opencl_atomic_fetch_min: + LibCallName = E->getValueType()->isSignedIntegerType() + ? "__atomic_fetch_min" + : "__atomic_fetch_umin"; + AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), + LoweredMemTy, E->getExprLoc(), sizeChars); + break; + case AtomicExpr::AO__opencl_atomic_fetch_max: + LibCallName = E->getValueType()->isSignedIntegerType() + ? "__atomic_fetch_max" + : "__atomic_fetch_umax"; + AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), + LoweredMemTy, E->getExprLoc(), sizeChars); + break; // T __atomic_nand_fetch_N(T *mem, T val, int order) // T __atomic_fetch_nand_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_nand_fetch: @@ -962,6 +1117,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { break; } + if (E->isOpenCL()) { + LibCallName = std::string("__opencl") + + StringRef(LibCallName).drop_front(1).str(); + + } // Optimized functions have the size in their name. if (UseOptimizedLibcall) LibCallName += "_" + llvm::utostr(Size); @@ -982,6 +1142,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // order is always the last parameter Args.add(RValue::get(Order), getContext().IntTy); + if (E->isOpenCL()) + Args.add(RValue::get(Scope), getContext().IntTy); // PostOp is only needed for the atomic_*_fetch operations, and // thus is only needed for and implemented in the @@ -1018,9 +1180,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { } bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store || + E->getOp() == AtomicExpr::AO__opencl_atomic_store || E->getOp() == AtomicExpr::AO__atomic_store || E->getOp() == AtomicExpr::AO__atomic_store_n; bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load || + E->getOp() == AtomicExpr::AO__opencl_atomic_load || E->getOp() == AtomicExpr::AO__atomic_load || E->getOp() == AtomicExpr::AO__atomic_load_n; @@ -1032,37 +1196,38 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { switch ((llvm::AtomicOrderingCABI)ord) { case llvm::AtomicOrderingCABI::relaxed: EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, - llvm::AtomicOrdering::Monotonic); + llvm::AtomicOrdering::Monotonic, Scope); break; case llvm::AtomicOrderingCABI::consume: case llvm::AtomicOrderingCABI::acquire: if (IsStore) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, - llvm::AtomicOrdering::Acquire); + llvm::AtomicOrdering::Acquire, Scope); break; case llvm::AtomicOrderingCABI::release: if (IsLoad) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, - llvm::AtomicOrdering::Release); + llvm::AtomicOrdering::Release, Scope); break; case llvm::AtomicOrderingCABI::acq_rel: if (IsLoad || IsStore) break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, - llvm::AtomicOrdering::AcquireRelease); + llvm::AtomicOrdering::AcquireRelease, Scope); break; case llvm::AtomicOrderingCABI::seq_cst: EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, - llvm::AtomicOrdering::SequentiallyConsistent); + llvm::AtomicOrdering::SequentiallyConsistent, Scope); break; } if (RValTy->isVoidType()) return RValue::get(nullptr); return convertTempToRValue( - Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo()), + Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo( + Dest.getAddressSpace())), RValTy, E->getExprLoc()); } @@ -1091,13 +1256,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // Emit all the different atomics Builder.SetInsertPoint(MonotonicBB); - EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, - Size, llvm::AtomicOrdering::Monotonic); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, + llvm::AtomicOrdering::Monotonic, Scope); Builder.CreateBr(ContBB); if (!IsStore) { Builder.SetInsertPoint(AcquireBB); - EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, - Size, llvm::AtomicOrdering::Acquire); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, + llvm::AtomicOrdering::Acquire, Scope); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume), AcquireBB); @@ -1106,23 +1271,23 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { } if (!IsLoad) { Builder.SetInsertPoint(ReleaseBB); - EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, - Size, llvm::AtomicOrdering::Release); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, + llvm::AtomicOrdering::Release, Scope); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release), ReleaseBB); } if (!IsLoad && !IsStore) { Builder.SetInsertPoint(AcqRelBB); - EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, - Size, llvm::AtomicOrdering::AcquireRelease); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, + llvm::AtomicOrdering::AcquireRelease, Scope); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel), AcqRelBB); } Builder.SetInsertPoint(SeqCstBB); - EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, - Size, llvm::AtomicOrdering::SequentiallyConsistent); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size, + llvm::AtomicOrdering::SequentiallyConsistent, Scope); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst), SeqCstBB); @@ -1134,7 +1299,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { assert(Atomics.getValueSizeInBits() <= Atomics.getAtomicSizeInBits()); return convertTempToRValue( - Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo()), + Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo( + Dest.getAddressSpace())), RValTy, E->getExprLoc()); } @@ -1181,15 +1347,15 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr, if (LVal.isBitField()) return CGF.EmitLoadOfBitfieldLValue( LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(), - LVal.getBaseInfo()), loc); + LVal.getBaseInfo(), TBAAAccessInfo()), loc); if (LVal.isVectorElt()) return CGF.EmitLoadOfLValue( LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(), - LVal.getBaseInfo()), loc); + LVal.getBaseInfo(), TBAAAccessInfo()), loc); assert(LVal.isExtVectorElt()); return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt( addr, LVal.getExtVectorElts(), LVal.getType(), - LVal.getBaseInfo())); + LVal.getBaseInfo(), TBAAAccessInfo())); } RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal, @@ -1260,8 +1426,7 @@ llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO, // Other decoration. if (IsVolatile) Load->setVolatile(true); - if (LVal.getTBAAInfo()) - CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo()); + CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo()); return Load; } @@ -1506,29 +1671,30 @@ EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal, UpdateLVal = LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); DesiredLVal = LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(), - AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getType(), AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); } else if (AtomicLVal.isVectorElt()) { UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); DesiredLVal = LValue::MakeVectorElt( DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo()); } else { assert(AtomicLVal.isExtVectorElt()); UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); DesiredLVal = LValue::MakeExtVectorElt( DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo()); } - UpdateLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); - DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation()); } // Store new value in the corresponding memory area @@ -1611,20 +1777,19 @@ static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, if (AtomicLVal.isBitField()) { DesiredLVal = LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(), - AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getType(), AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); } else if (AtomicLVal.isVectorElt()) { DesiredLVal = LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(), - AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getType(), AtomicLVal.getBaseInfo(), + AtomicLVal.getTBAAInfo()); } else { assert(AtomicLVal.isExtVectorElt()); DesiredLVal = LValue::MakeExtVectorElt( DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(), - AtomicLVal.getBaseInfo()); + AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo()); } - DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); // Store new value in the corresponding memory area assert(UpdateRVal.isScalar()); CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal); @@ -1777,8 +1942,7 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, // Other decoration. if (IsVolatile) store->setVolatile(true); - if (dest.getTBAAInfo()) - CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo()); + CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo()); return; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 1810489578798..5f73d4cf79137 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp @@ -14,10 +14,13 @@ #include "CGBlocks.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" +#include "CGOpenCLRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "clang/CodeGen/ConstantInitBuilder.h" +#include "ConstantEmitter.h" +#include "TargetInfo.h" #include "clang/AST/DeclObjC.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/SmallSet.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" @@ -290,7 +293,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM, const Expr *init = var->getInit(); if (!init) return nullptr; - return CGM.EmitConstantInit(*var, CGF); + return ConstantEmitter(CGM, CGF).tryEmitAbstractForInitializer(*var); } /// Get the low bit of a nonzero character count. This is the @@ -301,21 +304,57 @@ static CharUnits getLowBit(CharUnits v) { static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, SmallVectorImpl<llvm::Type*> &elementTypes) { - // The header is basically 'struct { void *; int; int; void *; void *; }'. - // Assert that that struct is packed. - assert(CGM.getIntSize() <= CGM.getPointerSize()); - assert(CGM.getIntAlign() <= CGM.getPointerAlign()); - assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign())); - - info.BlockAlign = CGM.getPointerAlign(); - info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize(); assert(elementTypes.empty()); - elementTypes.push_back(CGM.VoidPtrTy); - elementTypes.push_back(CGM.IntTy); - elementTypes.push_back(CGM.IntTy); - elementTypes.push_back(CGM.VoidPtrTy); - elementTypes.push_back(CGM.getBlockDescriptorType()); + if (CGM.getLangOpts().OpenCL) { + // The header is basically 'struct { int; int; generic void *; + // custom_fields; }'. Assert that struct is packed. + auto GenericAS = + CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic); + auto GenPtrAlign = + CharUnits::fromQuantity(CGM.getTarget().getPointerAlign(GenericAS) / 8); + auto GenPtrSize = + CharUnits::fromQuantity(CGM.getTarget().getPointerWidth(GenericAS) / 8); + assert(CGM.getIntSize() <= GenPtrSize); + assert(CGM.getIntAlign() <= GenPtrAlign); + assert((2 * CGM.getIntSize()).isMultipleOf(GenPtrAlign)); + elementTypes.push_back(CGM.IntTy); /* total size */ + elementTypes.push_back(CGM.IntTy); /* align */ + elementTypes.push_back( + CGM.getOpenCLRuntime() + .getGenericVoidPointerType()); /* invoke function */ + unsigned Offset = + 2 * CGM.getIntSize().getQuantity() + GenPtrSize.getQuantity(); + unsigned BlockAlign = GenPtrAlign.getQuantity(); + if (auto *Helper = + CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { + for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ { + // TargetOpenCLBlockHelp needs to make sure the struct is packed. + // If necessary, add padding fields to the custom fields. + unsigned Align = CGM.getDataLayout().getABITypeAlignment(I); + if (BlockAlign < Align) + BlockAlign = Align; + assert(Offset % Align == 0); + Offset += CGM.getDataLayout().getTypeAllocSize(I); + elementTypes.push_back(I); + } + } + info.BlockAlign = CharUnits::fromQuantity(BlockAlign); + info.BlockSize = CharUnits::fromQuantity(Offset); + } else { + // The header is basically 'struct { void *; int; int; void *; void *; }'. + // Assert that that struct is packed. + assert(CGM.getIntSize() <= CGM.getPointerSize()); + assert(CGM.getIntAlign() <= CGM.getPointerAlign()); + assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign())); + info.BlockAlign = CGM.getPointerAlign(); + info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize(); + elementTypes.push_back(CGM.VoidPtrTy); + elementTypes.push_back(CGM.IntTy); + elementTypes.push_back(CGM.IntTy); + elementTypes.push_back(CGM.VoidPtrTy); + elementTypes.push_back(CGM.getBlockDescriptorType()); + } } static QualType getCaptureFieldType(const CodeGenFunction &CGF, @@ -340,8 +379,12 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, SmallVector<llvm::Type*, 8> elementTypes; initializeForBlockHeader(CGM, info, elementTypes); - - if (!block->hasCaptures()) { + bool hasNonConstantCustomFields = false; + if (auto *OpenCLHelper = + CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) + hasNonConstantCustomFields = + !OpenCLHelper->areAllCustomFieldValuesConstant(info); + if (!block->hasCaptures() && !hasNonConstantCustomFields) { info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); info.CanBeGlobal = true; @@ -697,16 +740,27 @@ void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) { } /// Emit a block literal expression in the current function. -llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { +llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr, + llvm::Function **InvokeF) { // If the block has no captures, we won't have a pre-computed // layout for it. if (!blockExpr->getBlockDecl()->hasCaptures()) { - if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) + // The block literal is emitted as a global variable, and the block invoke + // function has to be extracted from its initializer. + if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) { + if (InvokeF) { + auto *GV = cast<llvm::GlobalVariable>( + cast<llvm::Constant>(Block)->stripPointerCasts()); + auto *BlockInit = cast<llvm::ConstantStruct>(GV->getInitializer()); + *InvokeF = cast<llvm::Function>( + BlockInit->getAggregateElement(2)->stripPointerCasts()); + } return Block; + } CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName()); computeBlockInfo(CGM, this, blockInfo); blockInfo.BlockExpression = blockExpr; - return EmitBlockLiteral(blockInfo); + return EmitBlockLiteral(blockInfo, InvokeF); } // Find the block info for this block and take ownership of it. @@ -715,44 +769,59 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { blockExpr->getBlockDecl())); blockInfo->BlockExpression = blockExpr; - return EmitBlockLiteral(*blockInfo); + return EmitBlockLiteral(*blockInfo, InvokeF); } -llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { +llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo, + llvm::Function **InvokeF) { + bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL; + auto GenVoidPtrTy = + IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy; + LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default; + auto GenVoidPtrSize = CharUnits::fromQuantity( + CGM.getTarget().getPointerWidth( + CGM.getContext().getTargetAddressSpace(GenVoidPtrAddr)) / + 8); // Using the computed layout, generate the actual block function. bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda(); - llvm::Constant *blockFn - = CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo, - LocalDeclMap, - isLambdaConv); - blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); + CodeGenFunction BlockCGF{CGM, true}; + BlockCGF.SanOpts = SanOpts; + auto *InvokeFn = BlockCGF.GenerateBlockFunction( + CurGD, blockInfo, LocalDeclMap, isLambdaConv, blockInfo.CanBeGlobal); + if (InvokeF) + *InvokeF = InvokeFn; + auto *blockFn = llvm::ConstantExpr::getPointerCast(InvokeFn, GenVoidPtrTy); // If there is nothing to capture, we can emit this as a global block. if (blockInfo.CanBeGlobal) - return buildGlobalBlock(CGM, blockInfo, blockFn); + return CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression); // Otherwise, we have to emit this as a local block. - llvm::Constant *isa = - (!CGM.getContext().getLangOpts().OpenCL) - ? CGM.getNSConcreteStackBlock() - : CGM.getNullPointer(VoidPtrPtrTy, - CGM.getContext().getPointerType( - QualType(CGM.getContext().VoidPtrTy))); - isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy); - - // Build the block descriptor. - llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo); - Address blockAddr = blockInfo.LocalAddress; assert(blockAddr.isValid() && "block has no address!"); - // Compute the initial on-stack block flags. - BlockFlags flags = BLOCK_HAS_SIGNATURE; - if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; - if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; - if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; - if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; + llvm::Constant *isa; + llvm::Constant *descriptor; + BlockFlags flags; + if (!IsOpenCL) { + isa = llvm::ConstantExpr::getBitCast(CGM.getNSConcreteStackBlock(), + VoidPtrTy); + + // Build the block descriptor. + descriptor = buildBlockDescriptor(CGM, blockInfo); + + // Compute the initial on-stack block flags. + flags = BLOCK_HAS_SIGNATURE; + if (blockInfo.HasCapturedVariableLayout) + flags |= BLOCK_HAS_EXTENDED_LAYOUT; + if (blockInfo.NeedsCopyDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; + if (blockInfo.HasCXXObject) + flags |= BLOCK_HAS_CXX_OBJ; + if (blockInfo.UsesStret) + flags |= BLOCK_USE_STRET; + } auto projectField = [&](unsigned index, CharUnits offset, const Twine &name) -> Address { @@ -776,13 +845,33 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { index++; }; - addHeaderField(isa, getPointerSize(), "block.isa"); - addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()), - getIntSize(), "block.flags"); - addHeaderField(llvm::ConstantInt::get(IntTy, 0), - getIntSize(), "block.reserved"); - addHeaderField(blockFn, getPointerSize(), "block.invoke"); - addHeaderField(descriptor, getPointerSize(), "block.descriptor"); + if (!IsOpenCL) { + addHeaderField(isa, getPointerSize(), "block.isa"); + addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()), + getIntSize(), "block.flags"); + addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(), + "block.reserved"); + } else { + addHeaderField( + llvm::ConstantInt::get(IntTy, blockInfo.BlockSize.getQuantity()), + getIntSize(), "block.size"); + addHeaderField( + llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()), + getIntSize(), "block.align"); + } + addHeaderField(blockFn, GenVoidPtrSize, "block.invoke"); + if (!IsOpenCL) + addHeaderField(descriptor, getPointerSize(), "block.descriptor"); + else if (auto *Helper = + CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { + for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) { + addHeaderField( + I.first, + CharUnits::fromQuantity( + CGM.getDataLayout().getTypeAllocSize(I.first->getType())), + I.second); + } + } } // Finally, capture all the values into the block. @@ -917,9 +1006,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // FIXME: Pass a specific location for the expr init so that the store is // attributed to a reasonable location - otherwise it may be attributed to // locations of subexpressions in the initialization. - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); EmitExprAsInit(&l2r, &BlockFieldPseudoVar, - MakeAddrLValue(blockField, type, BaseInfo), + MakeAddrLValue(blockField, type, AlignmentSource::Decl), /*captured by init*/ false); } @@ -978,21 +1066,38 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() { llvm::Type *BlockDescPtrTy = getBlockDescriptorType(); - // struct __block_literal_generic { - // void *__isa; - // int __flags; - // int __reserved; - // void (*__invoke)(void *); - // struct __block_descriptor *__descriptor; - // }; - GenericBlockLiteralType = - llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy, - IntTy, IntTy, VoidPtrTy, BlockDescPtrTy); + if (getLangOpts().OpenCL) { + // struct __opencl_block_literal_generic { + // int __size; + // int __align; + // __generic void *__invoke; + // /* custom fields */ + // }; + SmallVector<llvm::Type *, 8> StructFields( + {IntTy, IntTy, getOpenCLRuntime().getGenericVoidPointerType()}); + if (auto *Helper = getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { + for (auto I : Helper->getCustomFieldTypes()) + StructFields.push_back(I); + } + GenericBlockLiteralType = llvm::StructType::create( + StructFields, "struct.__opencl_block_literal_generic"); + } else { + // struct __block_literal_generic { + // void *__isa; + // int __flags; + // int __reserved; + // void (*__invoke)(void *); + // struct __block_descriptor *__descriptor; + // }; + GenericBlockLiteralType = + llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy, + IntTy, IntTy, VoidPtrTy, BlockDescPtrTy); + } return GenericBlockLiteralType; } -RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, +RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { const BlockPointerType *BPT = E->getCallee()->getType()->getAs<BlockPointerType>(); @@ -1017,8 +1122,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, // Get the function pointer from the literal. llvm::Value *FuncPtr = - Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, 3); - + Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, + CGM.getLangOpts().OpenCL ? 2 : 3); // Add the block literal. CallArgList Args; @@ -1026,8 +1131,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, QualType VoidPtrQualTy = getContext().VoidPtrTy; llvm::Type *GenericVoidPtrTy = VoidPtrTy; if (getLangOpts().OpenCL) { - GenericVoidPtrTy = Builder.getInt8PtrTy( - getContext().getTargetAddressSpace(LangAS::opencl_generic)); + GenericVoidPtrTy = CGM.getOpenCLRuntime().getGenericVoidPointerType(); VoidPtrQualTy = getContext().getPointerType(getContext().getAddrSpaceQualType( getContext().VoidTy, LangAS::opencl_generic)); @@ -1052,7 +1156,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo); llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); - Func = Builder.CreateBitCast(Func, BlockFTyPtr); + Func = Builder.CreatePointerCast(Func, BlockFTyPtr); // Prepare the callee. CGCallee Callee(CGCalleeInfo(), Func); @@ -1087,8 +1191,8 @@ Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable, variable->getName()); } - if (auto refType = capture.fieldType()->getAs<ReferenceType>()) - addr = EmitLoadOfReference(addr, refType); + if (capture.fieldType()->isReferenceType()) + addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType())); return addr; } @@ -1113,17 +1217,14 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, computeBlockInfo(*this, nullptr, blockInfo); // Using that metadata, generate the actual block function. - llvm::Constant *blockFn; { CodeGenFunction::DeclMapTy LocalDeclMap; - blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(), - blockInfo, - LocalDeclMap, - false); + CodeGenFunction(*this).GenerateBlockFunction( + GlobalDecl(), blockInfo, LocalDeclMap, + /*IsLambdaConversionToBlock*/ false, /*BuildGlobalBlock*/ true); } - blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); - return buildGlobalBlock(*this, blockInfo, blockFn); + return getAddrOfGlobalBlockIfEmitted(BE); } static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, @@ -1140,27 +1241,37 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, ConstantInitBuilder builder(CGM); auto fields = builder.beginStruct(); - // isa - fields.add((!CGM.getContext().getLangOpts().OpenCL) - ? CGM.getNSConcreteGlobalBlock() - : CGM.getNullPointer(CGM.VoidPtrPtrTy, - CGM.getContext().getPointerType(QualType( - CGM.getContext().VoidPtrTy)))); + bool IsOpenCL = CGM.getLangOpts().OpenCL; + if (!IsOpenCL) { + // isa + fields.add(CGM.getNSConcreteGlobalBlock()); + + // __flags + BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; + if (blockInfo.UsesStret) + flags |= BLOCK_USE_STRET; - // __flags - BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; - if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; - - fields.addInt(CGM.IntTy, flags.getBitMask()); + fields.addInt(CGM.IntTy, flags.getBitMask()); - // Reserved - fields.addInt(CGM.IntTy, 0); + // Reserved + fields.addInt(CGM.IntTy, 0); + } else { + fields.addInt(CGM.IntTy, blockInfo.BlockSize.getQuantity()); + fields.addInt(CGM.IntTy, blockInfo.BlockAlign.getQuantity()); + } // Function fields.add(blockFn); - // Descriptor - fields.add(buildBlockDescriptor(CGM, blockInfo)); + if (!IsOpenCL) { + // Descriptor + fields.add(buildBlockDescriptor(CGM, blockInfo)); + } else if (auto *Helper = + CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { + for (auto I : Helper->getCustomFieldValues(CGM, blockInfo)) { + fields.add(I); + } + } unsigned AddrSpace = 0; if (CGM.getContext().getLangOpts().OpenCL) @@ -1184,20 +1295,17 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D, llvm::Value *arg) { assert(BlockInfo && "not emitting prologue of block invocation function?!"); - llvm::Value *localAddr = nullptr; - if (CGM.getCodeGenOpts().OptimizationLevel == 0) { - // Allocate a stack slot to let the debug info survive the RA. - Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); - Builder.CreateStore(arg, alloc); - localAddr = Builder.CreateLoad(alloc); - } - + // Allocate a stack slot like for any local variable to guarantee optimal + // debug info at -O0. The mem2reg pass will eliminate it when optimizing. + Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); + Builder.CreateStore(arg, alloc); if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { DI->setLocation(D->getLocation()); - DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, arg, argNum, - localAddr, Builder); + DI->EmitDeclareOfBlockLiteralArgVariable( + *BlockInfo, D->getName(), argNum, + cast<llvm::AllocaInst>(alloc.getPointer()), Builder); } } @@ -1225,7 +1333,8 @@ llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &blockInfo, const DeclMapTy &ldm, - bool IsLambdaConversionToBlock) { + bool IsLambdaConversionToBlock, + bool BuildGlobalBlock) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); CurGD = GD; @@ -1284,6 +1393,14 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule()); CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo); + if (BuildGlobalBlock) { + auto GenVoidPtrTy = getContext().getLangOpts().OpenCL + ? CGM.getOpenCLRuntime().getGenericVoidPointerType() + : VoidPtrTy; + buildGlobalBlock(CGM, blockInfo, + llvm::ConstantExpr::getPointerCast(fn, GenVoidPtrTy)); + } + // Begin generating the function. StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args, blockDecl->getLocation(), @@ -1529,10 +1646,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); - auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(FD, C.VoidTy, Fn, FI, args); - // Create a scope with an artificial location for the body of this function. - auto AL = ApplyDebugLocation::CreateArtificial(*this); + ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); Address src = GetAddrOfLocalVar(&SrcDecl); @@ -1701,10 +1816,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { CGM.SetInternalFunctionAttributes(nullptr, Fn, FI); - // Create a scope with an artificial location for the body of this function. - auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(FD, C.VoidTy, Fn, FI, args); - auto AL = ApplyDebugLocation::CreateArtificial(*this); + ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuilder.h b/contrib/llvm/tools/clang/lib/CodeGen/CGBuilder.h index 42f9a428bb3a7..61fe4aac3afa2 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuilder.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuilder.h @@ -145,6 +145,13 @@ public: Addr.getAlignment()); } + using CGBuilderBaseTy::CreateAddrSpaceCast; + Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty, + const llvm::Twine &Name = "") { + return Address(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name), + Addr.getAlignment()); + } + /// Cast the element type of the given address to a different type, /// preserving information like the alignment and address space. Address CreateElementBitCast(Address Addr, llvm::Type *Ty, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp index f3527b0f39d13..3ecd1c6697d71 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -16,6 +16,7 @@ #include "CGOpenCLRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -29,6 +30,9 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetParser.h" #include <sstream> using namespace clang; @@ -641,6 +645,287 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup { }; } +Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E, + BuiltinCheckKind Kind) { + assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero) + && "Unsupported builtin check kind"); + + Value *ArgValue = EmitScalarExpr(E); + if (!SanOpts.has(SanitizerKind::Builtin) || !getTarget().isCLZForZeroUndef()) + return ArgValue; + + SanitizerScope SanScope(this); + Value *Cond = Builder.CreateICmpNE( + ArgValue, llvm::Constant::getNullValue(ArgValue->getType())); + EmitCheck(std::make_pair(Cond, SanitizerKind::Builtin), + SanitizerHandler::InvalidBuiltin, + {EmitCheckSourceLocation(E->getExprLoc()), + llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)}, + None); + return ArgValue; +} + +/// Get the argument type for arguments to os_log_helper. +static CanQualType getOSLogArgType(ASTContext &C, int Size) { + QualType UnsignedTy = C.getIntTypeForBitwidth(Size * 8, /*Signed=*/false); + return C.getCanonicalType(UnsignedTy); +} + +llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction( + const analyze_os_log::OSLogBufferLayout &Layout, + CharUnits BufferAlignment) { + ASTContext &Ctx = getContext(); + + llvm::SmallString<64> Name; + { + raw_svector_ostream OS(Name); + OS << "__os_log_helper"; + OS << "_" << BufferAlignment.getQuantity(); + OS << "_" << int(Layout.getSummaryByte()); + OS << "_" << int(Layout.getNumArgsByte()); + for (const auto &Item : Layout.Items) + OS << "_" << int(Item.getSizeByte()) << "_" + << int(Item.getDescriptorByte()); + } + + if (llvm::Function *F = CGM.getModule().getFunction(Name)) + return F; + + llvm::SmallVector<ImplicitParamDecl, 4> Params; + Params.emplace_back(Ctx, nullptr, SourceLocation(), &Ctx.Idents.get("buffer"), + Ctx.VoidPtrTy, ImplicitParamDecl::Other); + + for (unsigned int I = 0, E = Layout.Items.size(); I < E; ++I) { + char Size = Layout.Items[I].getSizeByte(); + if (!Size) + continue; + + Params.emplace_back( + Ctx, nullptr, SourceLocation(), + &Ctx.Idents.get(std::string("arg") + llvm::to_string(I)), + getOSLogArgType(Ctx, Size), ImplicitParamDecl::Other); + } + + FunctionArgList Args; + for (auto &P : Params) + Args.push_back(&P); + + // The helper function has linkonce_odr linkage to enable the linker to merge + // identical functions. To ensure the merging always happens, 'noinline' is + // attached to the function when compiling with -Oz. + const CGFunctionInfo &FI = + CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); + llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI); + llvm::Function *Fn = llvm::Function::Create( + FuncTy, llvm::GlobalValue::LinkOnceODRLinkage, Name, &CGM.getModule()); + Fn->setVisibility(llvm::GlobalValue::HiddenVisibility); + CGM.SetLLVMFunctionAttributes(nullptr, FI, Fn); + CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn); + + // Attach 'noinline' at -Oz. + if (CGM.getCodeGenOpts().OptimizeSize == 2) + Fn->addFnAttr(llvm::Attribute::NoInline); + + auto NL = ApplyDebugLocation::CreateEmpty(*this); + IdentifierInfo *II = &Ctx.Idents.get(Name); + FunctionDecl *FD = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, + Ctx.VoidTy, nullptr, SC_PrivateExtern, false, false); + + StartFunction(FD, Ctx.VoidTy, Fn, FI, Args); + + // Create a scope with an artificial location for the body of this function. + auto AL = ApplyDebugLocation::CreateArtificial(*this); + + CharUnits Offset; + Address BufAddr(Builder.CreateLoad(GetAddrOfLocalVar(&Params[0]), "buf"), + BufferAlignment); + Builder.CreateStore(Builder.getInt8(Layout.getSummaryByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "summary")); + Builder.CreateStore(Builder.getInt8(Layout.getNumArgsByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs")); + + unsigned I = 1; + for (const auto &Item : Layout.Items) { + Builder.CreateStore( + Builder.getInt8(Item.getDescriptorByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor")); + Builder.CreateStore( + Builder.getInt8(Item.getSizeByte()), + Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize")); + + CharUnits Size = Item.size(); + if (!Size.getQuantity()) + continue; + + Address Arg = GetAddrOfLocalVar(&Params[I]); + Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset, "argData"); + Addr = Builder.CreateBitCast(Addr, Arg.getPointer()->getType(), + "argDataCast"); + Builder.CreateStore(Builder.CreateLoad(Arg), Addr); + Offset += Size; + ++I; + } + + FinishFunction(); + + return Fn; +} + +RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { + assert(E.getNumArgs() >= 2 && + "__builtin_os_log_format takes at least 2 arguments"); + ASTContext &Ctx = getContext(); + analyze_os_log::OSLogBufferLayout Layout; + analyze_os_log::computeOSLogBufferLayout(Ctx, &E, Layout); + Address BufAddr = EmitPointerWithAlignment(E.getArg(0)); + llvm::SmallVector<llvm::Value *, 4> RetainableOperands; + + // Ignore argument 1, the format string. It is not currently used. + CallArgList Args; + Args.add(RValue::get(BufAddr.getPointer()), Ctx.VoidPtrTy); + + for (const auto &Item : Layout.Items) { + int Size = Item.getSizeByte(); + if (!Size) + continue; + + llvm::Value *ArgVal; + + if (const Expr *TheExpr = Item.getExpr()) { + ArgVal = EmitScalarExpr(TheExpr, /*Ignore*/ false); + + // Check if this is a retainable type. + if (TheExpr->getType()->isObjCRetainableType()) { + assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar && + "Only scalar can be a ObjC retainable type"); + // Check if the object is constant, if not, save it in + // RetainableOperands. + if (!isa<Constant>(ArgVal)) + RetainableOperands.push_back(ArgVal); + } + } else { + ArgVal = Builder.getInt32(Item.getConstValue().getQuantity()); + } + + unsigned ArgValSize = + CGM.getDataLayout().getTypeSizeInBits(ArgVal->getType()); + llvm::IntegerType *IntTy = llvm::Type::getIntNTy(getLLVMContext(), + ArgValSize); + ArgVal = Builder.CreateBitOrPointerCast(ArgVal, IntTy); + CanQualType ArgTy = getOSLogArgType(Ctx, Size); + // If ArgVal has type x86_fp80, zero-extend ArgVal. + ArgVal = Builder.CreateZExtOrBitCast(ArgVal, ConvertType(ArgTy)); + Args.add(RValue::get(ArgVal), ArgTy); + } + + const CGFunctionInfo &FI = + CGM.getTypes().arrangeBuiltinFunctionCall(Ctx.VoidTy, Args); + llvm::Function *F = CodeGenFunction(CGM).generateBuiltinOSLogHelperFunction( + Layout, BufAddr.getAlignment()); + EmitCall(FI, CGCallee::forDirect(F), ReturnValueSlot(), Args); + + // Push a clang.arc.use cleanup for each object in RetainableOperands. The + // cleanup will cause the use to appear after the final log call, keeping + // the object valid while it’s held in the log buffer. Note that if there’s + // a release cleanup on the object, it will already be active; since + // cleanups are emitted in reverse order, the use will occur before the + // object is released. + if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount && + CGM.getCodeGenOpts().OptimizationLevel != 0) + for (llvm::Value *Object : RetainableOperands) + pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), Object); + + return RValue::get(BufAddr.getPointer()); +} + +/// Determine if a binop is a checked mixed-sign multiply we can specialize. +static bool isSpecialMixedSignMultiply(unsigned BuiltinID, + WidthAndSignedness Op1Info, + WidthAndSignedness Op2Info, + WidthAndSignedness ResultInfo) { + return BuiltinID == Builtin::BI__builtin_mul_overflow && + Op1Info.Width == Op2Info.Width && Op1Info.Width >= ResultInfo.Width && + Op1Info.Signed != Op2Info.Signed; +} + +/// Emit a checked mixed-sign multiply. This is a cheaper specialization of +/// the generic checked-binop irgen. +static RValue +EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, + WidthAndSignedness Op1Info, const clang::Expr *Op2, + WidthAndSignedness Op2Info, + const clang::Expr *ResultArg, QualType ResultQTy, + WidthAndSignedness ResultInfo) { + assert(isSpecialMixedSignMultiply(Builtin::BI__builtin_mul_overflow, Op1Info, + Op2Info, ResultInfo) && + "Not a mixed-sign multipliction we can specialize"); + + // Emit the signed and unsigned operands. + const clang::Expr *SignedOp = Op1Info.Signed ? Op1 : Op2; + const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1; + llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp); + llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp); + + llvm::Type *OpTy = Signed->getType(); + llvm::Value *Zero = llvm::Constant::getNullValue(OpTy); + Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); + llvm::Type *ResTy = ResultPtr.getElementType(); + + // Take the absolute value of the signed operand. + llvm::Value *IsNegative = CGF.Builder.CreateICmpSLT(Signed, Zero); + llvm::Value *AbsOfNegative = CGF.Builder.CreateSub(Zero, Signed); + llvm::Value *AbsSigned = + CGF.Builder.CreateSelect(IsNegative, AbsOfNegative, Signed); + + // Perform a checked unsigned multiplication. + llvm::Value *UnsignedOverflow; + llvm::Value *UnsignedResult = + EmitOverflowIntrinsic(CGF, llvm::Intrinsic::umul_with_overflow, AbsSigned, + Unsigned, UnsignedOverflow); + + llvm::Value *Overflow, *Result; + if (ResultInfo.Signed) { + // Signed overflow occurs if the result is greater than INT_MAX or lesser + // than INT_MIN, i.e when |Result| > (INT_MAX + IsNegative). + auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Width) + .zextOrSelf(Op1Info.Width); + llvm::Value *MaxResult = + CGF.Builder.CreateAdd(llvm::ConstantInt::get(OpTy, IntMax), + CGF.Builder.CreateZExt(IsNegative, OpTy)); + llvm::Value *SignedOverflow = + CGF.Builder.CreateICmpUGT(UnsignedResult, MaxResult); + Overflow = CGF.Builder.CreateOr(UnsignedOverflow, SignedOverflow); + + // Prepare the signed result (possibly by negating it). + llvm::Value *NegativeResult = CGF.Builder.CreateNeg(UnsignedResult); + llvm::Value *SignedResult = + CGF.Builder.CreateSelect(IsNegative, NegativeResult, UnsignedResult); + Result = CGF.Builder.CreateTrunc(SignedResult, ResTy); + } else { + // Unsigned overflow occurs if the result is < 0 or greater than UINT_MAX. + llvm::Value *Underflow = CGF.Builder.CreateAnd( + IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult)); + Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow); + if (ResultInfo.Width < Op1Info.Width) { + auto IntMax = + llvm::APInt::getMaxValue(ResultInfo.Width).zext(Op1Info.Width); + llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT( + UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax)); + Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow); + } + + Result = CGF.Builder.CreateTrunc(UnsignedResult, ResTy); + } + assert(Overflow && Result && "Missing overflow or result"); + + bool isVolatile = + ResultArg->getType()->getPointeeType().isVolatileQualified(); + CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr, + isVolatile); + return RValue::get(Overflow); +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -656,11 +941,196 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Result.Val.getFloat())); } + // There are LLVM math intrinsics/instructions corresponding to math library + // functions except the LLVM op will never set errno while the math library + // might. Also, math builtins have the same semantics as their math library + // twins. Thus, we can transform math library and builtin calls to their + // LLVM counterparts if the call is marked 'const' (known to never set errno). + if (FD->hasAttr<ConstAttr>()) { + switch (BuiltinID) { + case Builtin::BIceil: + case Builtin::BIceilf: + case Builtin::BIceill: + case Builtin::BI__builtin_ceil: + case Builtin::BI__builtin_ceilf: + case Builtin::BI__builtin_ceill: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil)); + + case Builtin::BIcopysign: + case Builtin::BIcopysignf: + case Builtin::BIcopysignl: + case Builtin::BI__builtin_copysign: + case Builtin::BI__builtin_copysignf: + case Builtin::BI__builtin_copysignl: + return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::copysign)); + + case Builtin::BIcos: + case Builtin::BIcosf: + case Builtin::BIcosl: + case Builtin::BI__builtin_cos: + case Builtin::BI__builtin_cosf: + case Builtin::BI__builtin_cosl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos)); + + case Builtin::BIexp: + case Builtin::BIexpf: + case Builtin::BIexpl: + case Builtin::BI__builtin_exp: + case Builtin::BI__builtin_expf: + case Builtin::BI__builtin_expl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp)); + + case Builtin::BIexp2: + case Builtin::BIexp2f: + case Builtin::BIexp2l: + case Builtin::BI__builtin_exp2: + case Builtin::BI__builtin_exp2f: + case Builtin::BI__builtin_exp2l: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2)); + + case Builtin::BIfabs: + case Builtin::BIfabsf: + case Builtin::BIfabsl: + case Builtin::BI__builtin_fabs: + case Builtin::BI__builtin_fabsf: + case Builtin::BI__builtin_fabsl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::fabs)); + + case Builtin::BIfloor: + case Builtin::BIfloorf: + case Builtin::BIfloorl: + case Builtin::BI__builtin_floor: + case Builtin::BI__builtin_floorf: + case Builtin::BI__builtin_floorl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor)); + + case Builtin::BIfma: + case Builtin::BIfmaf: + case Builtin::BIfmal: + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma)); + + case Builtin::BIfmax: + case Builtin::BIfmaxf: + case Builtin::BIfmaxl: + case Builtin::BI__builtin_fmax: + case Builtin::BI__builtin_fmaxf: + case Builtin::BI__builtin_fmaxl: + return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum)); + + case Builtin::BIfmin: + case Builtin::BIfminf: + case Builtin::BIfminl: + case Builtin::BI__builtin_fmin: + case Builtin::BI__builtin_fminf: + case Builtin::BI__builtin_fminl: + return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum)); + + // fmod() is a special-case. It maps to the frem instruction rather than an + // LLVM intrinsic. + case Builtin::BIfmod: + case Builtin::BIfmodf: + case Builtin::BIfmodl: + case Builtin::BI__builtin_fmod: + case Builtin::BI__builtin_fmodf: + case Builtin::BI__builtin_fmodl: { + Value *Arg1 = EmitScalarExpr(E->getArg(0)); + Value *Arg2 = EmitScalarExpr(E->getArg(1)); + return RValue::get(Builder.CreateFRem(Arg1, Arg2, "fmod")); + } + + case Builtin::BIlog: + case Builtin::BIlogf: + case Builtin::BIlogl: + case Builtin::BI__builtin_log: + case Builtin::BI__builtin_logf: + case Builtin::BI__builtin_logl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log)); + + case Builtin::BIlog10: + case Builtin::BIlog10f: + case Builtin::BIlog10l: + case Builtin::BI__builtin_log10: + case Builtin::BI__builtin_log10f: + case Builtin::BI__builtin_log10l: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10)); + + case Builtin::BIlog2: + case Builtin::BIlog2f: + case Builtin::BIlog2l: + case Builtin::BI__builtin_log2: + case Builtin::BI__builtin_log2f: + case Builtin::BI__builtin_log2l: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2)); + + case Builtin::BInearbyint: + case Builtin::BInearbyintf: + case Builtin::BInearbyintl: + case Builtin::BI__builtin_nearbyint: + case Builtin::BI__builtin_nearbyintf: + case Builtin::BI__builtin_nearbyintl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint)); + + case Builtin::BIpow: + case Builtin::BIpowf: + case Builtin::BIpowl: + case Builtin::BI__builtin_pow: + case Builtin::BI__builtin_powf: + case Builtin::BI__builtin_powl: + return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow)); + + case Builtin::BIrint: + case Builtin::BIrintf: + case Builtin::BIrintl: + case Builtin::BI__builtin_rint: + case Builtin::BI__builtin_rintf: + case Builtin::BI__builtin_rintl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint)); + + case Builtin::BIround: + case Builtin::BIroundf: + case Builtin::BIroundl: + case Builtin::BI__builtin_round: + case Builtin::BI__builtin_roundf: + case Builtin::BI__builtin_roundl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round)); + + case Builtin::BIsin: + case Builtin::BIsinf: + case Builtin::BIsinl: + case Builtin::BI__builtin_sin: + case Builtin::BI__builtin_sinf: + case Builtin::BI__builtin_sinl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin)); + + case Builtin::BIsqrt: + case Builtin::BIsqrtf: + case Builtin::BIsqrtl: + case Builtin::BI__builtin_sqrt: + case Builtin::BI__builtin_sqrtf: + case Builtin::BI__builtin_sqrtl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt)); + + case Builtin::BItrunc: + case Builtin::BItruncf: + case Builtin::BItruncl: + case Builtin::BI__builtin_trunc: + case Builtin::BI__builtin_truncf: + case Builtin::BI__builtin_truncl: + return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc)); + + default: + break; + } + } + switch (BuiltinID) { - default: break; // Handle intrinsics and libm functions below. + default: break; case Builtin::BI__builtin___CFStringMakeConstantString: case Builtin::BI__builtin___NSStringMakeConstantString: - return RValue::get(CGM.EmitConstantExpr(E, E->getType(), nullptr)); + return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType())); case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: case Builtin::BI__va_start: @@ -696,64 +1166,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } - case Builtin::BI__builtin_fabs: - case Builtin::BI__builtin_fabsf: - case Builtin::BI__builtin_fabsl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::fabs)); - } - case Builtin::BI__builtin_fmod: - case Builtin::BI__builtin_fmodf: - case Builtin::BI__builtin_fmodl: { - Value *Arg1 = EmitScalarExpr(E->getArg(0)); - Value *Arg2 = EmitScalarExpr(E->getArg(1)); - Value *Result = Builder.CreateFRem(Arg1, Arg2, "fmod"); - return RValue::get(Result); - } - case Builtin::BI__builtin_copysign: - case Builtin::BI__builtin_copysignf: - case Builtin::BI__builtin_copysignl: { - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::copysign)); - } - case Builtin::BI__builtin_ceil: - case Builtin::BI__builtin_ceilf: - case Builtin::BI__builtin_ceill: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil)); - } - case Builtin::BI__builtin_floor: - case Builtin::BI__builtin_floorf: - case Builtin::BI__builtin_floorl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor)); - } - case Builtin::BI__builtin_trunc: - case Builtin::BI__builtin_truncf: - case Builtin::BI__builtin_truncl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc)); - } - case Builtin::BI__builtin_rint: - case Builtin::BI__builtin_rintf: - case Builtin::BI__builtin_rintl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint)); - } - case Builtin::BI__builtin_nearbyint: - case Builtin::BI__builtin_nearbyintf: - case Builtin::BI__builtin_nearbyintl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint)); - } - case Builtin::BI__builtin_round: - case Builtin::BI__builtin_roundf: - case Builtin::BI__builtin_roundl: { - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round)); - } - case Builtin::BI__builtin_fmin: - case Builtin::BI__builtin_fminf: - case Builtin::BI__builtin_fminl: { - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum)); - } - case Builtin::BI__builtin_fmax: - case Builtin::BI__builtin_fmaxf: - case Builtin::BI__builtin_fmaxl: { - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum)); - } case Builtin::BI__builtin_conj: case Builtin::BI__builtin_conjf: case Builtin::BI__builtin_conjl: { @@ -792,7 +1204,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); + Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CTZPassedZero); llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); @@ -809,7 +1221,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); + Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CLZPassedZero); llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); @@ -1234,7 +1646,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, 0); Builder.CreateMemSet(Dest, Builder.getInt8(0), SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(nullptr); } case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: { @@ -1346,8 +1758,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(Int32Ty, Offset))); } case Builtin::BI__builtin_return_address: { - Value *Depth = - CGM.EmitConstantExpr(E->getArg(0), getContext().UnsignedIntTy, this); + Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0), + getContext().UnsignedIntTy); Value *F = CGM.getIntrinsic(Intrinsic::returnaddress); return RValue::get(Builder.CreateCall(F, Depth)); } @@ -1356,8 +1768,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, Builder.getInt32(0))); } case Builtin::BI__builtin_frame_address: { - Value *Depth = - CGM.EmitConstantExpr(E->getArg(0), getContext().UnsignedIntTy, this); + Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0), + getContext().UnsignedIntTy); Value *F = CGM.getIntrinsic(Intrinsic::frameaddress); return RValue::get(Builder.CreateCall(F, Depth)); } @@ -1875,56 +2287,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(nullptr); } - // Library functions with special handling. - case Builtin::BIsqrt: - case Builtin::BIsqrtf: - case Builtin::BIsqrtl: { - // Transform a call to sqrt* into a @llvm.sqrt.* intrinsic call, but only - // in finite- or unsafe-math mode (the intrinsic has different semantics - // for handling negative numbers compared to the library function, so - // -fmath-errno=0 is not enough). - if (!FD->hasAttr<ConstAttr>()) - break; - if (!(CGM.getCodeGenOpts().UnsafeFPMath || - CGM.getCodeGenOpts().NoNaNsFPMath)) - break; - Value *Arg0 = EmitScalarExpr(E->getArg(0)); - llvm::Type *ArgType = Arg0->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::sqrt, ArgType); - return RValue::get(Builder.CreateCall(F, Arg0)); - } - - case Builtin::BI__builtin_pow: - case Builtin::BI__builtin_powf: - case Builtin::BI__builtin_powl: - case Builtin::BIpow: - case Builtin::BIpowf: - case Builtin::BIpowl: { - // Transform a call to pow* into a @llvm.pow.* intrinsic call. - if (!FD->hasAttr<ConstAttr>()) - break; - Value *Base = EmitScalarExpr(E->getArg(0)); - Value *Exponent = EmitScalarExpr(E->getArg(1)); - llvm::Type *ArgType = Base->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType); - return RValue::get(Builder.CreateCall(F, {Base, Exponent})); - } - - case Builtin::BIfma: - case Builtin::BIfmaf: - case Builtin::BIfmal: - case Builtin::BI__builtin_fma: - case Builtin::BI__builtin_fmaf: - case Builtin::BI__builtin_fmal: { - // Rewrite fma to intrinsic. - Value *FirstArg = EmitScalarExpr(E->getArg(0)); - llvm::Type *ArgType = FirstArg->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::fma, ArgType); - return RValue::get( - Builder.CreateCall(F, {FirstArg, EmitScalarExpr(E->getArg(1)), - EmitScalarExpr(E->getArg(2))})); - } - case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: { @@ -1932,6 +2294,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))), ConvertType(E->getType()))); } + case Builtin::BI__annotation: { + // Re-encode each wide string to UTF8 and make an MDString. + SmallVector<Metadata *, 1> Strings; + for (const Expr *Arg : E->arguments()) { + const auto *Str = cast<StringLiteral>(Arg->IgnoreParenCasts()); + assert(Str->getCharByteWidth() == 2); + StringRef WideBytes = Str->getBytes(); + std::string StrUtf8; + if (!convertUTF16ToUTF8String( + makeArrayRef(WideBytes.data(), WideBytes.size()), StrUtf8)) { + CGM.ErrorUnsupported(E, "non-UTF16 __annotation argument"); + continue; + } + Strings.push_back(llvm::MDString::get(getLLVMContext(), StrUtf8)); + } + + // Build and MDTuple of MDStrings and emit the intrinsic call. + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::codeview_annotation, {}); + MDTuple *StrTuple = MDTuple::get(getLLVMContext(), Strings); + Builder.CreateCall(F, MetadataAsValue::get(getLLVMContext(), StrTuple)); + return RValue::getIgnored(); + } case Builtin::BI__builtin_annotation: { llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0)); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::annotation, @@ -2026,6 +2410,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType()); WidthAndSignedness ResultInfo = getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy); + + // Handle mixed-sign multiplication as a special case, because adding + // runtime or backend support for our generic irgen would be too expensive. + if (isSpecialMixedSignMultiply(BuiltinID, LeftInfo, RightInfo, ResultInfo)) + return EmitCheckedMixedSignMultiply(*this, LeftArg, LeftInfo, RightArg, + RightInfo, ResultArg, ResultQTy, + ResultInfo); + WidthAndSignedness EncompassingInfo = EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo}); @@ -2560,12 +2952,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // The most basic form of the call with parameters: // queue_t, kernel_enqueue_flags_t, ndrange_t, block(void) Name = "__enqueue_kernel_basic"; - llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, GenericVoidPtrTy}; + llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, GenericVoidPtrTy, + GenericVoidPtrTy}; llvm::FunctionType *FTy = llvm::FunctionType::get( - Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys, 4), false); + Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false); - llvm::Value *Block = Builder.CreatePointerCast( - EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3)); + llvm::Value *Kernel = + Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + llvm::Value *Block = + Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); AttrBuilder B; B.addAttribute(Attribute::ByVal); @@ -2574,33 +2971,58 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, auto RTCall = Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name, ByValAttrSet), - {Queue, Flags, Range, Block}); + {Queue, Flags, Range, Kernel, Block}); RTCall->setAttributes(ByValAttrSet); return RValue::get(RTCall); } assert(NumArgs >= 5 && "Invalid enqueue_kernel signature"); + // Create a temporary array to hold the sizes of local pointer arguments + // for the block. \p First is the position of the first size argument. + auto CreateArrayForSizeVar = [=](unsigned First) { + auto *AT = llvm::ArrayType::get(SizeTy, NumArgs - First); + auto *Arr = Builder.CreateAlloca(AT); + llvm::Value *Ptr; + // Each of the following arguments specifies the size of the corresponding + // argument passed to the enqueued block. + auto *Zero = llvm::ConstantInt::get(IntTy, 0); + for (unsigned I = First; I < NumArgs; ++I) { + auto *Index = llvm::ConstantInt::get(IntTy, I - First); + auto *GEP = Builder.CreateGEP(Arr, {Zero, Index}); + if (I == First) + Ptr = GEP; + auto *V = + Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy); + Builder.CreateAlignedStore( + V, GEP, CGM.getDataLayout().getPrefTypeAlignment(SizeTy)); + } + return Ptr; + }; + // Could have events and/or vaargs. if (E->getArg(3)->getType()->isBlockPointerType()) { // No events passed, but has variadic arguments. Name = "__enqueue_kernel_vaargs"; - llvm::Value *Block = Builder.CreatePointerCast( - EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3)); + llvm::Value *Kernel = + Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + auto *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); + auto *PtrToSizeArray = CreateArrayForSizeVar(4); + // Create a vector of the arguments, as well as a constant value to // express to the runtime the number of variadic arguments. - std::vector<llvm::Value *> Args = {Queue, Flags, Range, Block, - ConstantInt::get(IntTy, NumArgs - 4)}; - std::vector<llvm::Type *> ArgTys = {QueueTy, IntTy, RangeTy, - GenericVoidPtrTy, IntTy}; - - // Each of the following arguments specifies the size of the corresponding - // argument passed to the enqueued block. - for (unsigned I = 4/*Position of the first size arg*/; I < NumArgs; ++I) - Args.push_back( - Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy)); + std::vector<llvm::Value *> Args = { + Queue, Flags, Range, + Kernel, Block, ConstantInt::get(IntTy, NumArgs - 4), + PtrToSizeArray}; + std::vector<llvm::Type *> ArgTys = { + QueueTy, IntTy, RangeTy, + GenericVoidPtrTy, GenericVoidPtrTy, IntTy, + PtrToSizeArray->getType()}; llvm::FunctionType *FTy = llvm::FunctionType::get( - Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), true); + Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false); return RValue::get( Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), llvm::ArrayRef<llvm::Value *>(Args))); @@ -2621,15 +3043,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Convert to generic address space. EventList = Builder.CreatePointerCast(EventList, EventPtrTy); ClkEvent = Builder.CreatePointerCast(ClkEvent, EventPtrTy); - llvm::Value *Block = Builder.CreatePointerCast( - EmitScalarExpr(E->getArg(6)), GenericVoidPtrTy); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(6)); + llvm::Value *Kernel = + Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + llvm::Value *Block = + Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); std::vector<llvm::Type *> ArgTys = { - QueueTy, Int32Ty, RangeTy, Int32Ty, - EventPtrTy, EventPtrTy, GenericVoidPtrTy}; + QueueTy, Int32Ty, RangeTy, Int32Ty, + EventPtrTy, EventPtrTy, GenericVoidPtrTy, GenericVoidPtrTy}; - std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents, - EventList, ClkEvent, Block}; + std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents, + EventList, ClkEvent, Kernel, Block}; if (NumArgs == 7) { // Has events but no variadics. @@ -2646,14 +3072,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, ArgTys.push_back(Int32Ty); Name = "__enqueue_kernel_events_vaargs"; - // Each of the following arguments specifies the size of the corresponding - // argument passed to the enqueued block. - for (unsigned I = 7/*Position of the first size arg*/; I < NumArgs; ++I) - Args.push_back( - Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy)); + auto *PtrToSizeArray = CreateArrayForSizeVar(7); + Args.push_back(PtrToSizeArray); + ArgTys.push_back(PtrToSizeArray->getType()); llvm::FunctionType *FTy = llvm::FunctionType::get( - Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), true); + Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false); return RValue::get( Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), llvm::ArrayRef<llvm::Value *>(Args))); @@ -2665,24 +3089,70 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BIget_kernel_work_group_size: { llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy( getContext().getTargetAddressSpace(LangAS::opencl_generic)); - Value *Arg = EmitScalarExpr(E->getArg(0)); - Arg = Builder.CreatePointerCast(Arg, GenericVoidPtrTy); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0)); + Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); return RValue::get(Builder.CreateCall( CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false), + llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy}, + false), "__get_kernel_work_group_size_impl"), - Arg)); + {Kernel, Arg})); } case Builtin::BIget_kernel_preferred_work_group_size_multiple: { llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy( getContext().getTargetAddressSpace(LangAS::opencl_generic)); - Value *Arg = EmitScalarExpr(E->getArg(0)); - Arg = Builder.CreatePointerCast(Arg, GenericVoidPtrTy); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0)); + Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); return RValue::get(Builder.CreateCall( CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false), + llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy}, + false), "__get_kernel_preferred_work_group_multiple_impl"), - Arg)); + {Kernel, Arg})); + } + case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: + case Builtin::BIget_kernel_sub_group_count_for_ndrange: { + llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy( + getContext().getTargetAddressSpace(LangAS::opencl_generic)); + LValue NDRangeL = EmitAggExprToLValue(E->getArg(0)); + llvm::Value *NDRange = NDRangeL.getAddress().getPointer(); + auto Info = + CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1)); + Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); + Value *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); + const char *Name = + BuiltinID == Builtin::BIget_kernel_max_sub_group_size_for_ndrange + ? "__get_kernel_max_sub_group_size_for_ndrange_impl" + : "__get_kernel_sub_group_count_for_ndrange_impl"; + return RValue::get(Builder.CreateCall( + CGM.CreateRuntimeFunction( + llvm::FunctionType::get( + IntTy, {NDRange->getType(), GenericVoidPtrTy, GenericVoidPtrTy}, + false), + Name), + {NDRange, Kernel, Block})); + } + + case Builtin::BI__builtin_store_half: + case Builtin::BI__builtin_store_halff: { + Value *Val = EmitScalarExpr(E->getArg(0)); + Address Address = EmitPointerWithAlignment(E->getArg(1)); + Value *HalfVal = Builder.CreateFPTrunc(Val, Builder.getHalfTy()); + return RValue::get(Builder.CreateStore(HalfVal, Address)); + } + case Builtin::BI__builtin_load_half: { + Address Address = EmitPointerWithAlignment(E->getArg(0)); + Value *HalfVal = Builder.CreateLoad(Address); + return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getDoubleTy())); + } + case Builtin::BI__builtin_load_halff: { + Address Address = EmitPointerWithAlignment(E->getArg(0)); + Value *HalfVal = Builder.CreateLoad(Address); + return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getFloatTy())); } case Builtin::BIprintf: if (getTarget().getTriple().isNVPTX()) @@ -2699,69 +3169,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Fall through - it's already mapped to the intrinsic by GCCBuiltin. break; } - case Builtin::BI__builtin_os_log_format: { - assert(E->getNumArgs() >= 2 && - "__builtin_os_log_format takes at least 2 arguments"); - analyze_os_log::OSLogBufferLayout Layout; - analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout); - Address BufAddr = EmitPointerWithAlignment(E->getArg(0)); - // Ignore argument 1, the format string. It is not currently used. - CharUnits Offset; - Builder.CreateStore( - Builder.getInt8(Layout.getSummaryByte()), - Builder.CreateConstByteGEP(BufAddr, Offset++, "summary")); - Builder.CreateStore( - Builder.getInt8(Layout.getNumArgsByte()), - Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs")); - - llvm::SmallVector<llvm::Value *, 4> RetainableOperands; - for (const auto &Item : Layout.Items) { - Builder.CreateStore( - Builder.getInt8(Item.getDescriptorByte()), - Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor")); - Builder.CreateStore( - Builder.getInt8(Item.getSizeByte()), - Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize")); - Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset); - if (const Expr *TheExpr = Item.getExpr()) { - Addr = Builder.CreateElementBitCast( - Addr, ConvertTypeForMem(TheExpr->getType())); - // Check if this is a retainable type. - if (TheExpr->getType()->isObjCRetainableType()) { - assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar && - "Only scalar can be a ObjC retainable type"); - llvm::Value *SV = EmitScalarExpr(TheExpr, /*Ignore*/ false); - RValue RV = RValue::get(SV); - LValue LV = MakeAddrLValue(Addr, TheExpr->getType()); - EmitStoreThroughLValue(RV, LV); - // Check if the object is constant, if not, save it in - // RetainableOperands. - if (!isa<Constant>(SV)) - RetainableOperands.push_back(SV); - } else { - EmitAnyExprToMem(TheExpr, Addr, Qualifiers(), /*isInit*/ true); - } - } else { - Addr = Builder.CreateElementBitCast(Addr, Int32Ty); - Builder.CreateStore( - Builder.getInt32(Item.getConstValue().getQuantity()), Addr); - } - Offset += Item.size(); - } - - // Push a clang.arc.use cleanup for each object in RetainableOperands. The - // cleanup will cause the use to appear after the final log call, keeping - // the object valid while it's held in the log buffer. Note that if there's - // a release cleanup on the object, it will already be active; since - // cleanups are emitted in reverse order, the use will occur before the - // object is released. - if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount && - CGM.getCodeGenOpts().OptimizationLevel != 0) - for (llvm::Value *object : RetainableOperands) - pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), object); - - return RValue::get(BufAddr.getPointer()); - } + case Builtin::BI__builtin_os_log_format: + return emitBuiltinOSLogFormat(*E); case Builtin::BI__builtin_os_log_format_buffer_size: { analyze_os_log::OSLogBufferLayout Layout; @@ -2773,10 +3182,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__xray_customevent: { if (!ShouldXRayInstrumentFunction()) return RValue::getIgnored(); - if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>()) { - if (XRayAttr->neverXRayInstrument()) + if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>()) + if (XRayAttr->neverXRayInstrument() && !AlwaysEmitXRayCustomEvents()) return RValue::getIgnored(); - } + Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent); auto FTy = F->getFunctionType(); auto Arg0 = E->getArg(0); @@ -2954,6 +3363,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, case llvm::Triple::wasm32: case llvm::Triple::wasm64: return CGF->EmitWebAssemblyBuiltinExpr(BuiltinID, E); + case llvm::Triple::hexagon: + return CGF->EmitHexagonBuiltinExpr(BuiltinID, E); default: return nullptr; } @@ -4397,8 +4808,8 @@ static bool HasExtraNeonArgument(unsigned BuiltinID) { case NEON::BI__builtin_neon_vsha1cq_u32: case NEON::BI__builtin_neon_vsha1pq_u32: case NEON::BI__builtin_neon_vsha1mq_u32: - case ARM::BI_MoveToCoprocessor: - case ARM::BI_MoveToCoprocessor2: + case clang::ARM::BI_MoveToCoprocessor: + case clang::ARM::BI_MoveToCoprocessor2: return false; } return true; @@ -7153,6 +7564,19 @@ static Value *EmitX86MaskedLoad(CodeGenFunction &CGF, return CGF.Builder.CreateMaskedLoad(Ops[0], Align, MaskVec, Ops[1]); } +static Value *EmitX86MaskLogic(CodeGenFunction &CGF, Instruction::BinaryOps Opc, + unsigned NumElts, SmallVectorImpl<Value *> &Ops, + bool InvertLHS = false) { + Value *LHS = getMaskVecValue(CGF, Ops[0], NumElts); + Value *RHS = getMaskVecValue(CGF, Ops[1], NumElts); + + if (InvertLHS) + LHS = CGF.Builder.CreateNot(LHS); + + return CGF.Builder.CreateBitCast(CGF.Builder.CreateBinOp(Opc, LHS, RHS), + CGF.Builder.getIntNTy(std::max(NumElts, 8U))); +} + static Value *EmitX86SubVectorBroadcast(CodeGenFunction &CGF, SmallVectorImpl<Value *> &Ops, llvm::Type *DstTy, @@ -7229,6 +7653,18 @@ static Value *EmitX86MaskedCompare(CodeGenFunction &CGF, unsigned CC, std::max(NumElts, 8U))); } +static Value *EmitX86Abs(CodeGenFunction &CGF, ArrayRef<Value *> Ops) { + + llvm::Type *Ty = Ops[0]->getType(); + Value *Zero = llvm::Constant::getNullValue(Ty); + Value *Sub = CGF.Builder.CreateSub(Zero, Ops[0]); + Value *Cmp = CGF.Builder.CreateICmp(ICmpInst::ICMP_SGT, Ops[0], Zero); + Value *Res = CGF.Builder.CreateSelect(Cmp, Ops[0], Sub); + if (Ops.size() == 1) + return Res; + return EmitX86Select(CGF, Ops[2], Res, Ops[1]); +} + static Value *EmitX86MinMax(CodeGenFunction &CGF, ICmpInst::Predicate Pred, ArrayRef<Value *> Ops) { Value *Cmp = CGF.Builder.CreateICmp(Pred, Ops[0], Ops[1]); @@ -7248,8 +7684,118 @@ static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op, return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2"); } +Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) { + const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); + StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString(); + return EmitX86CpuIs(CPUStr); +} + +Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) { + + llvm::Type *Int32Ty = Builder.getInt32Ty(); + + // Matching the struct layout from the compiler-rt/libgcc structure that is + // filled in: + // unsigned int __cpu_vendor; + // unsigned int __cpu_type; + // unsigned int __cpu_subtype; + // unsigned int __cpu_features[1]; + llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, + llvm::ArrayType::get(Int32Ty, 1)); + + // Grab the global __cpu_model. + llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); + + // Calculate the index needed to access the correct field based on the + // range. Also adjust the expected value. + unsigned Index; + unsigned Value; + std::tie(Index, Value) = StringSwitch<std::pair<unsigned, unsigned>>(CPUStr) +#define X86_VENDOR(ENUM, STRING) \ + .Case(STRING, {0u, static_cast<unsigned>(llvm::X86::ENUM)}) +#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) \ + .Cases(STR, ALIAS, {1u, static_cast<unsigned>(llvm::X86::ENUM)}) +#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) \ + .Case(STR, {1u, static_cast<unsigned>(llvm::X86::ENUM)}) +#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) \ + .Case(STR, {2u, static_cast<unsigned>(llvm::X86::ENUM)}) +#include "llvm/Support/X86TargetParser.def" + .Default({0, 0}); + assert(Value != 0 && "Invalid CPUStr passed to CpuIs"); + + // Grab the appropriate field from __cpu_model. + llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), + ConstantInt::get(Int32Ty, Index)}; + llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs); + CpuValue = Builder.CreateAlignedLoad(CpuValue, CharUnits::fromQuantity(4)); + + // Check the value of the field against the requested value. + return Builder.CreateICmpEQ(CpuValue, + llvm::ConstantInt::get(Int32Ty, Value)); +} + +Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) { + const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts(); + StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString(); + return EmitX86CpuSupports(FeatureStr); +} + +Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs) { + // Processor features and mapping to processor feature value. + + uint32_t FeaturesMask = 0; + + for (const StringRef &FeatureStr : FeatureStrs) { + unsigned Feature = + StringSwitch<unsigned>(FeatureStr) +#define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, VAL) +#include "llvm/Support/X86TargetParser.def" + ; + FeaturesMask |= (1U << Feature); + } + + // Matching the struct layout from the compiler-rt/libgcc structure that is + // filled in: + // unsigned int __cpu_vendor; + // unsigned int __cpu_type; + // unsigned int __cpu_subtype; + // unsigned int __cpu_features[1]; + llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, + llvm::ArrayType::get(Int32Ty, 1)); + + // Grab the global __cpu_model. + llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); + + // Grab the first (0th) element from the field __cpu_features off of the + // global in the struct STy. + Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 3), + ConstantInt::get(Int32Ty, 0)}; + Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); + Value *Features = + Builder.CreateAlignedLoad(CpuFeatures, CharUnits::fromQuantity(4)); + + // Check the value of the bit corresponding to the feature requested. + Value *Bitset = Builder.CreateAnd( + Features, llvm::ConstantInt::get(Int32Ty, FeaturesMask)); + return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0)); +} + +Value *CodeGenFunction::EmitX86CpuInit() { + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, + /*Variadic*/ false); + llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, "__cpu_indicator_init"); + return Builder.CreateCall(Func); +} + Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + if (BuiltinID == X86::BI__builtin_cpu_is) + return EmitX86CpuIs(E); + if (BuiltinID == X86::BI__builtin_cpu_supports) + return EmitX86CpuSupports(E); + if (BuiltinID == X86::BI__builtin_cpu_init) + return EmitX86CpuInit(); + SmallVector<Value*, 4> Ops; // Find out if any arguments are required to be integer constant expressions. @@ -7300,110 +7846,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, switch (BuiltinID) { default: return nullptr; - case X86::BI__builtin_cpu_supports: { - const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts(); - StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString(); - - // TODO: When/if this becomes more than x86 specific then use a TargetInfo - // based mapping. - // Processor features and mapping to processor feature value. - enum X86Features { - CMOV = 0, - MMX, - POPCNT, - SSE, - SSE2, - SSE3, - SSSE3, - SSE4_1, - SSE4_2, - AVX, - AVX2, - SSE4_A, - FMA4, - XOP, - FMA, - AVX512F, - BMI, - BMI2, - AES, - PCLMUL, - AVX512VL, - AVX512BW, - AVX512DQ, - AVX512CD, - AVX512ER, - AVX512PF, - AVX512VBMI, - AVX512IFMA, - AVX5124VNNIW, // TODO implement this fully - AVX5124FMAPS, // TODO implement this fully - AVX512VPOPCNTDQ, - MAX - }; - - X86Features Feature = - StringSwitch<X86Features>(FeatureStr) - .Case("cmov", X86Features::CMOV) - .Case("mmx", X86Features::MMX) - .Case("popcnt", X86Features::POPCNT) - .Case("sse", X86Features::SSE) - .Case("sse2", X86Features::SSE2) - .Case("sse3", X86Features::SSE3) - .Case("ssse3", X86Features::SSSE3) - .Case("sse4.1", X86Features::SSE4_1) - .Case("sse4.2", X86Features::SSE4_2) - .Case("avx", X86Features::AVX) - .Case("avx2", X86Features::AVX2) - .Case("sse4a", X86Features::SSE4_A) - .Case("fma4", X86Features::FMA4) - .Case("xop", X86Features::XOP) - .Case("fma", X86Features::FMA) - .Case("avx512f", X86Features::AVX512F) - .Case("bmi", X86Features::BMI) - .Case("bmi2", X86Features::BMI2) - .Case("aes", X86Features::AES) - .Case("pclmul", X86Features::PCLMUL) - .Case("avx512vl", X86Features::AVX512VL) - .Case("avx512bw", X86Features::AVX512BW) - .Case("avx512dq", X86Features::AVX512DQ) - .Case("avx512cd", X86Features::AVX512CD) - .Case("avx512er", X86Features::AVX512ER) - .Case("avx512pf", X86Features::AVX512PF) - .Case("avx512vbmi", X86Features::AVX512VBMI) - .Case("avx512ifma", X86Features::AVX512IFMA) - .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ) - .Default(X86Features::MAX); - assert(Feature != X86Features::MAX && "Invalid feature!"); - - // Matching the struct layout from the compiler-rt/libgcc structure that is - // filled in: - // unsigned int __cpu_vendor; - // unsigned int __cpu_type; - // unsigned int __cpu_subtype; - // unsigned int __cpu_features[1]; - llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, - llvm::ArrayType::get(Int32Ty, 1)); - - // Grab the global __cpu_model. - llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); - - // Grab the first (0th) element from the field __cpu_features off of the - // global in the struct STy. - Value *Idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 3), - ConstantInt::get(Int32Ty, 0) - }; - Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); - Value *Features = Builder.CreateAlignedLoad(CpuFeatures, - CharUnits::fromQuantity(4)); - - // Check the value of the bit corresponding to the feature requested. - Value *Bitset = Builder.CreateAnd( - Features, llvm::ConstantInt::get(Int32Ty, 1ULL << Feature)); - return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0)); - } case X86::BI_mm_prefetch: { Value *Address = Ops[0]; Value *RW = ConstantInt::get(Int32Ty, 0); @@ -7526,6 +7968,10 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_storesd128_mask: { return EmitX86MaskedStore(*this, Ops, 16); } + case X86::BI__builtin_ia32_vpopcntd_128: + case X86::BI__builtin_ia32_vpopcntq_128: + case X86::BI__builtin_ia32_vpopcntd_256: + case X86::BI__builtin_ia32_vpopcntq_256: case X86::BI__builtin_ia32_vpopcntd_512: case X86::BI__builtin_ia32_vpopcntq_512: { llvm::Type *ResultType = ConvertType(E->getType()); @@ -7669,6 +8115,45 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return EmitX86Select(*this, Ops[4], Align, Ops[3]); } + case X86::BI__builtin_ia32_vperm2f128_pd256: + case X86::BI__builtin_ia32_vperm2f128_ps256: + case X86::BI__builtin_ia32_vperm2f128_si256: + case X86::BI__builtin_ia32_permti256: { + unsigned Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); + unsigned NumElts = Ops[0]->getType()->getVectorNumElements(); + + // This takes a very simple approach since there are two lanes and a + // shuffle can have 2 inputs. So we reserve the first input for the first + // lane and the second input for the second lane. This may result in + // duplicate sources, but this can be dealt with in the backend. + + Value *OutOps[2]; + uint32_t Indices[8]; + for (unsigned l = 0; l != 2; ++l) { + // Determine the source for this lane. + if (Imm & (1 << ((l * 4) + 3))) + OutOps[l] = llvm::ConstantAggregateZero::get(Ops[0]->getType()); + else if (Imm & (1 << ((l * 4) + 1))) + OutOps[l] = Ops[1]; + else + OutOps[l] = Ops[0]; + + for (unsigned i = 0; i != NumElts/2; ++i) { + // Start with ith element of the source for this lane. + unsigned Idx = (l * NumElts) + i; + // If bit 0 of the immediate half is set, switch to the high half of + // the source. + if (Imm & (1 << (l * 4))) + Idx += NumElts/2; + Indices[(l * (NumElts/2)) + i] = Idx; + } + } + + return Builder.CreateShuffleVector(OutOps[0], OutOps[1], + makeArrayRef(Indices, NumElts), + "vperm"); + } + case X86::BI__builtin_ia32_movnti: case X86::BI__builtin_ia32_movnti64: case X86::BI__builtin_ia32_movntsd: @@ -7714,32 +8199,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_selectpd_256: case X86::BI__builtin_ia32_selectpd_512: return EmitX86Select(*this, Ops[0], Ops[1], Ops[2]); - case X86::BI__builtin_ia32_pcmpeqb128_mask: - case X86::BI__builtin_ia32_pcmpeqb256_mask: - case X86::BI__builtin_ia32_pcmpeqb512_mask: - case X86::BI__builtin_ia32_pcmpeqw128_mask: - case X86::BI__builtin_ia32_pcmpeqw256_mask: - case X86::BI__builtin_ia32_pcmpeqw512_mask: - case X86::BI__builtin_ia32_pcmpeqd128_mask: - case X86::BI__builtin_ia32_pcmpeqd256_mask: - case X86::BI__builtin_ia32_pcmpeqd512_mask: - case X86::BI__builtin_ia32_pcmpeqq128_mask: - case X86::BI__builtin_ia32_pcmpeqq256_mask: - case X86::BI__builtin_ia32_pcmpeqq512_mask: - return EmitX86MaskedCompare(*this, 0, false, Ops); - case X86::BI__builtin_ia32_pcmpgtb128_mask: - case X86::BI__builtin_ia32_pcmpgtb256_mask: - case X86::BI__builtin_ia32_pcmpgtb512_mask: - case X86::BI__builtin_ia32_pcmpgtw128_mask: - case X86::BI__builtin_ia32_pcmpgtw256_mask: - case X86::BI__builtin_ia32_pcmpgtw512_mask: - case X86::BI__builtin_ia32_pcmpgtd128_mask: - case X86::BI__builtin_ia32_pcmpgtd256_mask: - case X86::BI__builtin_ia32_pcmpgtd512_mask: - case X86::BI__builtin_ia32_pcmpgtq128_mask: - case X86::BI__builtin_ia32_pcmpgtq256_mask: - case X86::BI__builtin_ia32_pcmpgtq512_mask: - return EmitX86MaskedCompare(*this, 6, true, Ops); case X86::BI__builtin_ia32_cmpb128_mask: case X86::BI__builtin_ia32_cmpb256_mask: case X86::BI__builtin_ia32_cmpb512_mask: @@ -7771,6 +8230,22 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return EmitX86MaskedCompare(*this, CC, false, Ops); } + case X86::BI__builtin_ia32_kandhi: + return EmitX86MaskLogic(*this, Instruction::And, 16, Ops); + case X86::BI__builtin_ia32_kandnhi: + return EmitX86MaskLogic(*this, Instruction::And, 16, Ops, true); + case X86::BI__builtin_ia32_korhi: + return EmitX86MaskLogic(*this, Instruction::Or, 16, Ops); + case X86::BI__builtin_ia32_kxnorhi: + return EmitX86MaskLogic(*this, Instruction::Xor, 16, Ops, true); + case X86::BI__builtin_ia32_kxorhi: + return EmitX86MaskLogic(*this, Instruction::Xor, 16, Ops); + case X86::BI__builtin_ia32_knothi: { + Ops[0] = getMaskVecValue(*this, Ops[0], 16); + return Builder.CreateBitCast(Builder.CreateNot(Ops[0]), + Builder.getInt16Ty()); + } + case X86::BI__builtin_ia32_vplzcntd_128_mask: case X86::BI__builtin_ia32_vplzcntd_256_mask: case X86::BI__builtin_ia32_vplzcntd_512_mask: @@ -7783,6 +8258,20 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Ops[1]); } + case X86::BI__builtin_ia32_pabsb128: + case X86::BI__builtin_ia32_pabsw128: + case X86::BI__builtin_ia32_pabsd128: + case X86::BI__builtin_ia32_pabsb256: + case X86::BI__builtin_ia32_pabsw256: + case X86::BI__builtin_ia32_pabsd256: + case X86::BI__builtin_ia32_pabsq128_mask: + case X86::BI__builtin_ia32_pabsq256_mask: + case X86::BI__builtin_ia32_pabsb512_mask: + case X86::BI__builtin_ia32_pabsw512_mask: + case X86::BI__builtin_ia32_pabsd512_mask: + case X86::BI__builtin_ia32_pabsq512_mask: + return EmitX86Abs(*this, Ops); + case X86::BI__builtin_ia32_pmaxsb128: case X86::BI__builtin_ia32_pmaxsw128: case X86::BI__builtin_ia32_pmaxsd128: @@ -8071,6 +8560,45 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E); case X86::BI_InterlockedIncrement64: return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E); + case X86::BI_InterlockedCompareExchange128: { + // InterlockedCompareExchange128 doesn't directly refer to 128bit ints, + // instead it takes pointers to 64bit ints for Destination and + // ComparandResult, and exchange is taken as two 64bit ints (high & low). + // The previous value is written to ComparandResult, and success is + // returned. + + llvm::Type *Int128Ty = Builder.getInt128Ty(); + llvm::Type *Int128PtrTy = Int128Ty->getPointerTo(); + + Value *Destination = + Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int128PtrTy); + Value *ExchangeHigh128 = + Builder.CreateZExt(EmitScalarExpr(E->getArg(1)), Int128Ty); + Value *ExchangeLow128 = + Builder.CreateZExt(EmitScalarExpr(E->getArg(2)), Int128Ty); + Address ComparandResult( + Builder.CreateBitCast(EmitScalarExpr(E->getArg(3)), Int128PtrTy), + getContext().toCharUnitsFromBits(128)); + + Value *Exchange = Builder.CreateOr( + Builder.CreateShl(ExchangeHigh128, 64, "", false, false), + ExchangeLow128); + + Value *Comparand = Builder.CreateLoad(ComparandResult); + + AtomicCmpXchgInst *CXI = + Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange, + AtomicOrdering::SequentiallyConsistent, + AtomicOrdering::SequentiallyConsistent); + CXI->setVolatile(true); + + // Write the result back to the inout pointer. + Builder.CreateStore(Builder.CreateExtractValue(CXI, 0), ComparandResult); + + // Get the success boolean and zero extend it to i8. + Value *Success = Builder.CreateExtractValue(CXI, 1); + return Builder.CreateZExt(Success, ConvertType(E->getType())); + } case X86::BI_AddressOfReturnAddress: { Value *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress); @@ -8680,6 +9208,15 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, CI->setConvergent(); return CI; } + case AMDGPU::BI__builtin_amdgcn_read_exec_lo: + case AMDGPU::BI__builtin_amdgcn_read_exec_hi: { + StringRef RegName = BuiltinID == AMDGPU::BI__builtin_amdgcn_read_exec_lo ? + "exec_lo" : "exec_hi"; + CallInst *CI = cast<CallInst>( + EmitSpecialRegisterBuiltin(*this, E, Int32Ty, Int32Ty, true, RegName)); + CI->setConvergent(); + return CI; + } // amdgcn workitem case AMDGPU::BI__builtin_amdgcn_workitem_id_x: @@ -9129,6 +9666,16 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(FnALAF32, {Ptr, Val}); } + case NVPTX::BI__nvvm_atom_add_gen_d: { + Value *Ptr = EmitScalarExpr(E->getArg(0)); + Value *Val = EmitScalarExpr(E->getArg(1)); + // atomicrmw only deals with integer arguments, so we need to use + // LLVM's nvvm_atomic_load_add_f64 intrinsic. + Value *FnALAF64 = + CGM.getIntrinsic(Intrinsic::nvvm_atomic_load_add_f64, Ptr->getType()); + return Builder.CreateCall(FnALAF64, {Ptr, Val}); + } + case NVPTX::BI__nvvm_atom_inc_gen_ui: { Value *Ptr = EmitScalarExpr(E->getArg(0)); Value *Val = EmitScalarExpr(E->getArg(1)); @@ -9282,6 +9829,219 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, {Ptr->getType()->getPointerElementType(), Ptr->getType()}), {Ptr, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2))}); } + case NVPTX::BI__nvvm_match_all_sync_i32p: + case NVPTX::BI__nvvm_match_all_sync_i64p: { + Value *Mask = EmitScalarExpr(E->getArg(0)); + Value *Val = EmitScalarExpr(E->getArg(1)); + Address PredOutPtr = EmitPointerWithAlignment(E->getArg(2)); + Value *ResultPair = Builder.CreateCall( + CGM.getIntrinsic(BuiltinID == NVPTX::BI__nvvm_match_all_sync_i32p + ? Intrinsic::nvvm_match_all_sync_i32p + : Intrinsic::nvvm_match_all_sync_i64p), + {Mask, Val}); + Value *Pred = Builder.CreateZExt(Builder.CreateExtractValue(ResultPair, 1), + PredOutPtr.getElementType()); + Builder.CreateStore(Pred, PredOutPtr); + return Builder.CreateExtractValue(ResultPair, 0); + } + case NVPTX::BI__hmma_m16n16k16_ld_a: + case NVPTX::BI__hmma_m16n16k16_ld_b: + case NVPTX::BI__hmma_m16n16k16_ld_c_f16: + case NVPTX::BI__hmma_m16n16k16_ld_c_f32: { + Address Dst = EmitPointerWithAlignment(E->getArg(0)); + Value *Src = EmitScalarExpr(E->getArg(1)); + Value *Ldm = EmitScalarExpr(E->getArg(2)); + llvm::APSInt isColMajorArg; + if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext())) + return nullptr; + bool isColMajor = isColMajorArg.getSExtValue(); + unsigned IID; + unsigned NumResults; + switch (BuiltinID) { + case NVPTX::BI__hmma_m16n16k16_ld_a: + IID = isColMajor ? Intrinsic::nvvm_wmma_load_a_f16_col_stride + : Intrinsic::nvvm_wmma_load_a_f16_row_stride; + NumResults = 8; + break; + case NVPTX::BI__hmma_m16n16k16_ld_b: + IID = isColMajor ? Intrinsic::nvvm_wmma_load_b_f16_col_stride + : Intrinsic::nvvm_wmma_load_b_f16_row_stride; + NumResults = 8; + break; + case NVPTX::BI__hmma_m16n16k16_ld_c_f16: + IID = isColMajor ? Intrinsic::nvvm_wmma_load_c_f16_col_stride + : Intrinsic::nvvm_wmma_load_c_f16_row_stride; + NumResults = 4; + break; + case NVPTX::BI__hmma_m16n16k16_ld_c_f32: + IID = isColMajor ? Intrinsic::nvvm_wmma_load_c_f32_col_stride + : Intrinsic::nvvm_wmma_load_c_f32_row_stride; + NumResults = 8; + break; + default: + llvm_unreachable("Unexpected builtin ID."); + } + Value *Result = + Builder.CreateCall(CGM.getIntrinsic(IID), + {Builder.CreatePointerCast(Src, VoidPtrTy), Ldm}); + + // Save returned values. + for (unsigned i = 0; i < NumResults; ++i) { + Builder.CreateAlignedStore( + Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), + Dst.getElementType()), + Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + } + return Result; + } + + case NVPTX::BI__hmma_m16n16k16_st_c_f16: + case NVPTX::BI__hmma_m16n16k16_st_c_f32: { + Value *Dst = EmitScalarExpr(E->getArg(0)); + Address Src = EmitPointerWithAlignment(E->getArg(1)); + Value *Ldm = EmitScalarExpr(E->getArg(2)); + llvm::APSInt isColMajorArg; + if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext())) + return nullptr; + bool isColMajor = isColMajorArg.getSExtValue(); + unsigned IID; + unsigned NumResults = 8; + // PTX Instructions (and LLVM instrinsics) are defined for slice _d_, yet + // for some reason nvcc builtins use _c_. + switch (BuiltinID) { + case NVPTX::BI__hmma_m16n16k16_st_c_f16: + IID = isColMajor ? Intrinsic::nvvm_wmma_store_d_f16_col_stride + : Intrinsic::nvvm_wmma_store_d_f16_row_stride; + NumResults = 4; + break; + case NVPTX::BI__hmma_m16n16k16_st_c_f32: + IID = isColMajor ? Intrinsic::nvvm_wmma_store_d_f32_col_stride + : Intrinsic::nvvm_wmma_store_d_f32_row_stride; + break; + default: + llvm_unreachable("Unexpected builtin ID."); + } + Function *Intrinsic = CGM.getIntrinsic(IID); + llvm::Type *ParamType = Intrinsic->getFunctionType()->getParamType(1); + SmallVector<Value *, 10> Values; + Values.push_back(Builder.CreatePointerCast(Dst, VoidPtrTy)); + for (unsigned i = 0; i < NumResults; ++i) { + Value *V = Builder.CreateAlignedLoad( + Builder.CreateGEP(Src.getPointer(), llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + Values.push_back(Builder.CreateBitCast(V, ParamType)); + } + Values.push_back(Ldm); + Value *Result = Builder.CreateCall(Intrinsic, Values); + return Result; + } + + // BI__hmma_m16n16k16_mma_<Dtype><CType>(d, a, b, c, layout, satf) + // --> Intrinsic::nvvm_wmma_mma_sync<layout A,B><DType><CType><Satf> + case NVPTX::BI__hmma_m16n16k16_mma_f16f16: + case NVPTX::BI__hmma_m16n16k16_mma_f32f16: + case NVPTX::BI__hmma_m16n16k16_mma_f32f32: + case NVPTX::BI__hmma_m16n16k16_mma_f16f32: { + Address Dst = EmitPointerWithAlignment(E->getArg(0)); + Address SrcA = EmitPointerWithAlignment(E->getArg(1)); + Address SrcB = EmitPointerWithAlignment(E->getArg(2)); + Address SrcC = EmitPointerWithAlignment(E->getArg(3)); + llvm::APSInt LayoutArg; + if (!E->getArg(4)->isIntegerConstantExpr(LayoutArg, getContext())) + return nullptr; + int Layout = LayoutArg.getSExtValue(); + if (Layout < 0 || Layout > 3) + return nullptr; + llvm::APSInt SatfArg; + if (!E->getArg(5)->isIntegerConstantExpr(SatfArg, getContext())) + return nullptr; + bool Satf = SatfArg.getSExtValue(); + + // clang-format off +#define MMA_VARIANTS(type) {{ \ + Intrinsic::nvvm_wmma_mma_sync_row_row_##type, \ + Intrinsic::nvvm_wmma_mma_sync_row_row_##type##_satfinite, \ + Intrinsic::nvvm_wmma_mma_sync_row_col_##type, \ + Intrinsic::nvvm_wmma_mma_sync_row_col_##type##_satfinite, \ + Intrinsic::nvvm_wmma_mma_sync_col_row_##type, \ + Intrinsic::nvvm_wmma_mma_sync_col_row_##type##_satfinite, \ + Intrinsic::nvvm_wmma_mma_sync_col_col_##type, \ + Intrinsic::nvvm_wmma_mma_sync_col_col_##type##_satfinite \ + }} + // clang-format on + + auto getMMAIntrinsic = [Layout, Satf](std::array<unsigned, 8> Variants) { + unsigned Index = Layout * 2 + Satf; + assert(Index < 8); + return Variants[Index]; + }; + unsigned IID; + unsigned NumEltsC; + unsigned NumEltsD; + switch (BuiltinID) { + case NVPTX::BI__hmma_m16n16k16_mma_f16f16: + IID = getMMAIntrinsic(MMA_VARIANTS(f16_f16)); + NumEltsC = 4; + NumEltsD = 4; + break; + case NVPTX::BI__hmma_m16n16k16_mma_f32f16: + IID = getMMAIntrinsic(MMA_VARIANTS(f32_f16)); + NumEltsC = 4; + NumEltsD = 8; + break; + case NVPTX::BI__hmma_m16n16k16_mma_f16f32: + IID = getMMAIntrinsic(MMA_VARIANTS(f16_f32)); + NumEltsC = 8; + NumEltsD = 4; + break; + case NVPTX::BI__hmma_m16n16k16_mma_f32f32: + IID = getMMAIntrinsic(MMA_VARIANTS(f32_f32)); + NumEltsC = 8; + NumEltsD = 8; + break; + default: + llvm_unreachable("Unexpected builtin ID."); + } +#undef MMA_VARIANTS + + SmallVector<Value *, 24> Values; + Function *Intrinsic = CGM.getIntrinsic(IID); + llvm::Type *ABType = Intrinsic->getFunctionType()->getParamType(0); + // Load A + for (unsigned i = 0; i < 8; ++i) { + Value *V = Builder.CreateAlignedLoad( + Builder.CreateGEP(SrcA.getPointer(), + llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + Values.push_back(Builder.CreateBitCast(V, ABType)); + } + // Load B + for (unsigned i = 0; i < 8; ++i) { + Value *V = Builder.CreateAlignedLoad( + Builder.CreateGEP(SrcB.getPointer(), + llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + Values.push_back(Builder.CreateBitCast(V, ABType)); + } + // Load C + llvm::Type *CType = Intrinsic->getFunctionType()->getParamType(16); + for (unsigned i = 0; i < NumEltsC; ++i) { + Value *V = Builder.CreateAlignedLoad( + Builder.CreateGEP(SrcC.getPointer(), + llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + Values.push_back(Builder.CreateBitCast(V, CType)); + } + Value *Result = Builder.CreateCall(Intrinsic, Values); + llvm::Type *DType = Dst.getElementType(); + for (unsigned i = 0; i < NumEltsD; ++i) + Builder.CreateAlignedStore( + Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), DType), + Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)), + CharUnits::fromQuantity(4)); + return Result; + } default: return nullptr; } @@ -9315,3 +10075,58 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, return nullptr; } } + +Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + SmallVector<llvm::Value *, 4> Ops; + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry: + case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B: { + Address Dest = EmitPointerWithAlignment(E->getArg(2)); + unsigned Size; + if (BuiltinID == Hexagon::BI__builtin_HEXAGON_V6_vaddcarry) { + Size = 512; + ID = Intrinsic::hexagon_V6_vaddcarry; + } else { + Size = 1024; + ID = Intrinsic::hexagon_V6_vaddcarry_128B; + } + Dest = Builder.CreateBitCast(Dest, + llvm::VectorType::get(Builder.getInt1Ty(), Size)->getPointerTo(0)); + LoadInst *QLd = Builder.CreateLoad(Dest); + Ops = { EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), QLd }; + llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID), Ops); + llvm::Value *Vprd = Builder.CreateExtractValue(Result, 1); + llvm::Value *Base = Builder.CreateBitCast(EmitScalarExpr(E->getArg(2)), + Vprd->getType()->getPointerTo(0)); + Builder.CreateAlignedStore(Vprd, Base, Dest.getAlignment()); + return Builder.CreateExtractValue(Result, 0); + } + case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry: + case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B: { + Address Dest = EmitPointerWithAlignment(E->getArg(2)); + unsigned Size; + if (BuiltinID == Hexagon::BI__builtin_HEXAGON_V6_vsubcarry) { + Size = 512; + ID = Intrinsic::hexagon_V6_vsubcarry; + } else { + Size = 1024; + ID = Intrinsic::hexagon_V6_vsubcarry_128B; + } + Dest = Builder.CreateBitCast(Dest, + llvm::VectorType::get(Builder.getInt1Ty(), Size)->getPointerTo(0)); + LoadInst *QLd = Builder.CreateLoad(Dest); + Ops = { EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), QLd }; + llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID), Ops); + llvm::Value *Vprd = Builder.CreateExtractValue(Result, 1); + llvm::Value *Base = Builder.CreateBitCast(EmitScalarExpr(E->getArg(2)), + Vprd->getType()->getPointerTo(0)); + Builder.CreateAlignedStore(Vprd, Base, Dest.getAlignment()); + return Builder.CreateExtractValue(Result, 0); + } + } // switch + + return nullptr; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp index 0f3141ab76d0d..5ef4dc45fba12 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp @@ -110,16 +110,14 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { return true; return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), - GlobalDecl(BaseD, Dtor_Base), - false); + GlobalDecl(BaseD, Dtor_Base)); } /// Try to emit a definition as a global alias for another definition. /// If \p InEveryTU is true, we know that an equivalent alias can be produced /// in every translation unit. bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, - GlobalDecl TargetDecl, - bool InEveryTU) { + GlobalDecl TargetDecl) { if (!getCodeGenOpts().CXXCtorDtorAliases) return true; @@ -134,11 +132,6 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, llvm::GlobalValue::LinkageTypes TargetLinkage = getFunctionLinkage(TargetDecl); - // available_externally definitions aren't real definitions, so we cannot - // create an alias to one. - if (TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage) - return true; - // Check if we have it already. StringRef MangledName = getMangledName(AliasDecl); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); @@ -161,7 +154,14 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, // Instead of creating as alias to a linkonce_odr, replace all of the uses // of the aliasee. - if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) { + if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) && + !(TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage && + TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) { + // FIXME: An extern template instantiation will create functions with + // linkage "AvailableExternally". In libc++, some classes also define + // members with attribute "AlwaysInline" and expect no reference to + // be generated. It is desirable to reenable this optimisation after + // corresponding LLVM changes. addReplacement(MangledName, Aliasee); return false; } @@ -176,13 +176,11 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, return true; } - if (!InEveryTU) { - // If we don't have a definition for the destructor yet, don't - // emit. We can't emit aliases to declarations; that's just not - // how aliases work. - if (Ref->isDeclaration()) - return true; - } + // If we don't have a definition for the destructor yet or the definition is + // avaialable_externally, don't emit an alias. We can't emit aliases to + // declarations; that's just not how aliases work. + if (Ref->isDeclarationForLinker()) + return true; // Don't create an alias to a linker weak symbol. This avoids producing // different COMDATs in different TUs. Another option would be to diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp index 033258643ddf9..a27c3e9d27e39 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp @@ -149,12 +149,15 @@ void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList ¶ms) { } } -void CGCXXABI::EmitThisParam(CodeGenFunction &CGF) { +llvm::Value *CGCXXABI::loadIncomingCXXThis(CodeGenFunction &CGF) { + return CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)), + "this"); +} + +void CGCXXABI::setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr) { /// Initialize the 'this' slot. assert(getThisDecl(CGF) && "no 'this' variable for function"); - CGF.CXXABIThisValue - = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)), - "this"); + CGF.CXXABIThisValue = ThisPtr; } void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h index 7b912e3aca576..83426dc3a03c7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h @@ -73,9 +73,10 @@ protected: return CGF.CXXStructorImplicitParamValue; } - /// Perform prolog initialization of the parameter variable suitable - /// for 'this' emitted by buildThisParam. - void EmitThisParam(CodeGenFunction &CGF); + /// Loads the incoming C++ this pointer as it was passed by the caller. + llvm::Value *loadIncomingCXXThis(CodeGenFunction &CGF); + + void setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr); ASTContext &getContext() const { return CGM.getContext(); } @@ -358,13 +359,6 @@ public: return CharUnits::Zero(); } - /// Perform ABI-specific "this" parameter adjustment in a virtual function - /// prologue. - virtual llvm::Value *adjustThisParameterInVirtualFunctionPrologue( - CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) { - return This; - } - /// Emit the ABI-specific prolog for the function. virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; @@ -588,6 +582,13 @@ public: /// Emit a single constructor/destructor with the given type from a C++ /// constructor Decl. virtual void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) = 0; + + /// Load a vtable from This, an object of polymorphic type RD, or from one of + /// its virtual bases if it does not have its own vtable. Returns the vtable + /// and the class from which the vtable was loaded. + virtual std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) = 0; }; // Create an instance of a C++ ABI class: diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index 316bf44cb1c3d..c3709bf2e447e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -455,11 +455,15 @@ const CGFunctionInfo & CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, QualType receiverType) { SmallVector<CanQualType, 16> argTys; + SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2); argTys.push_back(Context.getCanonicalParamType(receiverType)); argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType())); // FIXME: Kill copy? for (const auto *I : MD->parameters()) { argTys.push_back(Context.getCanonicalParamType(I->getType())); + auto extParamInfo = FunctionProtoType::ExtParameterInfo().withIsNoEscape( + I->hasAttr<NoEscapeAttr>()); + extParamInfos.push_back(extParamInfo); } FunctionType::ExtInfo einfo; @@ -475,7 +479,7 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, return arrangeLLVMFunctionInfo( GetReturnType(MD->getReturnType()), /*instanceMethod=*/false, - /*chainCall=*/false, argTys, einfo, {}, required); + /*chainCall=*/false, argTys, einfo, extParamInfos, required); } const CGFunctionInfo & @@ -1223,14 +1227,15 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty, // // FIXME: Assert that we aren't truncating non-padding bits when have access // to that information. - Src = CGF.Builder.CreateBitCast(Src, llvm::PointerType::getUnqual(Ty)); + Src = CGF.Builder.CreateBitCast(Src, + Ty->getPointerTo(Src.getAddressSpace())); return CGF.Builder.CreateLoad(Src); } // Otherwise do coercion through memory. This is stupid, but simple. Address Tmp = CreateTempAllocaForCoercion(CGF, Ty, Src.getAlignment()); - Address Casted = CGF.Builder.CreateBitCast(Tmp, CGF.Int8PtrTy); - Address SrcCasted = CGF.Builder.CreateBitCast(Src, CGF.Int8PtrTy); + Address Casted = CGF.Builder.CreateBitCast(Tmp, CGF.AllocaInt8PtrTy); + Address SrcCasted = CGF.Builder.CreateBitCast(Src, CGF.AllocaInt8PtrTy); CGF.Builder.CreateMemCpy(Casted, SrcCasted, llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize), false); @@ -1311,8 +1316,8 @@ static void CreateCoercedStore(llvm::Value *Src, // to that information. Address Tmp = CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment()); CGF.Builder.CreateStore(Src, Tmp); - Address Casted = CGF.Builder.CreateBitCast(Tmp, CGF.Int8PtrTy); - Address DstCasted = CGF.Builder.CreateBitCast(Dst, CGF.Int8PtrTy); + Address Casted = CGF.Builder.CreateBitCast(Tmp, CGF.AllocaInt8PtrTy); + Address DstCasted = CGF.Builder.CreateBitCast(Dst, CGF.AllocaInt8PtrTy); CGF.Builder.CreateMemCpy(DstCasted, Casted, llvm::ConstantInt::get(CGF.IntPtrTy, DstSize), false); @@ -1734,10 +1739,15 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt)); // TODO: Reciprocal estimate codegen options should apply to instructions? - std::vector<std::string> &Recips = getTarget().getTargetOpts().Reciprocals; + const std::vector<std::string> &Recips = CodeGenOpts.Reciprocals; if (!Recips.empty()) FuncAttrs.addAttribute("reciprocal-estimates", - llvm::join(Recips.begin(), Recips.end(), ",")); + llvm::join(Recips, ",")); + + if (!CodeGenOpts.PreferVectorWidth.empty() && + CodeGenOpts.PreferVectorWidth != "none") + FuncAttrs.addAttribute("prefer-vector-width", + CodeGenOpts.PreferVectorWidth); if (CodeGenOpts.StackRealignment) FuncAttrs.addAttribute("stackrealign"); @@ -1745,13 +1755,16 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute("backchain"); } - if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { - // Conservatively, mark all functions and calls in CUDA as convergent - // (meaning, they may call an intrinsically convergent op, such as - // __syncthreads(), and so can't have certain optimizations applied around - // them). LLVM will remove this attribute where it safely can. + if (getLangOpts().assumeFunctionsAreConvergent()) { + // Conservatively, mark all functions and calls in CUDA and OpenCL as + // convergent (meaning, they may call an intrinsically convergent op, such + // as __syncthreads() / barrier(), and so can't have certain optimizations + // applied around them). LLVM will remove this attribute where it safely + // can. FuncAttrs.addAttribute(llvm::Attribute::Convergent); + } + if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { // Exceptions aren't supported in CUDA device code. FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); @@ -1847,6 +1860,16 @@ void CodeGenModule::ConstructAttributeList( !(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>())) FuncAttrs.addAttribute("split-stack"); + // Add NonLazyBind attribute to function declarations when -fno-plt + // is used. + if (TargetDecl && CodeGenOpts.NoPLT) { + if (auto *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { + if (!Fn->isDefined() && !AttrOnCallSite) { + FuncAttrs.addAttribute(llvm::Attribute::NonLazyBind); + } + } + } + if (!AttrOnCallSite) { bool DisableTailCalls = CodeGenOpts.DisableTailCalls || @@ -1859,13 +1882,13 @@ void CodeGenModule::ConstructAttributeList( // we have a decl for the function and it has a target attribute then // parse that and add it to the feature set. StringRef TargetCPU = getTarget().getTargetOpts().CPU; + std::vector<std::string> Features; const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); if (FD && FD->hasAttr<TargetAttr>()) { llvm::StringMap<bool> FeatureMap; getFunctionFeatureMap(FeatureMap, FD); // Produce the canonical string for this set of features. - std::vector<std::string> Features; for (llvm::StringMap<bool>::const_iterator it = FeatureMap.begin(), ie = FeatureMap.end(); it != ie; ++it) @@ -1877,28 +1900,22 @@ void CodeGenModule::ConstructAttributeList( // the function. const auto *TD = FD->getAttr<TargetAttr>(); TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); - if (ParsedAttr.Architecture != "") + if (ParsedAttr.Architecture != "" && + getTarget().isValidCPUName(ParsedAttr.Architecture)) TargetCPU = ParsedAttr.Architecture; - if (TargetCPU != "") - FuncAttrs.addAttribute("target-cpu", TargetCPU); - if (!Features.empty()) { - std::sort(Features.begin(), Features.end()); - FuncAttrs.addAttribute( - "target-features", - llvm::join(Features.begin(), Features.end(), ",")); - } } else { // Otherwise just add the existing target cpu and target features to the // function. - std::vector<std::string> &Features = getTarget().getTargetOpts().Features; - if (TargetCPU != "") - FuncAttrs.addAttribute("target-cpu", TargetCPU); - if (!Features.empty()) { - std::sort(Features.begin(), Features.end()); - FuncAttrs.addAttribute( - "target-features", - llvm::join(Features.begin(), Features.end(), ",")); - } + Features = getTarget().getTargetOpts().Features; + } + + if (TargetCPU != "") + FuncAttrs.addAttribute("target-cpu", TargetCPU); + if (!Features.empty()) { + std::sort(Features.begin(), Features.end()); + FuncAttrs.addAttribute( + "target-features", + llvm::join(Features, ",")); } } @@ -2092,6 +2109,9 @@ void CodeGenModule::ConstructAttributeList( break; } + if (FI.getExtParameterInfo(ArgNo).isNoEscape()) + Attrs.addAttribute(llvm::Attribute::NoCapture); + if (Attrs.hasAttributes()) { unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); @@ -3054,7 +3074,8 @@ static void emitWriteback(CodeGenFunction &CGF, // If the argument wasn't provably non-null, we need to null check // before doing the store. - bool provablyNonNull = llvm::isKnownNonNull(srcAddr.getPointer()); + bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), + CGF.CGM.getDataLayout()); if (!provablyNonNull) { llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback"); contBB = CGF.createBasicBlock("icr.done"); @@ -3194,7 +3215,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // If the address is *not* known to be non-null, we need to switch. llvm::Value *finalArgument; - bool provablyNonNull = llvm::isKnownNonNull(srcAddr.getPointer()); + bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), + CGF.CGM.getDataLayout()); if (provablyNonNull) { finalArgument = temp.getPointer(); } else { @@ -3946,7 +3968,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Builder.CreateMemCpy(TempAlloca, Src, SrcSize); Src = TempAlloca; } else { - Src = Builder.CreateBitCast(Src, llvm::PointerType::getUnqual(STy)); + Src = Builder.CreateBitCast(Src, + STy->getPointerTo(Src.getAddressSpace())); } auto SrcLayout = CGM.getDataLayout().getStructLayout(STy); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp index 50d702c622688..a6915071ec174 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp @@ -129,14 +129,16 @@ Address CodeGenFunction::EmitCXXMemberDataPointerAddress(const Expr *E, Address base, llvm::Value *memberPtr, const MemberPointerType *memberPtrType, - LValueBaseInfo *BaseInfo) { + LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo) { // Ask the ABI to compute the actual address. llvm::Value *ptr = CGM.getCXXABI().EmitMemberDataPointerAddress(*this, E, base, memberPtr, memberPtrType); QualType memberType = memberPtrType->getPointeeType(); - CharUnits memberAlign = getNaturalTypeAlignment(memberType, BaseInfo); + CharUnits memberAlign = getNaturalTypeAlignment(memberType, BaseInfo, + TBAAInfo); memberAlign = CGM.getDynamicOffsetAlignment(base.getAlignment(), memberPtrType->getClass()->getAsCXXRecordDecl(), @@ -1413,10 +1415,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // possible to delegate the destructor body to the complete // destructor. Do so. if (DtorType == Dtor_Deleting) { + RunCleanupsScope DtorEpilogue(*this); EnterDtorCleanups(Dtor, Dtor_Deleting); - EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, - /*Delegating=*/false, LoadCXXThisAddress()); - PopCleanupBlock(); + if (HaveInsertPoint()) + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + /*Delegating=*/false, LoadCXXThisAddress()); return; } @@ -1512,6 +1515,13 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) } namespace { + llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF, + const CXXDestructorDecl *DD) { + if (Expr *ThisArg = DD->getOperatorDeleteThisArg()) + return CGF.EmitScalarExpr(ThisArg); + return CGF.LoadCXXThis(); + } + /// Call the operator delete associated with the current destructor. struct CallDtorDelete final : EHScopeStack::Cleanup { CallDtorDelete() {} @@ -1519,11 +1529,38 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) override { const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); const CXXRecordDecl *ClassDecl = Dtor->getParent(); - CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), + CGF.EmitDeleteCall(Dtor->getOperatorDelete(), + LoadThisForDtorDelete(CGF, Dtor), CGF.getContext().getTagDeclType(ClassDecl)); } }; + void EmitConditionalDtorDeleteCall(CodeGenFunction &CGF, + llvm::Value *ShouldDeleteCondition, + bool ReturnAfterDelete) { + llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete"); + llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue"); + llvm::Value *ShouldCallDelete + = CGF.Builder.CreateIsNull(ShouldDeleteCondition); + CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB); + + CGF.EmitBlock(callDeleteBB); + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + CGF.EmitDeleteCall(Dtor->getOperatorDelete(), + LoadThisForDtorDelete(CGF, Dtor), + CGF.getContext().getTagDeclType(ClassDecl)); + assert(Dtor->getOperatorDelete()->isDestroyingOperatorDelete() == + ReturnAfterDelete && + "unexpected value for ReturnAfterDelete"); + if (ReturnAfterDelete) + CGF.EmitBranchThroughCleanup(CGF.ReturnBlock); + else + CGF.Builder.CreateBr(continueBB); + + CGF.EmitBlock(continueBB); + } + struct CallDtorDeleteConditional final : EHScopeStack::Cleanup { llvm::Value *ShouldDeleteCondition; @@ -1534,20 +1571,8 @@ namespace { } void Emit(CodeGenFunction &CGF, Flags flags) override { - llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete"); - llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue"); - llvm::Value *ShouldCallDelete - = CGF.Builder.CreateIsNull(ShouldDeleteCondition); - CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB); - - CGF.EmitBlock(callDeleteBB); - const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl); - const CXXRecordDecl *ClassDecl = Dtor->getParent(); - CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), - CGF.getContext().getTagDeclType(ClassDecl)); - CGF.Builder.CreateBr(continueBB); - - CGF.EmitBlock(continueBB); + EmitConditionalDtorDeleteCall(CGF, ShouldDeleteCondition, + /*ReturnAfterDelete*/false); } }; @@ -1577,6 +1602,7 @@ namespace { static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr, CharUnits::QuantityType PoisonSize) { + CodeGenFunction::SanitizerScope SanScope(&CGF); // Pass in void pointer and size of region as arguments to runtime // function llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy), @@ -1705,6 +1731,9 @@ namespace { /// \brief Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. +/// +/// For a deleting destructor, this also handles the case where a destroying +/// operator delete completely overrides the definition. void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, CXXDtorType DtorType) { assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) && @@ -1717,11 +1746,23 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, "operator delete missing - EnterDtorCleanups"); if (CXXStructorImplicitParamValue) { // If there is an implicit param to the deleting dtor, it's a boolean - // telling whether we should call delete at the end of the dtor. - EHStack.pushCleanup<CallDtorDeleteConditional>( - NormalAndEHCleanup, CXXStructorImplicitParamValue); + // telling whether this is a deleting destructor. + if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) + EmitConditionalDtorDeleteCall(*this, CXXStructorImplicitParamValue, + /*ReturnAfterDelete*/true); + else + EHStack.pushCleanup<CallDtorDeleteConditional>( + NormalAndEHCleanup, CXXStructorImplicitParamValue); } else { - EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup); + if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) { + const CXXRecordDecl *ClassDecl = DD->getParent(); + EmitDeleteCall(DD->getOperatorDelete(), + LoadThisForDtorDelete(*this, DD), + getContext().getTagDeclType(ClassDecl)); + EmitBranchThroughCleanup(ReturnBlock); + } else { + EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup); + } } return; } @@ -2382,7 +2423,8 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) { VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy); llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField); - CGM.DecorateInstructionWithTBAA(Store, CGM.getTBAAInfoForVTablePtr()); + TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTablePtrTy); + CGM.DecorateInstructionWithTBAA(Store, TBAAInfo); if (CGM.getCodeGenOpts().OptimizationLevel > 0 && CGM.getCodeGenOpts().StrictVTablePointers) CGM.DecorateInstructionWithInvariantGroup(Store, Vptr.VTableClass); @@ -2476,7 +2518,8 @@ llvm::Value *CodeGenFunction::GetVTablePtr(Address This, const CXXRecordDecl *RD) { Address VTablePtrSrc = Builder.CreateElementBitCast(This, VTableTy); llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable"); - CGM.DecorateInstructionWithTBAA(VTable, CGM.getTBAAInfoForVTablePtr()); + TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTableTy); + CGM.DecorateInstructionWithTBAA(VTable, TBAAInfo); if (CGM.getCodeGenOpts().OptimizationLevel > 0 && CGM.getCodeGenOpts().StrictVTablePointers) @@ -2523,8 +2566,10 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) { void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, llvm::Value *VTable, SourceLocation Loc) { - if (CGM.getCodeGenOpts().WholeProgramVTables && - CGM.HasHiddenLTOVisibility(RD)) { + if (SanOpts.has(SanitizerKind::CFIVCall)) + EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc); + else if (CGM.getCodeGenOpts().WholeProgramVTables && + CGM.HasHiddenLTOVisibility(RD)) { llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)); llvm::Value *TypeId = @@ -2536,9 +2581,6 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, {CastedVTable, TypeId}); Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest); } - - if (SanOpts.has(SanitizerKind::CFIVCall)) - EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc); } void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD, @@ -2585,8 +2627,9 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, EmitBlock(CheckBlock); } - llvm::Value *VTable = - GetVTablePtr(Address(Derived, getPointerAlign()), Int8PtrTy, ClassDecl); + llvm::Value *VTable; + std::tie(VTable, ClassDecl) = CGM.getCXXABI().LoadVTablePtr( + *this, Address(Derived, getPointerAlign()), ClassDecl); EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc); @@ -2604,28 +2647,34 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, !CGM.HasHiddenLTOVisibility(RD)) return; - std::string TypeName = RD->getQualifiedNameAsString(); - if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName)) - return; - - SanitizerScope SanScope(this); + SanitizerMask M; llvm::SanitizerStatKind SSK; switch (TCK) { case CFITCK_VCall: + M = SanitizerKind::CFIVCall; SSK = llvm::SanStat_CFI_VCall; break; case CFITCK_NVCall: + M = SanitizerKind::CFINVCall; SSK = llvm::SanStat_CFI_NVCall; break; case CFITCK_DerivedCast: + M = SanitizerKind::CFIDerivedCast; SSK = llvm::SanStat_CFI_DerivedCast; break; case CFITCK_UnrelatedCast: + M = SanitizerKind::CFIUnrelatedCast; SSK = llvm::SanStat_CFI_UnrelatedCast; break; case CFITCK_ICall: llvm_unreachable("not expecting CFITCK_ICall"); } + + std::string TypeName = RD->getQualifiedNameAsString(); + if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName)) + return; + + SanitizerScope SanScope(this); EmitSanitizerStatReport(SSK); llvm::Metadata *MD = @@ -2636,24 +2685,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *TypeTest = Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId}); - SanitizerMask M; - switch (TCK) { - case CFITCK_VCall: - M = SanitizerKind::CFIVCall; - break; - case CFITCK_NVCall: - M = SanitizerKind::CFINVCall; - break; - case CFITCK_DerivedCast: - M = SanitizerKind::CFIDerivedCast; - break; - case CFITCK_UnrelatedCast: - M = SanitizerKind::CFIUnrelatedCast; - break; - case CFITCK_ICall: - llvm_unreachable("not expecting CFITCK_ICall"); - } - llvm::Constant *StaticData[] = { llvm::ConstantInt::get(Int8Ty, TCK), EmitCheckSourceLocation(Loc), @@ -2688,7 +2719,8 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) { return false; std::string TypeName = RD->getQualifiedNameAsString(); - return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName); + return !getContext().getSanitizerBlacklist().isBlacklistedType( + SanitizerKind::CFIVCall, TypeName); } llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( @@ -2745,9 +2777,12 @@ void CodeGenFunction::EmitForwardingCallToLambda( RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. - if (!resultType->isVoidType() && returnSlot.isNull()) + if (!resultType->isVoidType() && returnSlot.isNull()) { + if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType()) { + RV = RValue::get(EmitARCRetainAutoreleasedReturnValue(RV.getScalarVal())); + } EmitReturnOfRValue(RV, resultType); - else + } else EmitBranchThroughCleanup(ReturnBlock); } @@ -2755,6 +2790,15 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { const BlockDecl *BD = BlockInfo->getBlockDecl(); const VarDecl *variable = BD->capture_begin()->getVariable(); const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl(); + const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); + + if (CallOp->isVariadic()) { + // FIXME: Making this work correctly is nasty because it requires either + // cloning the body of the call operator or making the call operator + // forward. + CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function"); + return; + } // Start building arguments for forwarding call CallArgList CallArgs; @@ -2769,18 +2813,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { assert(!Lambda->isGenericLambda() && "generic lambda interconversion to block not implemented"); - EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs); -} - -void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { - if (cast<CXXMethodDecl>(CurCodeDecl)->isVariadic()) { - // FIXME: Making this work correctly is nasty because it requires either - // cloning the body of the call operator or making the call operator forward. - CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function"); - return; - } - - EmitFunctionBody(Args, cast<FunctionDecl>(CurGD.getDecl())->getBody()); + EmitForwardingCallToLambda(CallOp, CallArgs); } void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { @@ -2813,7 +2846,7 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { EmitForwardingCallToLambda(CallOp, CallArgs); } -void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) { +void CodeGenFunction::EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD) { if (MD->isVariadic()) { // FIXME: Making this work correctly is nasty because it requires either // cloning the body of the call operator or making the call operator forward. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp index b5453bc11e305..22055b2cb9029 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp @@ -1096,7 +1096,7 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { break; } - // Otherwise, tell the scope that there's a jump propoagating + // Otherwise, tell the scope that there's a jump propagating // through it. If this isn't new information, all the rest of // the work has been done before. if (!Scope.addBranchThrough(Dest.getBlock())) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp index a65faa602b331..5842e7b3ff93c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp @@ -181,10 +181,8 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr}); auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr()); - if (SuspendRet != nullptr) { + if (SuspendRet != nullptr && SuspendRet->getType()->isIntegerTy(1)) { // Veto suspension if requested by bool returning await_suspend. - assert(SuspendRet->getType()->isIntegerTy(1) && - "Sema should have already checked that it is void or bool"); BasicBlock *RealSuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend.bool")); CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock); @@ -234,6 +232,13 @@ RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E, void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { ++CurCoro.Data->CoreturnCount; + const Expr *RV = S.getOperand(); + if (RV && RV->getType()->isVoidType()) { + // Make sure to evaluate the expression of a co_return with a void + // expression for side effects. + RunCleanupsScope cleanupScope(*this); + EmitIgnoredExpr(RV); + } EmitStmt(S.getPromiseCall()); EmitBranchThroughCleanup(CurCoro.Data->FinalJD); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index 18b1d10a921d1..caea41ec0e037 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -18,6 +18,7 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" @@ -28,6 +29,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessorOptions.h" @@ -95,6 +97,10 @@ void ApplyDebugLocation::init(SourceLocation TemporaryLocation, } OriginalLocation = CGF->Builder.getCurrentDebugLocation(); + + if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled()) + return; + if (TemporaryLocation.isValid()) { DI->EmitLocation(CGF->Builder, TemporaryLocation); return; @@ -218,6 +224,19 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, return Default; } +PrintingPolicy CGDebugInfo::getPrintingPolicy() const { + PrintingPolicy PP = CGM.getContext().getPrintingPolicy(); + + // If we're emitting codeview, it's important to try to match MSVC's naming so + // that visualizers written for MSVC will trigger for our class names. In + // particular, we can't have spaces between arguments of standard templates + // like basic_string and vector. + if (CGM.getCodeGenOpts().EmitCodeView) + PP.MSVCFormatting = true; + + return PP; +} + StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert(FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); @@ -238,18 +257,15 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { SmallString<128> NS; llvm::raw_svector_ostream OS(NS); - PrintingPolicy Policy(CGM.getLangOpts()); - Policy.MSVCFormatting = CGM.getCodeGenOpts().EmitCodeView; if (!UseQualifiedName) FD->printName(OS); else - FD->printQualifiedName(OS, Policy); + FD->printQualifiedName(OS, getPrintingPolicy()); // Add any template specialization args. if (Info) { const TemplateArgumentList *TArgs = Info->TemplateArguments; - TemplateSpecializationType::PrintTemplateArgumentList(OS, TArgs->asArray(), - Policy); + printTemplateArgumentList(OS, TArgs->asArray(), getPrintingPolicy()); } // Copy this name on the side and use its reference. @@ -296,7 +312,7 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { if (isa<ClassTemplateSpecializationDecl>(RD)) { SmallString<128> Name; llvm::raw_svector_ostream OS(Name); - RD->getNameForDiagnostic(OS, CGM.getContext().getPrintingPolicy(), + RD->getNameForDiagnostic(OS, getPrintingPolicy(), /*Qualified*/ false); // Copy this name on the side and use its reference. @@ -483,6 +499,16 @@ void CGDebugInfo::CreateCompileUnit() { llvm::sys::path::append(MainFileDirSS, MainFileName); MainFileName = MainFileDirSS.str(); } + // If the main file name provided is identical to the input file name, and + // if the input file is a preprocessed source, use the module name for + // debug info. The module name comes from the name specified in the first + // linemarker if the input is a preprocessed source. + if (MainFile->getName() == MainFileName && + FrontendOptions::getInputKindForExtension( + MainFile->getName().rsplit('.').second) + .isPreprocessed()) + MainFileName = CGM.getModule().getName().str(); + CSKind = computeChecksum(SM.getMainFileID(), Checksum); } @@ -527,16 +553,16 @@ void CGDebugInfo::CreateCompileUnit() { // Create new compile unit. // FIXME - Eliminate TheCU. + auto &CGOpts = CGM.getCodeGenOpts(); TheCU = DBuilder.createCompileUnit( LangTag, DBuilder.createFile(remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSKind, Checksum), - Producer, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers, - CGM.getCodeGenOpts().EnableSplitDwarf - ? "" - : CGM.getCodeGenOpts().SplitDwarfFile, - EmissionKind, 0 /* DWOid */, CGM.getCodeGenOpts().SplitDwarfInlining, - CGM.getCodeGenOpts().DebugInfoForProfiling); + Producer, LO.Optimize || CGOpts.PrepareForLTO || CGOpts.EmitSummaryIndex, + CGOpts.DwarfDebugFlags, RuntimeVers, + CGOpts.EnableSplitDwarf ? "" : CGOpts.SplitDwarfFile, EmissionKind, + 0 /* DWOid */, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, + CGOpts.GnuPubnames); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { @@ -645,6 +671,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::LongDouble: + case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Double: // FIXME: For targets where long double and __float128 have the same size, @@ -805,6 +832,10 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagFwdDecl, FullName); + if (CGM.getCodeGenOpts().DebugFwdTemplateParams) + if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + DBuilder.replaceArrays(RetTy, llvm::DINodeArray(), + CollectCXXTemplateParams(TSpecial, DefUnit)); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast<llvm::Metadata *>(RetTy))); @@ -909,12 +940,8 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, SmallString<128> NS; llvm::raw_svector_ostream OS(NS); - Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(), - /*qualified*/ false); - - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Ty->template_arguments(), - CGM.getContext().getPrintingPolicy()); + Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false); + printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); auto *AliasDecl = cast<TypeAliasTemplateDecl>( Ty->getTemplateName().getAsTemplateDecl())->getTemplatedDecl(); @@ -1174,13 +1201,13 @@ void CGDebugInfo::CollectRecordNormalField( elements.push_back(FieldType); } -void CGDebugInfo::CollectRecordNestedRecord( - const RecordDecl *RD, SmallVectorImpl<llvm::Metadata *> &elements) { - QualType Ty = CGM.getContext().getTypeDeclType(RD); +void CGDebugInfo::CollectRecordNestedType( + const TypeDecl *TD, SmallVectorImpl<llvm::Metadata *> &elements) { + QualType Ty = CGM.getContext().getTypeDeclType(TD); // Injected class names are not considered nested records. if (isa<InjectedClassNameType>(Ty)) return; - SourceLocation Loc = RD->getLocation(); + SourceLocation Loc = TD->getLocation(); llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc)); elements.push_back(nestedType); } @@ -1196,9 +1223,9 @@ void CGDebugInfo::CollectRecordFields( else { const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); - // Debug info for nested records is included in the member list only for + // Debug info for nested types is included in the member list only for // CodeView. - bool IncludeNestedRecords = CGM.getCodeGenOpts().EmitCodeView; + bool IncludeNestedTypes = CGM.getCodeGenOpts().EmitCodeView; // Field number for non-static fields. unsigned fieldNo = 0; @@ -1225,10 +1252,12 @@ void CGDebugInfo::CollectRecordFields( // Bump field number for next field. ++fieldNo; - } else if (const auto *nestedRec = dyn_cast<CXXRecordDecl>(I)) - if (IncludeNestedRecords && !nestedRec->isImplicit() && - nestedRec->getDeclContext() == record) - CollectRecordNestedRecord(nestedRec, elements); + } else if (IncludeNestedTypes) { + if (const auto *nestedType = dyn_cast<TypeDecl>(I)) + if (!nestedType->isImplicit() && + nestedType->getDeclContext() == record) + CollectRecordNestedType(nestedType, elements); + } } } @@ -1366,7 +1395,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( // C++ ABI does not include all virtual methods from non-primary bases in // the vtable for the most derived class. For example, if C inherits from // A and B, C's primary vftable will not include B's virtual methods. - if (Method->begin_overridden_methods() == Method->end_overridden_methods()) + if (Method->size_overridden_methods() == 0) Flags |= llvm::DINode::FlagIntroducedVirtual; // The 'this' adjustment accounts for both the virtual and non-virtual @@ -1379,6 +1408,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( ContainingType = RecordTy; } + if (Method->isStatic()) + Flags |= llvm::DINode::FlagStaticMember; if (Method->isImplicit()) Flags |= llvm::DINode::FlagArtificial; Flags |= getAccessFlag(Method->getAccess(), Method->getParent()); @@ -1590,7 +1621,7 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, QualType T = E->getType(); if (E->isGLValue()) T = CGM.getContext().getLValueReferenceType(T); - llvm::Constant *V = CGM.EmitConstantExpr(E, T); + llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T); assert(V && "Expression in template argument isn't constant"); llvm::DIType *TTy = getOrCreateType(T, Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( @@ -1766,6 +1797,29 @@ static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) { return false; } +/// Does a type definition exist in an imported clang module? +static bool isDefinedInClangModule(const RecordDecl *RD) { + // Only definitions that where imported from an AST file come from a module. + if (!RD || !RD->isFromASTFile()) + return false; + // Anonymous entities cannot be addressed. Treat them as not from module. + if (!RD->isExternallyVisible() && RD->getName().empty()) + return false; + if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) { + if (!CXXDecl->isCompleteDefinition()) + return false; + auto TemplateKind = CXXDecl->getTemplateSpecializationKind(); + if (TemplateKind != TSK_Undeclared) { + // This is a template, check the origin of the first member. + if (CXXDecl->field_begin() == CXXDecl->field_end()) + return TemplateKind == TSK_ExplicitInstantiationDeclaration; + if (!CXXDecl->field_begin()->isFromASTFile()) + return false; + } + } + return true; +} + void CGDebugInfo::completeClassData(const RecordDecl *RD) { if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) if (CXXRD->isDynamicClass() && @@ -1773,6 +1827,10 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) { llvm::GlobalValue::AvailableExternallyLinkage && !isClassOrMethodDLLImport(CXXRD)) return; + + if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) + return; + completeClass(RD); } @@ -1799,29 +1857,6 @@ static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, return false; } -/// Does a type definition exist in an imported clang module? -static bool isDefinedInClangModule(const RecordDecl *RD) { - // Only definitions that where imported from an AST file come from a module. - if (!RD || !RD->isFromASTFile()) - return false; - // Anonymous entities cannot be addressed. Treat them as not from module. - if (!RD->isExternallyVisible() && RD->getName().empty()) - return false; - if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) { - if (!CXXDecl->isCompleteDefinition()) - return false; - auto TemplateKind = CXXDecl->getTemplateSpecializationKind(); - if (TemplateKind != TSK_Undeclared) { - // This is a template, check the origin of the first member. - if (CXXDecl->field_begin() == CXXDecl->field_end()) - return TemplateKind == TSK_ExplicitInstantiationDeclaration; - if (!CXXDecl->field_begin()->isFromASTFile()) - return false; - } - } - return true; -} - static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, bool DebugTypeExtRefs, const RecordDecl *RD, const LangOptions &LangOpts) { @@ -3655,9 +3690,9 @@ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) { } void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *Arg, + StringRef Name, unsigned ArgNo, - llvm::Value *LocalAddr, + llvm::AllocaInst *Alloca, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); ASTContext &C = CGM.getContext(); @@ -3789,19 +3824,11 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, // Create the descriptor for the parameter. auto *debugVar = DBuilder.createParameterVariable( - scope, Arg->getName(), ArgNo, tunit, line, type, + scope, Name, ArgNo, tunit, line, type, CGM.getLangOpts().Optimize, flags); - if (LocalAddr) { - // Insert an llvm.dbg.value into the current block. - DBuilder.insertDbgValueIntrinsic( - LocalAddr, 0, debugVar, DBuilder.createExpression(), - llvm::DebugLoc::get(line, column, scope, CurInlinedAt), - Builder.GetInsertBlock()); - } - // Insert an llvm.dbg.declare into the current block. - DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(), + DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(), llvm::DebugLoc::get(line, column, scope, CurInlinedAt), Builder.GetInsertBlock()); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h index 39249c7cf4da2..4f7b7f2a0d9c4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h @@ -278,8 +278,8 @@ class CGDebugInfo { llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &E, llvm::DIType *RecordTy, const RecordDecl *RD); - void CollectRecordNestedRecord(const RecordDecl *RD, - SmallVectorImpl<llvm::Metadata *> &E); + void CollectRecordNestedType(const TypeDecl *RD, + SmallVectorImpl<llvm::Metadata *> &E); void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile *F, SmallVectorImpl<llvm::Metadata *> &E, llvm::DICompositeType *RecordTy); @@ -398,8 +398,8 @@ public: /// Emit call to \c llvm.dbg.declare for the block-literal argument /// to a block invocation function. void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *Arg, unsigned ArgNo, - llvm::Value *LocalAddr, + StringRef Name, unsigned ArgNo, + llvm::AllocaInst *LocalAddr, CGBuilderTy &Builder); /// Emit information about a global variable. @@ -558,6 +558,9 @@ private: unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext); + /// Get the printing policy for producing names for debug info. + PrintingPolicy getPrintingPolicy() const; + /// Get function name for the given FunctionDecl. If the name is /// constructed on demand (e.g., C++ destructor) then the name is /// stored on the side. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp index 23517867437c7..04585a8afbb65 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -161,6 +162,10 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { // needs to be emitted like a static variable, e.g. a function-scope // variable in constant address space in OpenCL. if (D.getStorageDuration() != SD_Automatic) { + // Static sampler variables translated to function calls. + if (D.getType()->isSamplerT()) + return; + llvm::GlobalValue::LinkageTypes Linkage = CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false); @@ -221,7 +226,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( Name = getStaticDeclName(*this, D); llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty); - unsigned AS = GetGlobalVarAddressSpace(&D); + LangAS AS = GetGlobalVarAddressSpace(&D); unsigned TargetAS = getContext().getTargetAddressSpace(AS); // Local address space cannot have an initializer. @@ -235,7 +240,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name, nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); - setGlobalVisibility(GV, &D); + setGlobalVisibility(GV, &D, ForDefinition); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); @@ -251,7 +256,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( } // Make sure the result is of the correct type. - unsigned ExpectedAS = Ty.getAddressSpace(); + LangAS ExpectedAS = Ty.getAddressSpace(); llvm::Constant *Addr = GV; if (AS != ExpectedAS) { Addr = getTargetCodeGenInfo().performAddrSpaceCast( @@ -307,7 +312,8 @@ static bool hasNontrivialDestruction(QualType T) { llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { - llvm::Constant *Init = CGM.EmitConstantInit(D, this); + ConstantEmitter emitter(*this); + llvm::Constant *Init = emitter.tryEmitForInitializer(D); // If constant emission failed, then this should be a C++ static // initializer. @@ -355,6 +361,8 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, GV->setConstant(CGM.isTypeConstant(D.getType(), true)); GV->setInitializer(Init); + emitter.finalize(GV); + if (hasNontrivialDestruction(D.getType()) && HaveInsertPoint()) { // We have a constant initializer, but a nontrivial destructor. We still // need to perform a guarded "initialization" in order to register the @@ -952,7 +960,9 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { CodeGenFunction::AutoVarEmission CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { QualType Ty = D.getType(); - assert(Ty.getAddressSpace() == LangAS::Default); + assert( + Ty.getAddressSpace() == LangAS::Default || + (Ty.getAddressSpace() == LangAS::opencl_private && getLangOpts().OpenCL)); AutoVarEmission emission(D); @@ -1236,7 +1246,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::Constant *constant = nullptr; if (emission.IsConstantAggregate || D.isConstexpr()) { assert(!capturedByInit && "constant init contains a capturing block?"); - constant = CGM.EmitConstantInit(D, this); + constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D); } if (!constant) { @@ -1260,7 +1270,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::ConstantInt::get(IntPtrTy, getContext().getTypeSizeInChars(type).getQuantity()); - llvm::Type *BP = Int8PtrTy; + llvm::Type *BP = AllocaInt8PtrTy; if (Loc.getType() != BP) Loc = Builder.CreateBitCast(Loc, BP); @@ -1786,24 +1796,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, setBlockContextParameter(IPD, ArgNo, Arg.getDirectValue()); return; } - - // Apply any prologue 'this' adjustments required by the ABI. Be careful to - // handle the case where 'this' is passed indirectly as part of an inalloca - // struct. - if (const CXXMethodDecl *MD = - dyn_cast_or_null<CXXMethodDecl>(CurCodeDecl)) { - if (MD->isVirtual() && IPD == CXXABIThisDecl) { - llvm::Value *This = Arg.isIndirect() - ? Builder.CreateLoad(Arg.getIndirectAddress()) - : Arg.getDirectValue(); - This = CGM.getCXXABI().adjustThisParameterInVirtualFunctionPrologue( - *this, CurGD, This); - if (Arg.isIndirect()) - Builder.CreateStore(This, Arg.getIndirectAddress()); - else - Arg = ParamValue::forDirect(This); - } - } } Address DeclPtr = Address::invalid(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp index d8768bee2cdf4..0429978317021 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp @@ -18,6 +18,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/Support/Path.h" using namespace clang; @@ -259,6 +260,43 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); } +void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit, + llvm::BasicBlock *InitBlock, + llvm::BasicBlock *NoInitBlock, + GuardKind Kind, + const VarDecl *D) { + assert((Kind == GuardKind::TlsGuard || D) && "no guarded variable"); + + // A guess at how many times we will enter the initialization of a + // variable, depending on the kind of variable. + static const uint64_t InitsPerTLSVar = 1024; + static const uint64_t InitsPerLocalVar = 1024 * 1024; + + llvm::MDNode *Weights; + if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) { + // For non-local variables, don't apply any weighting for now. Due to our + // use of COMDATs, we expect there to be at most one initialization of the + // variable per DSO, but we have no way to know how many DSOs will try to + // initialize the variable. + Weights = nullptr; + } else { + uint64_t NumInits; + // FIXME: For the TLS case, collect and use profiling information to + // determine a more accurate brach weight. + if (Kind == GuardKind::TlsGuard || D->getTLSKind()) + NumInits = InitsPerTLSVar; + else + NumInits = InitsPerLocalVar; + + // The probability of us entering the initializer is + // 1 / (total number of times we attempt to initialize the variable). + llvm::MDBuilder MDHelper(CGM.getLLVMContext()); + Weights = MDHelper.createBranchWeights(1, NumInits - 1); + } + + Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights); +} + llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction( llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI, SourceLocation Loc, bool TLS) { @@ -278,17 +316,29 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction( if (!getLangOpts().Exceptions) Fn->setDoesNotThrow(); - if (!isInSanitizerBlacklist(Fn, Loc)) { - if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address | - SanitizerKind::KernelAddress)) - Fn->addFnAttr(llvm::Attribute::SanitizeAddress); - if (getLangOpts().Sanitize.has(SanitizerKind::Thread)) - Fn->addFnAttr(llvm::Attribute::SanitizeThread); - if (getLangOpts().Sanitize.has(SanitizerKind::Memory)) - Fn->addFnAttr(llvm::Attribute::SanitizeMemory); - if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack)) - Fn->addFnAttr(llvm::Attribute::SafeStack); - } + if (getLangOpts().Sanitize.has(SanitizerKind::Address) && + !isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeAddress); + + if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) && + !isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeAddress); + + if (getLangOpts().Sanitize.has(SanitizerKind::HWAddress) && + !isInSanitizerBlacklist(SanitizerKind::HWAddress, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress); + + if (getLangOpts().Sanitize.has(SanitizerKind::Thread) && + !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeThread); + + if (getLangOpts().Sanitize.has(SanitizerKind::Memory) && + !isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeMemory); + + if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) && + !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SafeStack); return Fn; } @@ -449,16 +499,12 @@ CodeGenModule::EmitCXXGlobalInitFunc() { PrioritizedCXXGlobalInits.clear(); } - SmallString<128> FileName; - SourceManager &SM = Context.getSourceManager(); - if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - // Include the filename in the symbol name. Including "sub_" matches gcc and - // makes sure these symbols appear lexicographically behind the symbols with - // priority emitted above. - FileName = llvm::sys::path::filename(MainFile->getName()); - } else { + // Include the filename in the symbol name. Including "sub_" matches gcc and + // makes sure these symbols appear lexicographically behind the symbols with + // priority emitted above. + SmallString<128> FileName = llvm::sys::path::filename(getModule().getName()); + if (FileName.empty()) FileName = "<null>"; - } for (size_t i = 0; i < FileName.size(); ++i) { // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens @@ -539,7 +585,8 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, "guard.uninitialized"); llvm::BasicBlock *InitBlock = createBasicBlock("init"); ExitBlock = createBasicBlock("exit"); - Builder.CreateCondBr(Uninit, InitBlock, ExitBlock); + EmitCXXGuardedInitBranch(Uninit, InitBlock, ExitBlock, + GuardKind::TlsGuard, nullptr); EmitBlock(InitBlock); // Mark as initialized before initializing anything else. If the // initializers use previously-initialized thread_local vars, that's diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp index 40ae0921098cb..6c9d9f170ace6 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp @@ -15,6 +15,7 @@ #include "CGCXXABI.h" #include "CGCleanup.h" #include "CGObjCRuntime.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/Mangle.h" #include "clang/AST/StmtCXX.h" @@ -111,17 +112,11 @@ EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr }; const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr }; -/// On Win64, use libgcc's SEH personality function. We fall back to dwarf on -/// other platforms, unless the user asked for SjLj exceptions. -static bool useLibGCCSEHPersonality(const llvm::Triple &T) { - return T.isOSWindows() && T.getArch() == llvm::Triple::x86_64; -} - static const EHPersonality &getCPersonality(const llvm::Triple &T, const LangOptions &L) { if (L.SjLjExceptions) return EHPersonality::GNU_C_SJLJ; - else if (useLibGCCSEHPersonality(T)) + if (L.SEHExceptions) return EHPersonality::GNU_C_SEH; return EHPersonality::GNU_C; } @@ -143,7 +138,7 @@ static const EHPersonality &getObjCPersonality(const llvm::Triple &T, case ObjCRuntime::ObjFW: if (L.SjLjExceptions) return EHPersonality::GNU_ObjC_SJLJ; - else if (useLibGCCSEHPersonality(T)) + if (L.SEHExceptions) return EHPersonality::GNU_ObjC_SEH; return EHPersonality::GNU_ObjC; } @@ -154,7 +149,7 @@ static const EHPersonality &getCXXPersonality(const llvm::Triple &T, const LangOptions &L) { if (L.SjLjExceptions) return EHPersonality::GNU_CPlusPlus_SJLJ; - else if (useLibGCCSEHPersonality(T)) + if (L.SEHExceptions) return EHPersonality::GNU_CPlusPlus_SEH; return EHPersonality::GNU_CPlusPlus; } @@ -164,26 +159,27 @@ static const EHPersonality &getCXXPersonality(const llvm::Triple &T, static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T, const LangOptions &L) { switch (L.ObjCRuntime.getKind()) { + // In the fragile ABI, just use C++ exception handling and hope + // they're not doing crazy exception mixing. + case ObjCRuntime::FragileMacOSX: + return getCXXPersonality(T, L); + // The ObjC personality defers to the C++ personality for non-ObjC // handlers. Unlike the C++ case, we use the same personality // function on targets using (backend-driven) SJLJ EH. case ObjCRuntime::MacOSX: case ObjCRuntime::iOS: case ObjCRuntime::WatchOS: - return EHPersonality::NeXT_ObjC; + return getObjCPersonality(T, L); - // In the fragile ABI, just use C++ exception handling and hope - // they're not doing crazy exception mixing. - case ObjCRuntime::FragileMacOSX: - return getCXXPersonality(T, L); + case ObjCRuntime::GNUstep: + return EHPersonality::GNU_ObjCXX; // The GCC runtime's personality function inherently doesn't support - // mixed EH. Use the C++ personality just to avoid returning null. + // mixed EH. Use the ObjC personality just to avoid returning null. case ObjCRuntime::GCC: case ObjCRuntime::ObjFW: return getObjCPersonality(T, L); - case ObjCRuntime::GNUstep: - return EHPersonality::GNU_ObjCXX; } llvm_unreachable("bad runtime kind"); } @@ -209,8 +205,9 @@ const EHPersonality &EHPersonality::get(CodeGenModule &CGM, if (T.isWindowsMSVCEnvironment() && !L.ObjC1) { if (L.SjLjExceptions) return EHPersonality::GNU_CPlusPlus_SJLJ; - else - return EHPersonality::MSVC_CxxFrameHandler3; + if (L.DWARFExceptions) + return EHPersonality::GNU_CPlusPlus; + return EHPersonality::MSVC_CxxFrameHandler3; } if (L.CPlusPlus && L.ObjC1) @@ -224,7 +221,12 @@ const EHPersonality &EHPersonality::get(CodeGenModule &CGM, } const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) { - return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(CGF.CurCodeDecl)); + const auto *FD = CGF.CurCodeDecl; + // For outlined finallys and filters, use the SEH personality in case they + // contain more SEH. This mostly only affects finallys. Filters could + // hypothetically use gnu statement expressions to sneak in nested SEH. + FD = FD ? FD : CGF.CurSEHParent; + return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD)); } static llvm::Constant *getPersonalityFn(CodeGenModule &CGM, @@ -1800,7 +1802,8 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // "catch i8* null". We can't do this on x86 because the filter has to save // the exception code. llvm::Constant *C = - CGM.EmitConstantExpr(Except->getFilterExpr(), getContext().IntTy, this); + ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(), + getContext().IntTy); if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && C->isOneValue()) { CatchScope->setCatchAllHandler(0, createBasicBlock("__except")); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index 63c7b3d10bf90..98740e8f9aabe 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -20,6 +20,7 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" @@ -48,7 +49,7 @@ using namespace CodeGen; llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) { unsigned addressSpace = - cast<llvm::PointerType>(value->getType())->getAddressSpace(); + cast<llvm::PointerType>(value->getType())->getAddressSpace(); llvm::PointerType *destType = Int8PtrTy; if (addressSpace) @@ -73,12 +74,15 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, // cast alloca to the default address space when necessary. if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) { auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default); - auto CurIP = Builder.saveIP(); - Builder.SetInsertPoint(AllocaInsertPt); + llvm::IRBuilderBase::InsertPointGuard IPG(Builder); + // When ArraySize is nullptr, alloca is inserted at AllocaInsertPt, + // otherwise alloca is inserted at the current insertion point of the + // builder. + if (!ArraySize) + Builder.SetInsertPoint(AllocaInsertPt); V = getTargetHooks().performAddrSpaceCast( *this, V, getASTAllocaAddressSpace(), LangAS::Default, Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); - Builder.restoreIP(CurIP); } return Address(V, Align); @@ -356,7 +360,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, if (CGF.CGM.getCodeGenOpts().MergeAllConstants && (Ty->isArrayType() || Ty->isRecordType()) && CGF.CGM.isTypeConstant(Ty, true)) - if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) { + if (auto Init = ConstantEmitter(CGF).tryEmitAbstract(Inner, Ty)) { if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) { auto AS = AddrSpace.getValue(); auto *GV = new llvm::GlobalVariable( @@ -411,14 +415,12 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // dynamic initialization or a cleanup and we can just return the address // of the temporary. if (Var->hasInitializer()) - return MakeAddrLValue(Object, M->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl); Var->setInitializer(CGM.EmitNullConstant(E->getType())); } LValue RefTempDst = MakeAddrLValue(Object, M->getType(), - LValueBaseInfo(AlignmentSource::Decl, - false)); + AlignmentSource::Decl); switch (getEvaluationKind(E->getType())) { default: llvm_unreachable("expected scalar or aggregate expression"); @@ -505,8 +507,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { break; case SubobjectAdjustment::FieldAdjustment: { - LValue LV = MakeAddrLValue(Object, E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + LValue LV = MakeAddrLValue(Object, E->getType(), AlignmentSource::Decl); LV = EmitLValueForField(LV, Adjustment.Field); assert(LV.isSimple() && "materialized temporary field is not a simple lvalue"); @@ -523,8 +524,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { } } - return MakeAddrLValue(Object, M->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl); } RValue @@ -568,6 +568,19 @@ static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low, return Builder.CreateMul(B1, KMul); } +bool CodeGenFunction::isNullPointerAllowed(TypeCheckKind TCK) { + return TCK == TCK_DowncastPointer || TCK == TCK_Upcast || + TCK == TCK_UpcastToVirtualBase; +} + +bool CodeGenFunction::isVptrCheckRequired(TypeCheckKind TCK, QualType Ty) { + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + return (RD && RD->hasDefinition() && RD->isDynamicClass()) && + (TCK == TCK_MemberAccess || TCK == TCK_MemberCall || + TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference || + TCK == TCK_UpcastToVirtualBase); +} + bool CodeGenFunction::sanitizePerformTypeCheck() const { return SanOpts.has(SanitizerKind::Null) | SanOpts.has(SanitizerKind::Alignment) | @@ -604,20 +617,22 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, auto PtrToAlloca = dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases()); - bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast || - TCK == TCK_UpcastToVirtualBase; + llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext()); + llvm::Value *IsNonNull = nullptr; + bool IsGuaranteedNonNull = + SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca; + bool AllowNullPointers = isNullPointerAllowed(TCK); if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) && - !SkippedChecks.has(SanitizerKind::Null) && !PtrToAlloca) { + !IsGuaranteedNonNull) { // The glvalue must not be an empty glvalue. - llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr); + IsNonNull = Builder.CreateIsNotNull(Ptr); // The IR builder can constant-fold the null check if the pointer points to // a constant. - bool PtrIsNonNull = - IsNonNull == llvm::ConstantInt::getTrue(getLLVMContext()); + IsGuaranteedNonNull = IsNonNull == True; // Skip the null check if the pointer is known to be non-null. - if (!PtrIsNonNull) { + if (!IsGuaranteedNonNull) { if (AllowNullPointers) { // When performing pointer casts, it's OK if the value is null. // Skip the remaining checks in that case. @@ -652,6 +667,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, } uint64_t AlignVal = 0; + llvm::Value *PtrAsInt = nullptr; if (SanOpts.has(SanitizerKind::Alignment) && !SkippedChecks.has(SanitizerKind::Alignment)) { @@ -662,12 +678,13 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, // The glvalue must be suitably aligned. if (AlignVal > 1 && (!PtrToAlloca || PtrToAlloca->getAlignment() < AlignVal)) { - llvm::Value *Align = - Builder.CreateAnd(Builder.CreatePtrToInt(Ptr, IntPtrTy), - llvm::ConstantInt::get(IntPtrTy, AlignVal - 1)); + PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy); + llvm::Value *Align = Builder.CreateAnd( + PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal - 1)); llvm::Value *Aligned = - Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)); - Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment)); + Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)); + if (Aligned != True) + Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment)); } } @@ -679,7 +696,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty), llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2_64(AlignVal) : 1), llvm::ConstantInt::get(Int8Ty, TCK)}; - EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData, Ptr); + EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData, + PtrAsInt ? PtrAsInt : Ptr); } // If possible, check that the vptr indicates that there is a subobject of @@ -690,13 +708,20 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, // The program has undefined behavior if: // -- the [pointer or glvalue] is used to access a non-static data member // or call a non-static member function - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (SanOpts.has(SanitizerKind::Vptr) && - !SkippedChecks.has(SanitizerKind::Vptr) && - (TCK == TCK_MemberAccess || TCK == TCK_MemberCall || - TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference || - TCK == TCK_UpcastToVirtualBase) && - RD && RD->hasDefinition() && RD->isDynamicClass()) { + !SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) { + // Ensure that the pointer is non-null before loading it. If there is no + // compile-time guarantee, reuse the run-time null check or emit a new one. + if (!IsGuaranteedNonNull) { + if (!IsNonNull) + IsNonNull = Builder.CreateIsNotNull(Ptr); + if (!Done) + Done = createBasicBlock("vptr.null"); + llvm::BasicBlock *VptrNotNull = createBasicBlock("vptr.not.null"); + Builder.CreateCondBr(IsNonNull, VptrNotNull, Done); + EmitBlock(VptrNotNull); + } + // Compute a hash of the mangled name of the type. // // FIXME: This is not guaranteed to be deterministic! Move to a @@ -709,7 +734,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, // Blacklist based on the mangled type. if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType( - Out.str())) { + SanitizerKind::Vptr, Out.str())) { llvm::hash_code TypeHash = hash_value(Out.str()); // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). @@ -789,6 +814,45 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { return false; } +llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E, + QualType EltTy) { + ASTContext &C = getContext(); + uint64_t EltSize = C.getTypeSizeInChars(EltTy).getQuantity(); + if (!EltSize) + return nullptr; + + auto *ArrayDeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); + if (!ArrayDeclRef) + return nullptr; + + auto *ParamDecl = dyn_cast<ParmVarDecl>(ArrayDeclRef->getDecl()); + if (!ParamDecl) + return nullptr; + + auto *POSAttr = ParamDecl->getAttr<PassObjectSizeAttr>(); + if (!POSAttr) + return nullptr; + + // Don't load the size if it's a lower bound. + int POSType = POSAttr->getType(); + if (POSType != 0 && POSType != 1) + return nullptr; + + // Find the implicit size parameter. + auto PassedSizeIt = SizeArguments.find(ParamDecl); + if (PassedSizeIt == SizeArguments.end()) + return nullptr; + + const ImplicitParamDecl *PassedSizeDecl = PassedSizeIt->second; + assert(LocalDeclMap.count(PassedSizeDecl) && "Passed size not loadable"); + Address AddrOfSize = LocalDeclMap.find(PassedSizeDecl)->second; + llvm::Value *SizeInBytes = EmitLoadOfScalar(AddrOfSize, /*Volatile=*/false, + C.getSizeType(), E->getExprLoc()); + llvm::Value *SizeOfElement = + llvm::ConstantInt::get(SizeInBytes->getType(), EltSize); + return Builder.CreateUDiv(SizeInBytes, SizeOfElement); +} + /// If Base is known to point to the start of an array, return the length of /// that array. Return 0 if the length cannot be determined. static llvm::Value *getArrayIndexingBound( @@ -810,9 +874,16 @@ static llvm::Value *getArrayIndexingBound( return CGF.Builder.getInt(CAT->getSize()); else if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) return CGF.getVLASize(VAT).first; + // Ignore pass_object_size here. It's not applicable on decayed pointers. } } + QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0}; + if (llvm::Value *POS = CGF.LoadPassedObjectSize(Base, EltTy)) { + IndexedType = Base->getType(); + return POS; + } + return nullptr; } @@ -894,7 +965,8 @@ void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E, /// EmitPointerWithAlignment - Given an expression of pointer type, try to /// derive a more accurate bound on the alignment of the pointer. Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, - LValueBaseInfo *BaseInfo) { + LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo) { // We allow this with ObjC object pointers because of fragile ABIs. assert(E->getType()->isPointerType() || E->getType()->isObjCObjectPointerType()); @@ -909,24 +981,35 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, // Non-converting casts (but not C's implicit conversion from void*). case CK_BitCast: case CK_NoOp: + case CK_AddressSpaceConversion: if (auto PtrTy = CE->getSubExpr()->getType()->getAs<PointerType>()) { if (PtrTy->getPointeeType()->isVoidType()) break; - LValueBaseInfo InnerInfo; - Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), &InnerInfo); - if (BaseInfo) *BaseInfo = InnerInfo; + LValueBaseInfo InnerBaseInfo; + TBAAAccessInfo InnerTBAAInfo; + Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), + &InnerBaseInfo, + &InnerTBAAInfo); + if (BaseInfo) *BaseInfo = InnerBaseInfo; + if (TBAAInfo) *TBAAInfo = InnerTBAAInfo; - // If this is an explicit bitcast, and the source l-value is - // opaque, honor the alignment of the casted-to type. - if (isa<ExplicitCastExpr>(CE) && - InnerInfo.getAlignmentSource() != AlignmentSource::Decl) { - LValueBaseInfo ExpInfo; + if (isa<ExplicitCastExpr>(CE)) { + LValueBaseInfo TargetTypeBaseInfo; + TBAAAccessInfo TargetTypeTBAAInfo; CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), - &ExpInfo); - if (BaseInfo) - BaseInfo->mergeForCast(ExpInfo); - Addr = Address(Addr.getPointer(), Align); + &TargetTypeBaseInfo, + &TargetTypeTBAAInfo); + if (TBAAInfo) + *TBAAInfo = CGM.mergeTBAAInfoForCast(*TBAAInfo, + TargetTypeTBAAInfo); + // If the source l-value is opaque, honor the alignment of the + // casted-to type. + if (InnerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) { + if (BaseInfo) + BaseInfo->mergeForCast(TargetTypeBaseInfo); + Addr = Address(Addr.getPointer(), Align); + } } if (SanOpts.has(SanitizerKind::CFIUnrelatedCast) && @@ -937,19 +1020,22 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, CodeGenFunction::CFITCK_UnrelatedCast, CE->getLocStart()); } - - return Builder.CreateBitCast(Addr, ConvertType(E->getType())); + return CE->getCastKind() != CK_AddressSpaceConversion + ? Builder.CreateBitCast(Addr, ConvertType(E->getType())) + : Builder.CreateAddrSpaceCast(Addr, + ConvertType(E->getType())); } break; // Array-to-pointer decay. case CK_ArrayToPointerDecay: - return EmitArrayToPointerDecay(CE->getSubExpr(), BaseInfo); + return EmitArrayToPointerDecay(CE->getSubExpr(), BaseInfo, TBAAInfo); // Derived-to-base conversions. case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), BaseInfo); + Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), BaseInfo, + TBAAInfo); auto Derived = CE->getSubExpr()->getType()->getPointeeCXXRecordDecl(); return GetAddressOfBaseClass(Addr, Derived, CE->path_begin(), CE->path_end(), @@ -969,6 +1055,7 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, if (UO->getOpcode() == UO_AddrOf) { LValue LV = EmitLValue(UO->getSubExpr()); if (BaseInfo) *BaseInfo = LV.getBaseInfo(); + if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo(); return LV.getAddress(); } } @@ -976,7 +1063,8 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, // TODO: conditional operators, comma. // Otherwise, use the alignment of the type. - CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), BaseInfo); + CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), BaseInfo, + TBAAInfo); return Address(EmitScalarExpr(E), Align); } @@ -1145,8 +1233,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { llvm::Value *V = LV.getPointer(); Scope.ForceCleanup({&V}); return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(), - getContext(), LV.getBaseInfo(), - LV.getTBAAInfo()); + getContext(), LV.getBaseInfo(), LV.getTBAAInfo()); } // FIXME: Is it possible to create an ExprWithCleanups that produces a // bitfield lvalue or some other non-simple lvalue? @@ -1303,7 +1390,8 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { return ConstantEmission(); // Emit as a constant. - llvm::Constant *C = CGM.EmitConstantValue(result.Val, resultType, this); + auto C = ConstantEmitter(*this).emitAbstract(refExpr->getLocation(), + result.Val, resultType); // Make sure we emit a debug reference to the global variable. // This should probably fire even for @@ -1322,13 +1410,30 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { return ConstantEmission::forValue(C); } +static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF, + const MemberExpr *ME) { + if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) { + // Try to emit static variable member expressions as DREs. + return DeclRefExpr::Create( + CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD, + /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(), + ME->getType(), ME->getValueKind()); + } + return nullptr; +} + +CodeGenFunction::ConstantEmission +CodeGenFunction::tryEmitAsConstant(const MemberExpr *ME) { + if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, ME)) + return tryEmitAsConstant(DRE); + return ConstantEmission(); +} + llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue, SourceLocation Loc) { return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(), lvalue.getType(), Loc, lvalue.getBaseInfo(), - lvalue.getTBAAInfo(), - lvalue.getTBAABaseType(), lvalue.getTBAAOffset(), - lvalue.isNontemporal()); + lvalue.getTBAAInfo(), lvalue.isNontemporal()); } static bool hasBooleanRepresentation(QualType Ty) { @@ -1412,17 +1517,17 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty, if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool)) return true; + auto &Ctx = getLLVMContext(); SanitizerScope SanScope(this); llvm::Value *Check; --End; if (!Min) { - Check = Builder.CreateICmpULE( - Value, llvm::ConstantInt::get(getLLVMContext(), End)); + Check = Builder.CreateICmpULE(Value, llvm::ConstantInt::get(Ctx, End)); } else { - llvm::Value *Upper = Builder.CreateICmpSLE( - Value, llvm::ConstantInt::get(getLLVMContext(), End)); - llvm::Value *Lower = Builder.CreateICmpSGE( - Value, llvm::ConstantInt::get(getLLVMContext(), Min)); + llvm::Value *Upper = + Builder.CreateICmpSLE(Value, llvm::ConstantInt::get(Ctx, End)); + llvm::Value *Lower = + Builder.CreateICmpSGE(Value, llvm::ConstantInt::get(Ctx, Min)); Check = Builder.CreateAnd(Upper, Lower); } llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc), @@ -1438,9 +1543,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, SourceLocation Loc, LValueBaseInfo BaseInfo, - llvm::MDNode *TBAAInfo, - QualType TBAABaseType, - uint64_t TBAAOffset, + TBAAAccessInfo TBAAInfo, bool isNontemporal) { if (!CGM.getCodeGenOpts().PreserveVec3Type) { // For better performance, handle vector loads differently. @@ -1480,14 +1583,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, Load->getContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1))); Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); } - if (TBAAInfo) { - bool MayAlias = BaseInfo.getMayAlias(); - llvm::MDNode *TBAA = MayAlias - ? CGM.getTBAAInfo(getContext().CharTy) - : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); - if (TBAA) - CGM.DecorateInstructionWithTBAA(Load, TBAA, MayAlias); - } + + CGM.DecorateInstructionWithTBAA(Load, TBAAInfo); if (EmitScalarRangeCheck(Load, Ty, Loc)) { // In order to prevent the optimizer from throwing away the check, don't @@ -1527,11 +1624,8 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, bool Volatile, QualType Ty, LValueBaseInfo BaseInfo, - llvm::MDNode *TBAAInfo, - bool isInit, QualType TBAABaseType, - uint64_t TBAAOffset, - bool isNontemporal) { - + TBAAAccessInfo TBAAInfo, + bool isInit, bool isNontemporal) { if (!CGM.getCodeGenOpts().PreserveVec3Type) { // Handle vectors differently to get better performance. if (Ty->isVectorType()) { @@ -1571,22 +1665,15 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, llvm::ConstantAsMetadata::get(Builder.getInt32(1))); Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); } - if (TBAAInfo) { - bool MayAlias = BaseInfo.getMayAlias(); - llvm::MDNode *TBAA = MayAlias - ? CGM.getTBAAInfo(getContext().CharTy) - : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); - if (TBAA) - CGM.DecorateInstructionWithTBAA(Store, TBAA, MayAlias); - } + + CGM.DecorateInstructionWithTBAA(Store, TBAAInfo); } void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit) { EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(), lvalue.getType(), lvalue.getBaseInfo(), - lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(), - lvalue.getTBAAOffset(), lvalue.isNontemporal()); + lvalue.getTBAAInfo(), isInit, lvalue.isNontemporal()); } /// EmitLoadOfLValue - Given an expression that represents a value lvalue, this @@ -2116,39 +2203,48 @@ static LValue EmitThreadPrivateVarDeclLValue( llvm::Type *RealVarTy, SourceLocation Loc) { Addr = CGF.CGM.getOpenMPRuntime().getAddrOfThreadPrivate(CGF, VD, Addr, Loc); Addr = CGF.Builder.CreateElementBitCast(Addr, RealVarTy); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - return CGF.MakeAddrLValue(Addr, T, BaseInfo); + return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl); } -Address CodeGenFunction::EmitLoadOfReference(Address Addr, - const ReferenceType *RefTy, - LValueBaseInfo *BaseInfo) { - llvm::Value *Ptr = Builder.CreateLoad(Addr); - return Address(Ptr, getNaturalTypeAlignment(RefTy->getPointeeType(), - BaseInfo, /*forPointee*/ true)); +Address +CodeGenFunction::EmitLoadOfReference(LValue RefLVal, + LValueBaseInfo *PointeeBaseInfo, + TBAAAccessInfo *PointeeTBAAInfo) { + llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(), + RefLVal.isVolatile()); + CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo()); + + CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(), + PointeeBaseInfo, PointeeTBAAInfo, + /* forPointeeType= */ true); + return Address(Load, Align); } -LValue CodeGenFunction::EmitLoadOfReferenceLValue(Address RefAddr, - const ReferenceType *RefTy) { - LValueBaseInfo BaseInfo; - Address Addr = EmitLoadOfReference(RefAddr, RefTy, &BaseInfo); - return MakeAddrLValue(Addr, RefTy->getPointeeType(), BaseInfo); +LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) { + LValueBaseInfo PointeeBaseInfo; + TBAAAccessInfo PointeeTBAAInfo; + Address PointeeAddr = EmitLoadOfReference(RefLVal, &PointeeBaseInfo, + &PointeeTBAAInfo); + return MakeAddrLValue(PointeeAddr, RefLVal.getType()->getPointeeType(), + PointeeBaseInfo, PointeeTBAAInfo); } Address CodeGenFunction::EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy, - LValueBaseInfo *BaseInfo) { + LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo) { llvm::Value *Addr = Builder.CreateLoad(Ptr); return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(), - BaseInfo, + BaseInfo, TBAAInfo, /*forPointeeType=*/true)); } LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr, const PointerType *PtrTy) { LValueBaseInfo BaseInfo; - Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &BaseInfo); - return MakeAddrLValue(Addr, PtrTy->getPointeeType(), BaseInfo); + TBAAAccessInfo TBAAInfo; + Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &BaseInfo, &TBAAInfo); + return MakeAddrLValue(Addr, PtrTy->getPointeeType(), BaseInfo, TBAAInfo); } static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, @@ -2165,18 +2261,15 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy); CharUnits Alignment = CGF.getContext().getDeclAlign(VD); Address Addr(V, Alignment); - LValue LV; // Emit reference to the private copy of the variable if it is an OpenMP // threadprivate variable. if (CGF.getLangOpts().OpenMP && VD->hasAttr<OMPThreadPrivateDeclAttr>()) return EmitThreadPrivateVarDeclLValue(CGF, VD, T, Addr, RealVarTy, E->getExprLoc()); - if (auto RefTy = VD->getType()->getAs<ReferenceType>()) { - LV = CGF.EmitLoadOfReferenceLValue(Addr, RefTy); - } else { - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - LV = CGF.MakeAddrLValue(Addr, T, BaseInfo); - } + LValue LV = VD->getType()->isReferenceType() ? + CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(), + AlignmentSource::Decl) : + CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl); setObjCGCLValueClass(CGF.getContext(), E, LV); return LV; } @@ -2209,8 +2302,8 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E, const FunctionDecl *FD) { llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, FD); CharUnits Alignment = CGF.getContext().getDeclAlign(FD); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - return CGF.MakeAddrLValue(V, E->getType(), Alignment, BaseInfo); + return CGF.MakeAddrLValue(V, E->getType(), Alignment, + AlignmentSource::Decl); } static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD, @@ -2265,44 +2358,52 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { VD->isUsableInConstantExpressions(getContext()) && VD->checkInitIsICE() && // Do not emit if it is private OpenMP variable. - !(E->refersToEnclosingVariableOrCapture() && CapturedStmtInfo && - LocalDeclMap.count(VD))) { + !(E->refersToEnclosingVariableOrCapture() && + ((CapturedStmtInfo && + (LocalDeclMap.count(VD->getCanonicalDecl()) || + CapturedStmtInfo->lookup(VD->getCanonicalDecl()))) || + LambdaCaptureFields.lookup(VD->getCanonicalDecl()) || + isa<BlockDecl>(CurCodeDecl)))) { llvm::Constant *Val = - CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this); + ConstantEmitter(*this).emitAbstract(E->getLocation(), + *VD->evaluateValue(), + VD->getType()); assert(Val && "failed to emit reference constant expression"); // FIXME: Eventually we will want to emit vector element references. // Should we be using the alignment of the constant pointer we emitted? - CharUnits Alignment = getNaturalTypeAlignment(E->getType(), nullptr, - /*pointee*/ true); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - return MakeAddrLValue(Address(Val, Alignment), T, BaseInfo); + CharUnits Alignment = getNaturalTypeAlignment(E->getType(), + /* BaseInfo= */ nullptr, + /* TBAAInfo= */ nullptr, + /* forPointeeType= */ true); + return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl); } // Check for captured variables. if (E->refersToEnclosingVariableOrCapture()) { + VD = VD->getCanonicalDecl(); if (auto *FD = LambdaCaptureFields.lookup(VD)) return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); else if (CapturedStmtInfo) { auto I = LocalDeclMap.find(VD); if (I != LocalDeclMap.end()) { - if (auto RefTy = VD->getType()->getAs<ReferenceType>()) - return EmitLoadOfReferenceLValue(I->second, RefTy); + if (VD->getType()->isReferenceType()) + return EmitLoadOfReferenceLValue(I->second, VD->getType(), + AlignmentSource::Decl); return MakeAddrLValue(I->second, T); } LValue CapLVal = EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD), CapturedStmtInfo->getContextValue()); - bool MayAlias = CapLVal.getBaseInfo().getMayAlias(); return MakeAddrLValue( Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)), - CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl, MayAlias)); + CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl), + CapLVal.getTBAAInfo()); } assert(isa<BlockDecl>(CurCodeDecl)); Address addr = GetAddrOfBlockDecl(VD, VD->hasAttr<BlocksAttr>()); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - return MakeAddrLValue(addr, T, BaseInfo); + return MakeAddrLValue(addr, T, AlignmentSource::Decl); } } @@ -2316,8 +2417,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (ND->hasAttr<WeakRefAttr>()) { const auto *VD = cast<ValueDecl>(ND); ConstantAddress Aliasee = CGM.GetWeakRefReference(VD); - return MakeAddrLValue(Aliasee, T, - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Aliasee, T, AlignmentSource::Decl); } if (const auto *VD = dyn_cast<VarDecl>(ND)) { @@ -2359,13 +2459,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } // Drill into reference types. - LValue LV; - if (auto RefTy = VD->getType()->getAs<ReferenceType>()) { - LV = EmitLoadOfReferenceLValue(addr, RefTy); - } else { - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - LV = MakeAddrLValue(addr, T, BaseInfo); - } + LValue LV = VD->getType()->isReferenceType() ? + EmitLoadOfReferenceLValue(addr, VD->getType(), AlignmentSource::Decl) : + MakeAddrLValue(addr, T, AlignmentSource::Decl); bool isLocalStorage = VD->hasLocalStorage(); @@ -2410,8 +2506,10 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); LValueBaseInfo BaseInfo; - Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &BaseInfo); - LValue LV = MakeAddrLValue(Addr, T, BaseInfo); + TBAAAccessInfo TBAAInfo; + Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &BaseInfo, + &TBAAInfo); + LValue LV = MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); LV.getQuals().setAddressSpace(ExprTy.getAddressSpace()); // We should not generate __weak write barrier on indirect reference @@ -2443,7 +2541,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { (E->getOpcode() == UO_Real ? emitAddrOfRealComponent(LV.getAddress(), LV.getType()) : emitAddrOfImagComponent(LV.getAddress(), LV.getType())); - LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo()); + LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, T)); ElemLV.getQuals().addQualifiers(LV.getQuals()); return ElemLV; } @@ -2463,14 +2562,12 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E), - E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + E->getType(), AlignmentSource::Decl); } LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) { return MakeAddrLValue(CGM.GetAddrOfConstantStringFromObjCEncode(E), - E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + E->getType(), AlignmentSource::Decl); } LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { @@ -2482,7 +2579,6 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { StringRef NameItems[] = { PredefinedExpr::getIdentTypeName(E->getIdentType()), FnName}; std::string GVName = llvm::join(NameItems, NameItems + 2, "."); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); if (auto *BD = dyn_cast<BlockDecl>(CurCodeDecl)) { std::string Name = SL->getString(); if (!Name.empty()) { @@ -2491,14 +2587,14 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { if (Discriminator) Name += "_" + Twine(Discriminator + 1).str(); auto C = CGM.GetAddrOfConstantCString(Name, GVName.c_str()); - return MakeAddrLValue(C, E->getType(), BaseInfo); + return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl); } else { auto C = CGM.GetAddrOfConstantCString(FnName, GVName.c_str()); - return MakeAddrLValue(C, E->getType(), BaseInfo); + return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl); } } auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName); - return MakeAddrLValue(C, E->getType(), BaseInfo); + return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl); } /// Emit a type description suitable for use by a runtime sanitizer library. The @@ -2556,6 +2652,9 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) { llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { llvm::Type *TargetTy = IntPtrTy; + if (V->getType() == TargetTy) + return V; + // Floating-point types which fit into intptr_t are bitcast to integers // and then passed directly (after zero-extension, if necessary). if (V->getType()->isFloatingPointTy()) { @@ -2685,13 +2784,16 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF, assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable); bool NeedsAbortSuffix = IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable; + bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime; const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler]; const StringRef CheckName = CheckInfo.Name; - std::string FnName = - ("__ubsan_handle_" + CheckName + - (CheckInfo.Version ? "_v" + llvm::utostr(CheckInfo.Version) : "") + - (NeedsAbortSuffix ? "_abort" : "")) - .str(); + std::string FnName = "__ubsan_handle_" + CheckName.str(); + if (CheckInfo.Version && !MinimalRuntime) + FnName += "_v" + llvm::utostr(CheckInfo.Version); + if (MinimalRuntime) + FnName += "_minimal"; + if (NeedsAbortSuffix) + FnName += "_abort"; bool MayReturn = !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable; @@ -2723,7 +2825,7 @@ void CodeGenFunction::EmitCheck( assert(IsSanitizerScope); assert(Checked.size() > 0); assert(CheckHandler >= 0 && - CheckHandler < sizeof(SanitizerHandlers) / sizeof(*SanitizerHandlers)); + size_t(CheckHandler) < llvm::array_lengthof(SanitizerHandlers)); const StringRef CheckName = SanitizerHandlers[CheckHandler].Name; llvm::Value *FatalCond = nullptr; @@ -2778,24 +2880,26 @@ void CodeGenFunction::EmitCheck( // representing operand values. SmallVector<llvm::Value *, 4> Args; SmallVector<llvm::Type *, 4> ArgTypes; - Args.reserve(DynamicArgs.size() + 1); - ArgTypes.reserve(DynamicArgs.size() + 1); + if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) { + Args.reserve(DynamicArgs.size() + 1); + ArgTypes.reserve(DynamicArgs.size() + 1); - // Emit handler arguments and create handler function type. - if (!StaticArgs.empty()) { - llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs); - auto *InfoPtr = - new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false, - llvm::GlobalVariable::PrivateLinkage, Info); - InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr); - Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy)); - ArgTypes.push_back(Int8PtrTy); - } + // Emit handler arguments and create handler function type. + if (!StaticArgs.empty()) { + llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs); + auto *InfoPtr = + new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false, + llvm::GlobalVariable::PrivateLinkage, Info); + InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr); + Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy)); + ArgTypes.push_back(Int8PtrTy); + } - for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) { - Args.push_back(EmitCheckValue(DynamicArgs[i])); - ArgTypes.push_back(IntPtrTy); + for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) { + Args.push_back(EmitCheckValue(DynamicArgs[i])); + ArgTypes.push_back(IntPtrTy); + } } llvm::FunctionType *FnType = @@ -3005,14 +3109,14 @@ llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { } Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, - LValueBaseInfo *BaseInfo) { + LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo) { assert(E->getType()->isArrayType() && "Array to pointer decay must have array source type!"); // Expressions of array type can't be bitfields or vector elements. LValue LV = EmitLValue(E); Address Addr = LV.getAddress(); - if (BaseInfo) *BaseInfo = LV.getBaseInfo(); // If the array type was an incomplete type, we need to make sure // the decay ends up being the right type. @@ -3027,7 +3131,15 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, Addr = Builder.CreateStructGEP(Addr, 0, CharUnits::Zero(), "arraydecay"); } + // The result of this decay conversion points to an array element within the + // base lvalue. However, since TBAA currently does not support representing + // accesses to elements of member arrays, we conservatively represent accesses + // to the pointee object as if it had no any base lvalue specified. + // TODO: Support TBAA for member arrays. QualType EltType = E->getType()->castAsArrayTypeUnsafe()->getElementType(); + if (BaseInfo) *BaseInfo = LV.getBaseInfo(); + if (TBAAInfo) *TBAAInfo = CGM.getTBAAAccessInfo(EltType); + return Builder.CreateElementBitCast(Addr, ConvertTypeForMem(EltType)); } @@ -3152,9 +3264,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, LValue LHS = EmitLValue(E->getBase()); auto *Idx = EmitIdxAfterBase(/*Promote*/false); assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); - return LValue::MakeVectorElt(LHS.getAddress(), Idx, - E->getBase()->getType(), - LHS.getBaseInfo()); + return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(), + LHS.getBaseInfo(), TBAAAccessInfo()); } // All the other cases basically behave like simple offsetting. @@ -3168,17 +3279,19 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, QualType EltType = LV.getType()->castAs<VectorType>()->getElementType(); Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true, SignedIndices, E->getExprLoc()); - return MakeAddrLValue(Addr, EltType, LV.getBaseInfo()); + return MakeAddrLValue(Addr, EltType, LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, EltType)); } - LValueBaseInfo BaseInfo; + LValueBaseInfo EltBaseInfo; + TBAAAccessInfo EltTBAAInfo; Address Addr = Address::invalid(); if (const VariableArrayType *vla = getContext().getAsVariableArrayType(E->getType())) { // The base must be a pointer, which is not an aggregate. Emit // it. It needs to be emitted first in case it's what captures // the VLA bounds. - Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo); + Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); auto *Idx = EmitIdxAfterBase(/*Promote*/true); // The element count here is the total number of non-VLA elements. @@ -3202,7 +3315,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // Indexing over an interface, as in "NSString *P; P[4];" // Emit the base pointer. - Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo); + Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); auto *Idx = EmitIdxAfterBase(/*Promote*/true); CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT); @@ -3249,19 +3362,18 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices, E->getExprLoc()); - BaseInfo = ArrayLV.getBaseInfo(); + EltBaseInfo = ArrayLV.getBaseInfo(); + EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType()); } else { // The base must be a pointer; emit it with an estimate of its alignment. - Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo); + Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); auto *Idx = EmitIdxAfterBase(/*Promote*/true); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices, E->getExprLoc()); } - LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo); - - // TODO: Preserve/extend path TBAA metadata? + LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); if (getLangOpts().ObjC1 && getLangOpts().getGC() != LangOptions::NonGC) { @@ -3273,6 +3385,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, LValueBaseInfo &BaseInfo, + TBAAAccessInfo &TBAAInfo, QualType BaseTy, QualType ElTy, bool IsLowerBound) { LValue BaseLVal; @@ -3299,12 +3412,15 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, return CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(ElTy)); } - LValueBaseInfo TypeInfo; - CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeInfo); - BaseInfo.mergeForCast(TypeInfo); + LValueBaseInfo TypeBaseInfo; + TBAAAccessInfo TypeTBAAInfo; + CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeBaseInfo, + &TypeTBAAInfo); + BaseInfo.mergeForCast(TypeBaseInfo); + TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo); return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align); } - return CGF.EmitPointerWithAlignment(Base, &BaseInfo); + return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo); } LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, @@ -3404,13 +3520,14 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, Address EltPtr = Address::invalid(); LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; if (auto *VLA = getContext().getAsVariableArrayType(ResultExprTy)) { // The base must be a pointer, which is not an aggregate. Emit // it. It needs to be emitted first in case it's what captures // the VLA bounds. Address Base = - emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, BaseTy, - VLA->getElementType(), IsLowerBound); + emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo, + BaseTy, VLA->getElementType(), IsLowerBound); // The element count here is the total number of non-VLA elements. llvm::Value *NumElements = getVLASize(VLA).first; @@ -3446,15 +3563,17 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), /*SignedIndices=*/false, E->getExprLoc()); BaseInfo = ArrayLV.getBaseInfo(); + TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy); } else { Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, - BaseTy, ResultExprTy, IsLowerBound); + TBAAInfo, BaseTy, ResultExprTy, + IsLowerBound); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), /*SignedIndices=*/false, E->getExprLoc()); } - return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo); + return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo, TBAAInfo); } LValue CodeGenFunction:: @@ -3467,9 +3586,10 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { // If it is a pointer to a vector, emit the address and form an lvalue with // it. LValueBaseInfo BaseInfo; - Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo); + TBAAAccessInfo TBAAInfo; + Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo); const PointerType *PT = E->getBase()->getType()->getAs<PointerType>(); - Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo); + Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo, TBAAInfo); Base.getQuals().removeObjCGCAttr(); } else if (E->getBase()->isGLValue()) { // Otherwise, if the base is an lvalue ( as in the case of foo.x.x), @@ -3486,7 +3606,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { Address VecMem = CreateMemTemp(E->getBase()->getType()); Builder.CreateStore(Vec, VecMem); Base = MakeAddrLValue(VecMem, E->getBase()->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); } QualType type = @@ -3500,7 +3620,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Constant *CV = llvm::ConstantDataVector::get(getLLVMContext(), Indices); return LValue::MakeExtVectorElt(Base.getAddress(), CV, type, - Base.getBaseInfo()); + Base.getBaseInfo(), TBAAAccessInfo()); } assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!"); @@ -3511,16 +3631,22 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { CElts.push_back(BaseElts->getAggregateElement(Indices[i])); llvm::Constant *CV = llvm::ConstantVector::get(CElts); return LValue::MakeExtVectorElt(Base.getExtVectorAddress(), CV, type, - Base.getBaseInfo()); + Base.getBaseInfo(), TBAAAccessInfo()); } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { + if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) { + EmitIgnoredExpr(E->getBase()); + return EmitDeclRefLValue(DRE); + } + Expr *BaseExpr = E->getBase(); // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. LValue BaseLV; if (E->isArrow()) { LValueBaseInfo BaseInfo; - Address Addr = EmitPointerWithAlignment(BaseExpr, &BaseInfo); + TBAAAccessInfo TBAAInfo; + Address Addr = EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo); QualType PtrTy = BaseExpr->getType()->getPointeeType(); SanitizerSet SkippedChecks; bool IsBaseCXXThis = IsWrappedCXXThis(BaseExpr); @@ -3530,7 +3656,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { SkippedChecks.set(SanitizerKind::Null, true); EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy, /*Alignment=*/CharUnits::Zero(), SkippedChecks); - BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo); + BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo); } else BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess); @@ -3541,9 +3667,6 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { return LV; } - if (auto *VD = dyn_cast<VarDecl>(ND)) - return EmitGlobalVarDeclLValue(*this, E, VD); - if (const auto *FD = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, FD); @@ -3610,15 +3733,6 @@ static bool hasAnyVptr(const QualType Type, const ASTContext &Context) { LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field) { LValueBaseInfo BaseInfo = base.getBaseInfo(); - AlignmentSource fieldAlignSource = - getFieldAlignmentSource(BaseInfo.getAlignmentSource()); - LValueBaseInfo FieldBaseInfo(fieldAlignSource, BaseInfo.getMayAlias()); - - QualType type = field->getType(); - const RecordDecl *rec = field->getParent(); - if (rec->isUnion() || rec->hasAttr<MayAliasAttr>() || type->isVectorType()) - FieldBaseInfo.setMayAlias(true); - bool mayAlias = FieldBaseInfo.getMayAlias(); if (field->isBitField()) { const CGRecordLayout &RL = @@ -3638,19 +3752,53 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, QualType fieldType = field->getType().withCVRQualifiers(base.getVRQualifiers()); - return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo); + // TODO: Support TBAA for bit fields. + LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource()); + return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo, + TBAAAccessInfo()); + } + + // Fields of may-alias structures are may-alias themselves. + // FIXME: this should get propagated down through anonymous structs + // and unions. + QualType FieldType = field->getType(); + const RecordDecl *rec = field->getParent(); + AlignmentSource BaseAlignSource = BaseInfo.getAlignmentSource(); + LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(BaseAlignSource)); + TBAAAccessInfo FieldTBAAInfo; + if (base.getTBAAInfo().isMayAlias() || + rec->hasAttr<MayAliasAttr>() || FieldType->isVectorType()) { + FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo(); + } else if (rec->isUnion()) { + // TODO: Support TBAA for unions. + FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo(); + } else { + // If no base type been assigned for the base access, then try to generate + // one for this base lvalue. + FieldTBAAInfo = base.getTBAAInfo(); + if (!FieldTBAAInfo.BaseType) { + FieldTBAAInfo.BaseType = CGM.getTBAABaseTypeInfo(base.getType()); + assert(!FieldTBAAInfo.Offset && + "Nonzero offset for an access with no base type!"); + } + + // Adjust offset to be relative to the base type. + const ASTRecordLayout &Layout = + getContext().getASTRecordLayout(field->getParent()); + unsigned CharWidth = getContext().getCharWidth(); + if (FieldTBAAInfo.BaseType) + FieldTBAAInfo.Offset += + Layout.getFieldOffset(field->getFieldIndex()) / CharWidth; + + // Update the final access type. + FieldTBAAInfo.AccessType = CGM.getTBAATypeInfo(FieldType); } Address addr = base.getAddress(); - unsigned cvr = base.getVRQualifiers(); - bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA; + unsigned RecordCVR = base.getVRQualifiers(); if (rec->isUnion()) { // For unions, there is no pointer adjustment. - assert(!type->isReferenceType() && "union has reference member"); - // TODO: handle path-aware TBAA for union. - TBAAPath = false; - - const auto FieldType = field->getType(); + assert(!FieldType->isReferenceType() && "union has reference member"); if (CGM.getCodeGenOpts().StrictVTablePointers && hasAnyVptr(FieldType, getContext())) // Because unions can easily skip invariant.barriers, we need to add @@ -3662,34 +3810,16 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, addr = emitAddrOfFieldStorage(*this, addr, field); // If this is a reference field, load the reference right now. - if (const ReferenceType *refType = type->getAs<ReferenceType>()) { - llvm::LoadInst *load = Builder.CreateLoad(addr, "ref"); - if (cvr & Qualifiers::Volatile) load->setVolatile(true); - - // Loading the reference will disable path-aware TBAA. - TBAAPath = false; - if (CGM.shouldUseTBAA()) { - llvm::MDNode *tbaa; - if (mayAlias) - tbaa = CGM.getTBAAInfo(getContext().CharTy); - else - tbaa = CGM.getTBAAInfo(type); - if (tbaa) - CGM.DecorateInstructionWithTBAA(load, tbaa); - } - - mayAlias = false; - type = refType->getPointeeType(); - - CharUnits alignment = - getNaturalTypeAlignment(type, &FieldBaseInfo, /*pointee*/ true); - FieldBaseInfo.setMayAlias(false); - addr = Address(load, alignment); + if (FieldType->isReferenceType()) { + LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo, + FieldTBAAInfo); + if (RecordCVR & Qualifiers::Volatile) + RefLVal.getQuals().setVolatile(true); + addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo); - // Qualifiers on the struct don't apply to the referencee, and - // we'll pick up CVR from the actual type later, so reset these - // additional qualifiers now. - cvr = 0; + // Qualifiers on the struct don't apply to the referencee. + RecordCVR = 0; + FieldType = FieldType->getPointeeType(); } } @@ -3697,36 +3827,19 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, // for both unions and structs. A union needs a bitcast, a struct element // will need a bitcast if the LLVM type laid out doesn't match the desired // type. - addr = Builder.CreateElementBitCast(addr, - CGM.getTypes().ConvertTypeForMem(type), - field->getName()); + addr = Builder.CreateElementBitCast( + addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName()); if (field->hasAttr<AnnotateAttr>()) addr = EmitFieldAnnotations(field, addr); - LValue LV = MakeAddrLValue(addr, type, FieldBaseInfo); - LV.getQuals().addCVRQualifiers(cvr); - if (TBAAPath) { - const ASTRecordLayout &Layout = - getContext().getASTRecordLayout(field->getParent()); - // Set the base type to be the base type of the base LValue and - // update offset to be relative to the base type. - LV.setTBAABaseType(mayAlias ? getContext().CharTy : base.getTBAABaseType()); - LV.setTBAAOffset(mayAlias ? 0 : base.getTBAAOffset() + - Layout.getFieldOffset(field->getFieldIndex()) / - getContext().getCharWidth()); - } + LValue LV = MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo); + LV.getQuals().addCVRQualifiers(RecordCVR); // __weak attribute on a field is ignored. if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak) LV.getQuals().removeObjCGCAttr(); - // Fields of may_alias structs act like 'char' for TBAA purposes. - // FIXME: this should get propagated down through anonymous structs - // and unions. - if (mayAlias && LV.getTBAAInfo()) - LV.setTBAAInfo(CGM.getTBAAInfo(getContext().CharTy)); - return LV; } @@ -3744,19 +3857,20 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base, llvm::Type *llvmType = ConvertTypeForMem(FieldType); V = Builder.CreateElementBitCast(V, llvmType, Field->getName()); - // TODO: access-path TBAA? + // TODO: Generate TBAA information that describes this access as a structure + // member access and not just an access to an object of the field's type. This + // should be similar to what we do in EmitLValueForField(). LValueBaseInfo BaseInfo = Base.getBaseInfo(); - LValueBaseInfo FieldBaseInfo( - getFieldAlignmentSource(BaseInfo.getAlignmentSource()), - BaseInfo.getMayAlias()); - return MakeAddrLValue(V, FieldType, FieldBaseInfo); + AlignmentSource FieldAlignSource = BaseInfo.getAlignmentSource(); + LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(FieldAlignSource)); + return MakeAddrLValue(V, FieldType, FieldBaseInfo, + CGM.getTBAAInfoForSubobject(Base, FieldType)); } LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); if (E->isFileScope()) { ConstantAddress GlobalPtr = CGM.GetAddrOfConstantCompoundLiteral(E); - return MakeAddrLValue(GlobalPtr, E->getType(), BaseInfo); + return MakeAddrLValue(GlobalPtr, E->getType(), AlignmentSource::Decl); } if (E->getType()->isVariablyModifiedType()) // make sure to emit the VLA size. @@ -3764,7 +3878,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ Address DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral"); const Expr *InitExpr = E->getInitializer(); - LValue Result = MakeAddrLValue(DeclPtr, E->getType(), BaseInfo); + LValue Result = MakeAddrLValue(DeclPtr, E->getType(), AlignmentSource::Decl); EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(), /*Init*/ true); @@ -3863,10 +3977,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { AlignmentSource alignSource = std::max(lhs->getBaseInfo().getAlignmentSource(), rhs->getBaseInfo().getAlignmentSource()); - bool MayAlias = lhs->getBaseInfo().getMayAlias() || - rhs->getBaseInfo().getMayAlias(); - return MakeAddrLValue(result, expr->getType(), - LValueBaseInfo(alignSource, MayAlias)); + TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForConditionalOperator( + lhs->getTBAAInfo(), rhs->getTBAAInfo()); + return MakeAddrLValue(result, expr->getType(), LValueBaseInfo(alignSource), + TBAAInfo); } else { assert((lhs || rhs) && "both operands of glvalue conditional are throw-expressions?"); @@ -3964,7 +4078,11 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { This, DerivedClassDecl, E->path_begin(), E->path_end(), /*NullCheckValue=*/false, E->getExprLoc()); - return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo()); + // TODO: Support accesses to members of base classes in TBAA. For now, we + // conservatively pretend that the complete object is of the base class + // type. + return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, E->getType())); } case CK_ToUnion: return EmitAggExprToLValue(E); @@ -3991,7 +4109,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { /*MayBeNull=*/false, CFITCK_DerivedCast, E->getLocStart()); - return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo()); + return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, E->getType())); } case CK_LValueBitCast: { // This must be a reinterpret_cast (or c-style equivalent). @@ -4007,13 +4126,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { /*MayBeNull=*/false, CFITCK_UnrelatedCast, E->getLocStart()); - return MakeAddrLValue(V, E->getType(), LV.getBaseInfo()); + return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, E->getType())); } case CK_ObjCObjectLValueCast: { LValue LV = EmitLValue(E->getSubExpr()); Address V = Builder.CreateElementBitCast(LV.getAddress(), ConvertType(E->getType())); - return MakeAddrLValue(V, E->getType(), LV.getBaseInfo()); + return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(), + CGM.getTBAAInfoForSubobject(LV, E->getType())); } case CK_ZeroToOCLQueue: llvm_unreachable("NULL to OpenCL queue lvalue cast is not valid"); @@ -4202,7 +4323,7 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { if (!RV.isScalar()) return MakeAddrLValue(RV.getAggregateAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); assert(E->getCallReturnType(getContext())->isReferenceType() && "Can't have a scalar return unless the return type is a " @@ -4221,8 +4342,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { && "binding l-value to type which needs a temporary"); AggValueSlot Slot = CreateAggTemp(E->getType()); EmitCXXConstructExpr(E, Slot); - return MakeAddrLValue(Slot.getAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl); } LValue @@ -4237,7 +4357,7 @@ Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) { LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) { return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); } LValue @@ -4246,16 +4366,14 @@ CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { Slot.setExternallyDestructed(); EmitAggExpr(E->getSubExpr(), Slot); EmitCXXTemporary(E->getTemporary(), E->getType(), Slot.getAddress()); - return MakeAddrLValue(Slot.getAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl); } LValue CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) { AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue"); EmitLambdaExpr(E, Slot); - return MakeAddrLValue(Slot.getAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl); } LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { @@ -4263,7 +4381,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { if (!RV.isScalar()) return MakeAddrLValue(RV.getAggregateAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); assert(E->getMethodDecl()->getReturnType()->isReferenceType() && "Can't have a scalar return unless the return type is a " @@ -4275,8 +4393,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) { Address V = CGM.getObjCRuntime().GetAddrOfSelector(*this, E->getSelector()); - return MakeAddrLValue(V, E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + return MakeAddrLValue(V, E->getType(), AlignmentSource::Decl); } llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface, @@ -4320,7 +4437,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); return MakeAddrLValue(RV.getAggregateAddress(), E->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); } RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee, @@ -4358,10 +4475,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee SanitizerScope SanScope(this); llvm::Constant *FTRTTIConst = CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true); - llvm::Type *PrefixStructTyElems[] = { - PrefixSig->getType(), - FTRTTIConst->getType() - }; + llvm::Type *PrefixStructTyElems[] = {PrefixSig->getType(), Int32Ty}; llvm::StructType *PrefixStructTy = llvm::StructType::get( CGM.getLLVMContext(), PrefixStructTyElems, /*isPacked=*/true); @@ -4382,8 +4496,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee EmitBlock(TypeCheck); llvm::Value *CalleeRTTIPtr = Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 1); - llvm::Value *CalleeRTTI = + llvm::Value *CalleeRTTIEncoded = Builder.CreateAlignedLoad(CalleeRTTIPtr, getPointerAlign()); + llvm::Value *CalleeRTTI = + DecodeAddrUsedInPrologue(CalleePtr, CalleeRTTIEncoded); llvm::Value *CalleeRTTIMatch = Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst); llvm::Constant *StaticData[] = { @@ -4405,7 +4521,12 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee SanitizerScope SanScope(this); EmitSanitizerStatReport(llvm::SanStat_CFI_ICall); - llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0)); + llvm::Metadata *MD; + if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers) + MD = CGM.CreateMetadataIdentifierGeneralized(QualType(FnType, 0)); + else + MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0)); + llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD); llvm::Value *CalleePtr = Callee.getFunctionPointer(); @@ -4513,10 +4634,12 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { = E->getRHS()->getType()->getAs<MemberPointerType>(); LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; Address MemberAddr = - EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo); + EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo, + &TBAAInfo); - return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo); + return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo, TBAAInfo); } /// Given the address of a temporary variable, produce an r-value of @@ -4524,8 +4647,7 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { RValue CodeGenFunction::convertTempToRValue(Address addr, QualType type, SourceLocation loc) { - LValue lvalue = MakeAddrLValue(addr, type, - LValueBaseInfo(AlignmentSource::Decl, false)); + LValue lvalue = MakeAddrLValue(addr, type, AlignmentSource::Decl); switch (getEvaluationKind(type)) { case TEK_Complex: return RValue::getComplex(EmitLoadOfComplex(lvalue, loc)); @@ -4580,9 +4702,8 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF, if (ov == resultExpr && ov->isRValue() && !forLValue && CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) { CGF.EmitAggExpr(ov->getSourceExpr(), slot); - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); LValue LV = CGF.MakeAddrLValue(slot.getAddress(), ov->getType(), - BaseInfo); + AlignmentSource::Decl); opaqueData = OVMA::bind(CGF, ov, LV); result.RV = slot.asRValue(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp index a05a088f09191..1ab8433864c4b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp @@ -124,24 +124,7 @@ public: } // l-values. - void VisitDeclRefExpr(DeclRefExpr *E) { - // For aggregates, we should always be able to emit the variable - // as an l-value unless it's a reference. This is due to the fact - // that we can't actually ever see a normal l2r conversion on an - // aggregate in C++, and in C there's no language standard - // actively preventing us from listing variables in the captures - // list of a block. - if (E->getDecl()->getType()->isReferenceType()) { - if (CodeGenFunction::ConstantEmission result - = CGF.tryEmitAsConstant(E)) { - EmitFinalDestCopy(E->getType(), result.getReferenceLValue(CGF, E)); - return; - } - } - - EmitAggLoadOfLValue(E); - } - + void VisitDeclRefExpr(DeclRefExpr *E) { EmitAggLoadOfLValue(E); } void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); } void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); } void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp index ab170245284ce..41bb199ffde73 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp @@ -16,6 +16,7 @@ #include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" +#include "ConstantEmitter.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/IR/CallSite.h" @@ -367,9 +368,11 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( } else { if (SanOpts.has(SanitizerKind::CFINVCall) && MD->getParent()->isDynamicClass()) { - llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy, MD->getParent()); - EmitVTablePtrCheckForCall(MD->getParent(), VTable, CFITCK_NVCall, - CE->getLocStart()); + llvm::Value *VTable; + const CXXRecordDecl *RD; + std::tie(VTable, RD) = + CGM.getCXXABI().LoadVTablePtr(*this, This, MD->getParent()); + EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getLocStart()); } if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier) @@ -681,8 +684,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, // Emit the array size expression. // We multiply the size of all dimensions for NumElements. // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6. - numElements = CGF.CGM.EmitConstantExpr(e->getArraySize(), - CGF.getContext().getSizeType(), &CGF); + numElements = + ConstantEmitter(CGF).tryEmitAbstract(e->getArraySize(), e->getType()); if (!numElements) numElements = CGF.EmitScalarExpr(e->getArraySize()); assert(isa<llvm::IntegerType>(numElements->getType())); @@ -1310,29 +1313,44 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, llvm_unreachable("predeclared global operator new/delete is missing"); } -static std::pair<bool, bool> -shouldPassSizeAndAlignToUsualDelete(const FunctionProtoType *FPT) { +namespace { +/// The parameters to pass to a usual operator delete. +struct UsualDeleteParams { + bool DestroyingDelete = false; + bool Size = false; + bool Alignment = false; +}; +} + +static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) { + UsualDeleteParams Params; + + const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); auto AI = FPT->param_type_begin(), AE = FPT->param_type_end(); // The first argument is always a void*. ++AI; - // Figure out what other parameters we should be implicitly passing. - bool PassSize = false; - bool PassAlignment = false; + // The next parameter may be a std::destroying_delete_t. + if (FD->isDestroyingOperatorDelete()) { + Params.DestroyingDelete = true; + assert(AI != AE); + ++AI; + } + // Figure out what other parameters we should be implicitly passing. if (AI != AE && (*AI)->isIntegerType()) { - PassSize = true; + Params.Size = true; ++AI; } if (AI != AE && (*AI)->isAlignValT()) { - PassAlignment = true; + Params.Alignment = true; ++AI; } assert(AI == AE && "unexpected usual deallocation function parameter"); - return {PassSize, PassAlignment}; + return Params; } namespace { @@ -1385,25 +1403,27 @@ namespace { OperatorDelete->getType()->getAs<FunctionProtoType>(); CallArgList DeleteArgs; - // The first argument is always a void*. + // The first argument is always a void* (or C* for a destroying operator + // delete for class type C). DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(0)); // Figure out what other parameters we should be implicitly passing. - bool PassSize = false; - bool PassAlignment = false; + UsualDeleteParams Params; if (NumPlacementArgs) { // A placement deallocation function is implicitly passed an alignment // if the placement allocation function was, but is never passed a size. - PassAlignment = PassAlignmentToPlacementDelete; + Params.Alignment = PassAlignmentToPlacementDelete; } else { // For a non-placement new-expression, 'operator delete' can take a // size and/or an alignment if it has the right parameters. - std::tie(PassSize, PassAlignment) = - shouldPassSizeAndAlignToUsualDelete(FPT); + Params = getUsualDeleteParams(OperatorDelete); } + assert(!Params.DestroyingDelete && + "should not call destroying delete in a new-expression"); + // The second argument can be a std::size_t (for non-placement delete). - if (PassSize) + if (Params.Size) DeleteArgs.add(Traits::get(CGF, AllocSize), CGF.getContext().getSizeType()); @@ -1411,7 +1431,7 @@ namespace { // is an enum whose underlying type is std::size_t. // FIXME: Use the right type as the parameter type. Note that in a call // to operator delete(size_t, ...), we may not have it available. - if (PassAlignment) + if (Params.Alignment) DeleteArgs.add(RValue::get(llvm::ConstantInt::get( CGF.SizeTy, AllocAlign.getQuantity())), CGF.getContext().getSizeType()); @@ -1714,9 +1734,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, CallArgList DeleteArgs; - std::pair<bool, bool> PassSizeAndAlign = - shouldPassSizeAndAlignToUsualDelete(DeleteFTy); - + auto Params = getUsualDeleteParams(DeleteFD); auto ParamTypeIt = DeleteFTy->param_type_begin(); // Pass the pointer itself. @@ -1724,8 +1742,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); DeleteArgs.add(RValue::get(DeletePtr), ArgTy); + // Pass the std::destroying_delete tag if present. + if (Params.DestroyingDelete) { + QualType DDTag = *ParamTypeIt++; + // Just pass an 'undef'. We expect the tag type to be an empty struct. + auto *V = llvm::UndefValue::get(getTypes().ConvertType(DDTag)); + DeleteArgs.add(RValue::get(V), DDTag); + } + // Pass the size if the delete function has a size_t parameter. - if (PassSizeAndAlign.first) { + if (Params.Size) { QualType SizeType = *ParamTypeIt++; CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy); llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType), @@ -1744,7 +1770,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, } // Pass the alignment if the delete function has an align_val_t parameter. - if (PassSizeAndAlign.second) { + if (Params.Alignment) { QualType AlignValType = *ParamTypeIt++; CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits( getContext().getTypeAlignIfKnown(DeleteTy)); @@ -1786,6 +1812,21 @@ CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete, OperatorDelete, ElementType); } +/// Emit the code for deleting a single object with a destroying operator +/// delete. If the element type has a non-virtual destructor, Ptr has already +/// been converted to the type of the parameter of 'operator delete'. Otherwise +/// Ptr points to an object of the static type. +static void EmitDestroyingObjectDelete(CodeGenFunction &CGF, + const CXXDeleteExpr *DE, Address Ptr, + QualType ElementType) { + auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor(); + if (Dtor && Dtor->isVirtual()) + CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, + Dtor); + else + CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType); +} + /// Emit the code for deleting a single object. static void EmitObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, @@ -1800,6 +1841,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF, DE->getExprLoc(), Ptr.getPointer(), ElementType); + const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); + assert(!OperatorDelete->isDestroyingOperatorDelete()); + // Find the destructor for the type, if applicable. If the // destructor is virtual, we'll just emit the vcall and return. const CXXDestructorDecl *Dtor = nullptr; @@ -1819,7 +1863,6 @@ static void EmitObjectDelete(CodeGenFunction &CGF, // Make sure that we call delete even if the dtor throws. // This doesn't have to a conditional cleanup because we're going // to pop it off in a second. - const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, Ptr.getPointer(), OperatorDelete, ElementType); @@ -1931,10 +1974,19 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); + QualType DeleteTy = E->getDestroyedType(); + + // A destroying operator delete overrides the entire operation of the + // delete expression. + if (E->getOperatorDelete()->isDestroyingOperatorDelete()) { + EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy); + EmitBlock(DeleteEnd); + return; + } + // We might be deleting a pointer to array. If so, GEP down to the // first non-array element. // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*) - QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType(); if (DeleteTy->isConstantArrayType()) { llvm::Value *Zero = Builder.getInt32(0); SmallVector<llvm::Value*,8> GEP; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp index 980972370dc2b..e860b3045f0e1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp @@ -120,18 +120,22 @@ public: return Visit(E->getSubExpr()); } + ComplexPairTy emitConstant(const CodeGenFunction::ConstantEmission &Constant, + Expr *E) { + assert(Constant && "not a constant"); + if (Constant.isReference()) + return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E), + E->getExprLoc()); + + llvm::Constant *pair = Constant.getValue(); + return ComplexPairTy(pair->getAggregateElement(0U), + pair->getAggregateElement(1U)); + } // l-values. ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) { - if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { - if (result.isReference()) - return EmitLoadOfLValue(result.getReferenceLValue(CGF, E), - E->getExprLoc()); - - llvm::Constant *pair = result.getValue(); - return ComplexPairTy(pair->getAggregateElement(0U), - pair->getAggregateElement(1U)); - } + if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) + return emitConstant(Constant, E); return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { @@ -141,7 +145,14 @@ public: return CGF.EmitObjCMessageExpr(E).getComplexVal(); } ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitMemberExpr(MemberExpr *ME) { + if (CodeGenFunction::ConstantEmission Constant = + CGF.tryEmitAsConstant(ME)) { + CGF.EmitIgnoredExpr(ME->getBase()); + return emitConstant(Constant, ME); + } + return EmitLoadOfLValue(ME); + } ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) { if (E->isGLValue()) return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc()); @@ -764,7 +775,6 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { if (!LHSi) LibCallOp.LHS.second = llvm::Constant::getNullValue(LHSr->getType()); - StringRef LibCallName; switch (LHSr->getType()->getTypeID()) { default: llvm_unreachable("Unsupported floating point type!"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp index 6b72774c10a59..d1b9e13a6f937 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp @@ -16,6 +16,7 @@ #include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" @@ -37,25 +38,26 @@ namespace { class ConstExprEmitter; class ConstStructBuilder { CodeGenModule &CGM; - CodeGenFunction *CGF; + ConstantEmitter &Emitter; bool Packed; CharUnits NextFieldOffsetInChars; CharUnits LLVMStructAlignment; SmallVector<llvm::Constant *, 32> Elements; public: - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CFG, - ConstExprEmitter *Emitter, + static llvm::Constant *BuildStruct(ConstantEmitter &Emitter, + ConstExprEmitter *ExprEmitter, llvm::ConstantStruct *Base, - InitListExpr *Updater); - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, - InitListExpr *ILE); - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *Updater, + QualType ValTy); + static llvm::Constant *BuildStruct(ConstantEmitter &Emitter, + InitListExpr *ILE, QualType StructTy); + static llvm::Constant *BuildStruct(ConstantEmitter &Emitter, const APValue &Value, QualType ValTy); private: - ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) - : CGM(CGM), CGF(CGF), Packed(false), + ConstStructBuilder(ConstantEmitter &emitter) + : CGM(emitter.CGM), Emitter(emitter), Packed(false), NextFieldOffsetInChars(CharUnits::Zero()), LLVMStructAlignment(CharUnits::One()) { } @@ -76,7 +78,7 @@ private: bool Build(InitListExpr *ILE); bool Build(ConstExprEmitter *Emitter, llvm::ConstantStruct *Base, InitListExpr *Updater); - void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase, + bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase, const CXXRecordDecl *VTableClass, CharUnits BaseOffset); llvm::Constant *Finalize(QualType Ty); @@ -391,10 +393,10 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { // we just use explicit null values for them. llvm::Constant *EltInit; if (ElementNo < ILE->getNumInits()) - EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++), - Field->getType(), CGF); + EltInit = Emitter.tryEmitPrivateForMemory(ILE->getInit(ElementNo++), + Field->getType()); else - EltInit = CGM.EmitNullConstant(Field->getType()); + EltInit = Emitter.emitNullForMemory(Field->getType()); if (!EltInit) return false; @@ -431,7 +433,7 @@ struct BaseInfo { }; } -void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, +bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase, const CXXRecordDecl *VTableClass, CharUnits Offset) { @@ -486,8 +488,9 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, const APValue &FieldValue = RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo); llvm::Constant *EltInit = - CGM.EmitConstantValueForMemory(FieldValue, Field->getType(), CGF); - assert(EltInit && "EmitConstantValue can't fail"); + Emitter.tryEmitPrivateForMemory(FieldValue, Field->getType()); + if (!EltInit) + return false; if (!Field->isBitField()) { // Handle non-bitfield members. @@ -498,6 +501,8 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, cast<llvm::ConstantInt>(EltInit)); } } + + return true; } llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) { @@ -559,37 +564,37 @@ llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) { return Result; } -llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, - CodeGenFunction *CGF, - ConstExprEmitter *Emitter, +llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter, + ConstExprEmitter *ExprEmitter, llvm::ConstantStruct *Base, - InitListExpr *Updater) { - ConstStructBuilder Builder(CGM, CGF); - if (!Builder.Build(Emitter, Base, Updater)) + InitListExpr *Updater, + QualType ValTy) { + ConstStructBuilder Builder(Emitter); + if (!Builder.Build(ExprEmitter, Base, Updater)) return nullptr; - return Builder.Finalize(Updater->getType()); + return Builder.Finalize(ValTy); } -llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, - CodeGenFunction *CGF, - InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); +llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter, + InitListExpr *ILE, + QualType ValTy) { + ConstStructBuilder Builder(Emitter); if (!Builder.Build(ILE)) return nullptr; - return Builder.Finalize(ILE->getType()); + return Builder.Finalize(ValTy); } -llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, - CodeGenFunction *CGF, +llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter, const APValue &Val, QualType ValTy) { - ConstStructBuilder Builder(CGM, CGF); + ConstStructBuilder Builder(Emitter); const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl(); const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD); - Builder.Build(Val, RD, false, CD, CharUnits::Zero()); + if (!Builder.Build(Val, RD, false, CD, CharUnits::Zero())) + return nullptr; return Builder.Finalize(ValTy); } @@ -599,57 +604,86 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, // ConstExprEmitter //===----------------------------------------------------------------------===// +static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM, + CodeGenFunction *CGF, + const CompoundLiteralExpr *E) { + CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType()); + if (llvm::GlobalVariable *Addr = + CGM.getAddrOfConstantCompoundLiteralIfEmitted(E)) + return ConstantAddress(Addr, Align); + + LangAS addressSpace = E->getType().getAddressSpace(); + + ConstantEmitter emitter(CGM, CGF); + llvm::Constant *C = emitter.tryEmitForInitializer(E->getInitializer(), + addressSpace, E->getType()); + if (!C) { + assert(!E->isFileScope() && + "file-scope compound literal did not have constant initializer!"); + return ConstantAddress::invalid(); + } + + auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), + CGM.isTypeConstant(E->getType(), true), + llvm::GlobalValue::InternalLinkage, + C, ".compoundliteral", nullptr, + llvm::GlobalVariable::NotThreadLocal, + CGM.getContext().getTargetAddressSpace(addressSpace)); + emitter.finalize(GV); + GV->setAlignment(Align.getQuantity()); + CGM.setAddrOfConstantCompoundLiteral(E, GV); + return ConstantAddress(GV, Align); +} + /// This class only needs to handle two cases: /// 1) Literals (this is used by APValue emission to emit literals). /// 2) Arrays, structs and unions (outside C++11 mode, we don't currently /// constant fold these types). class ConstExprEmitter : - public StmtVisitor<ConstExprEmitter, llvm::Constant*> { + public StmtVisitor<ConstExprEmitter, llvm::Constant*, QualType> { CodeGenModule &CGM; - CodeGenFunction *CGF; + ConstantEmitter &Emitter; llvm::LLVMContext &VMContext; public: - ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf) - : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()) { + ConstExprEmitter(ConstantEmitter &emitter) + : CGM(emitter.CGM), Emitter(emitter), VMContext(CGM.getLLVMContext()) { } //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - llvm::Constant *VisitStmt(Stmt *S) { + llvm::Constant *VisitStmt(Stmt *S, QualType T) { return nullptr; } - llvm::Constant *VisitParenExpr(ParenExpr *PE) { - return Visit(PE->getSubExpr()); + llvm::Constant *VisitParenExpr(ParenExpr *PE, QualType T) { + return Visit(PE->getSubExpr(), T); } llvm::Constant * - VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) { - return Visit(PE->getReplacement()); + VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE, + QualType T) { + return Visit(PE->getReplacement(), T); } - llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) { - return Visit(GE->getResultExpr()); + llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE, + QualType T) { + return Visit(GE->getResultExpr(), T); } - llvm::Constant *VisitChooseExpr(ChooseExpr *CE) { - return Visit(CE->getChosenSubExpr()); + llvm::Constant *VisitChooseExpr(ChooseExpr *CE, QualType T) { + return Visit(CE->getChosenSubExpr(), T); } - llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - return Visit(E->getInitializer()); + llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E, QualType T) { + return Visit(E->getInitializer(), T); } - llvm::Constant *VisitCastExpr(CastExpr* E) { + llvm::Constant *VisitCastExpr(CastExpr *E, QualType destType) { if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E)) - CGM.EmitExplicitCastExprType(ECE, CGF); + CGM.EmitExplicitCastExprType(ECE, Emitter.CGF); Expr *subExpr = E->getSubExpr(); - llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF); - if (!C) return nullptr; - - llvm::Type *destType = ConvertType(E->getType()); switch (E->getCastKind()) { case CK_ToUnion: { @@ -657,14 +691,22 @@ public: assert(E->getType()->isUnionType() && "Destination type is not union type!"); + auto field = E->getTargetUnionField(); + + auto C = Emitter.tryEmitPrivateForMemory(subExpr, field->getType()); + if (!C) return nullptr; + + auto destTy = ConvertType(destType); + if (C->getType() == destTy) return C; + // Build a struct with the union sub-element as the first member, - // and padded to the appropriate size + // and padded to the appropriate size. SmallVector<llvm::Constant*, 2> Elts; SmallVector<llvm::Type*, 2> Types; Elts.push_back(C); Types.push_back(C->getType()); unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType()); - unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destType); + unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destTy); assert(CurSize <= TotalSize && "Union size mismatch!"); if (unsigned NumPadBytes = TotalSize - CurSize) { @@ -676,20 +718,26 @@ public: Types.push_back(Ty); } - llvm::StructType* STy = - llvm::StructType::get(C->getType()->getContext(), Types, false); + llvm::StructType *STy = llvm::StructType::get(VMContext, Types, false); return llvm::ConstantStruct::get(STy, Elts); } - case CK_AddressSpaceConversion: - return llvm::ConstantExpr::getAddrSpaceCast(C, destType); + case CK_AddressSpaceConversion: { + auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType()); + if (!C) return nullptr; + LangAS destAS = E->getType()->getPointeeType().getAddressSpace(); + LangAS srcAS = subExpr->getType()->getPointeeType().getAddressSpace(); + llvm::Type *destTy = ConvertType(E->getType()); + return CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGM, C, srcAS, + destAS, destTy); + } case CK_LValueToRValue: case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_NoOp: case CK_ConstructorConversion: - return C; + return Visit(subExpr, destType); case CK_IntToOCLSampler: llvm_unreachable("global sampler variables are not generated"); @@ -701,8 +749,11 @@ public: case CK_ReinterpretMemberPointer: case CK_DerivedToBaseMemberPointer: - case CK_BaseToDerivedMemberPointer: + case CK_BaseToDerivedMemberPointer: { + auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType()); + if (!C) return nullptr; return CGM.getCXXABI().EmitMemberPointerConversion(E, C); + } // These will never be supported. case CK_ObjCObjectLValueCast: @@ -759,27 +810,28 @@ public: llvm_unreachable("Invalid CastKind"); } - llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { - return Visit(DAE->getExpr()); + llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE, QualType T) { + return Visit(DAE->getExpr(), T); } - llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE, QualType T) { // No need for a DefaultInitExprScope: we don't handle 'this' in a // constant expression. - return Visit(DIE->getExpr()); + return Visit(DIE->getExpr(), T); } - llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E) { + llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E, QualType T) { if (!E->cleanupsHaveSideEffects()) - return Visit(E->getSubExpr()); + return Visit(E->getSubExpr(), T); return nullptr; } - llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { - return Visit(E->GetTemporaryExpr()); + llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E, + QualType T) { + return Visit(E->GetTemporaryExpr(), T); } - llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { + llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) { llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ILE->getType())); llvm::Type *ElemTy = AType->getElementType(); @@ -790,13 +842,14 @@ public: // initialise any elements that have not been initialised explicitly unsigned NumInitableElts = std::min(NumInitElements, NumElements); + QualType EltType = CGM.getContext().getAsArrayType(T)->getElementType(); + // Initialize remaining array elements. - // FIXME: This doesn't handle member pointers correctly! llvm::Constant *fillC; if (Expr *filler = ILE->getArrayFiller()) - fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF); + fillC = Emitter.tryEmitAbstractForMemory(filler, EltType); else - fillC = llvm::Constant::getNullValue(ElemTy); + fillC = Emitter.emitNullForMemory(EltType); if (!fillC) return nullptr; @@ -805,13 +858,13 @@ public: return llvm::ConstantAggregateZero::get(AType); // Copy initializer elements. - std::vector<llvm::Constant*> Elts; + SmallVector<llvm::Constant*, 16> Elts; Elts.reserve(NumInitableElts + NumElements); bool RewriteType = false; for (unsigned i = 0; i < NumInitableElts; ++i) { Expr *Init = ILE->getInit(i); - llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF); + llvm::Constant *C = Emitter.tryEmitPrivateForMemory(Init, EltType); if (!C) return nullptr; RewriteType |= (C->getType() != ElemTy); @@ -835,33 +888,33 @@ public: return llvm::ConstantArray::get(AType, Elts); } - llvm::Constant *EmitRecordInitialization(InitListExpr *ILE) { - return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); + llvm::Constant *EmitRecordInitialization(InitListExpr *ILE, QualType T) { + return ConstStructBuilder::BuildStruct(Emitter, ILE, T); } - llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) { - return CGM.EmitNullConstant(E->getType()); + llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E, + QualType T) { + return CGM.EmitNullConstant(T); } - llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { + llvm::Constant *VisitInitListExpr(InitListExpr *ILE, QualType T) { if (ILE->isTransparent()) - return Visit(ILE->getInit(0)); + return Visit(ILE->getInit(0), T); if (ILE->getType()->isArrayType()) - return EmitArrayInitialization(ILE); + return EmitArrayInitialization(ILE, T); if (ILE->getType()->isRecordType()) - return EmitRecordInitialization(ILE); + return EmitRecordInitialization(ILE, T); return nullptr; } llvm::Constant *EmitDesignatedInitUpdater(llvm::Constant *Base, - InitListExpr *Updater) { - QualType ExprType = Updater->getType(); - - if (ExprType->isArrayType()) { - llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ExprType)); + InitListExpr *Updater, + QualType destType) { + if (auto destAT = CGM.getContext().getAsArrayType(destType)) { + llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(destType)); llvm::Type *ElemType = AType->getElementType(); unsigned NumInitElements = Updater->getNumInits(); @@ -870,12 +923,12 @@ public: std::vector<llvm::Constant *> Elts; Elts.reserve(NumElements); - if (llvm::ConstantDataArray *DataArray = - dyn_cast<llvm::ConstantDataArray>(Base)) + QualType destElemType = destAT->getElementType(); + + if (auto DataArray = dyn_cast<llvm::ConstantDataArray>(Base)) for (unsigned i = 0; i != NumElements; ++i) Elts.push_back(DataArray->getElementAsConstant(i)); - else if (llvm::ConstantArray *Array = - dyn_cast<llvm::ConstantArray>(Base)) + else if (auto Array = dyn_cast<llvm::ConstantArray>(Base)) for (unsigned i = 0; i != NumElements; ++i) Elts.push_back(Array->getOperand(i)); else @@ -884,7 +937,7 @@ public: llvm::Constant *fillC = nullptr; if (Expr *filler = Updater->getArrayFiller()) if (!isa<NoInitExpr>(filler)) - fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF); + fillC = Emitter.tryEmitAbstractForMemory(filler, destElemType); bool RewriteType = (fillC && fillC->getType() != ElemType); for (unsigned i = 0; i != NumElements; ++i) { @@ -897,9 +950,9 @@ public: else if (!Init || isa<NoInitExpr>(Init)) ; // Do nothing. else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init)) - Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE); + Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE, destElemType); else - Elts[i] = CGM.EmitConstantExpr(Init, Init->getType(), CGF); + Elts[i] = Emitter.tryEmitPrivateForMemory(Init, destElemType); if (!Elts[i]) return nullptr; @@ -919,25 +972,24 @@ public: return llvm::ConstantArray::get(AType, Elts); } - if (ExprType->isRecordType()) - return ConstStructBuilder::BuildStruct(CGM, CGF, this, - dyn_cast<llvm::ConstantStruct>(Base), Updater); + if (destType->isRecordType()) + return ConstStructBuilder::BuildStruct(Emitter, this, + dyn_cast<llvm::ConstantStruct>(Base), Updater, destType); return nullptr; } - llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) { - return EmitDesignatedInitUpdater( - CGM.EmitConstantExpr(E->getBase(), E->getType(), CGF), - E->getUpdater()); + llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E, + QualType destType) { + auto C = Visit(E->getBase(), destType); + if (!C) return nullptr; + return EmitDesignatedInitUpdater(C, E->getUpdater(), destType); } - llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) { + llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E, QualType Ty) { if (!E->getConstructor()->isTrivial()) return nullptr; - QualType Ty = E->getType(); - // FIXME: We should not have to call getBaseElementType here. const RecordType *RT = CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>(); @@ -960,26 +1012,23 @@ public: assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) && "argument to copy ctor is of wrong type"); - return Visit(Arg); + return Visit(Arg, Ty); } return CGM.EmitNullConstant(Ty); } - llvm::Constant *VisitStringLiteral(StringLiteral *E) { + llvm::Constant *VisitStringLiteral(StringLiteral *E, QualType T) { return CGM.GetConstantArrayFromStringLiteral(E); } - llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E, QualType T) { // This must be an @encode initializing an array in a static initializer. // Don't emit it as the address of the string, emit the string data itself // as an inline array. std::string Str; CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str); - QualType T = E->getType(); - if (T->getTypeClass() == Type::TypeOfExpr) - T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType(); - const ConstantArrayType *CAT = cast<ConstantArrayType>(T); + const ConstantArrayType *CAT = CGM.getContext().getAsConstantArrayType(T); // Resize the string to the right size, adding zeros at the end, or // truncating as needed. @@ -987,151 +1036,19 @@ public: return llvm::ConstantDataArray::getString(VMContext, Str, false); } - llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) { - return Visit(E->getSubExpr()); + llvm::Constant *VisitUnaryExtension(const UnaryOperator *E, QualType T) { + return Visit(E->getSubExpr(), T); } // Utility methods llvm::Type *ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); } - -public: - ConstantAddress EmitLValue(APValue::LValueBase LVBase) { - if (const ValueDecl *Decl = LVBase.dyn_cast<const ValueDecl*>()) { - if (Decl->hasAttr<WeakRefAttr>()) - return CGM.GetWeakRefReference(Decl); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl)) - return ConstantAddress(CGM.GetAddrOfFunction(FD), CharUnits::One()); - if (const VarDecl* VD = dyn_cast<VarDecl>(Decl)) { - // We can never refer to a variable with local storage. - if (!VD->hasLocalStorage()) { - CharUnits Align = CGM.getContext().getDeclAlign(VD); - if (VD->isFileVarDecl() || VD->hasExternalStorage()) - return ConstantAddress(CGM.GetAddrOfGlobalVar(VD), Align); - else if (VD->isLocalVarDecl()) { - auto Ptr = CGM.getOrCreateStaticVarDecl( - *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false)); - return ConstantAddress(Ptr, Align); - } - } - } - return ConstantAddress::invalid(); - } - - Expr *E = const_cast<Expr*>(LVBase.get<const Expr*>()); - switch (E->getStmtClass()) { - default: break; - case Expr::CompoundLiteralExprClass: { - CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E); - CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType()); - if (llvm::GlobalVariable *Addr = - CGM.getAddrOfConstantCompoundLiteralIfEmitted(CLE)) - return ConstantAddress(Addr, Align); - - llvm::Constant* C = CGM.EmitConstantExpr(CLE->getInitializer(), - CLE->getType(), CGF); - // FIXME: "Leaked" on failure. - if (!C) return ConstantAddress::invalid(); - - auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), - E->getType().isConstant(CGM.getContext()), - llvm::GlobalValue::InternalLinkage, - C, ".compoundliteral", nullptr, - llvm::GlobalVariable::NotThreadLocal, - CGM.getContext().getTargetAddressSpace(E->getType())); - GV->setAlignment(Align.getQuantity()); - CGM.setAddrOfConstantCompoundLiteral(CLE, GV); - return ConstantAddress(GV, Align); - } - case Expr::StringLiteralClass: - return CGM.GetAddrOfConstantStringFromLiteral(cast<StringLiteral>(E)); - case Expr::ObjCEncodeExprClass: - return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E)); - case Expr::ObjCStringLiteralClass: { - ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E); - ConstantAddress C = - CGM.getObjCRuntime().GenerateConstantString(SL->getString()); - return C.getElementBitCast(ConvertType(E->getType())); - } - case Expr::PredefinedExprClass: { - unsigned Type = cast<PredefinedExpr>(E)->getIdentType(); - if (CGF) { - LValue Res = CGF->EmitPredefinedLValue(cast<PredefinedExpr>(E)); - return cast<ConstantAddress>(Res.getAddress()); - } else if (Type == PredefinedExpr::PrettyFunction) { - return CGM.GetAddrOfConstantCString("top level", ".tmp"); - } - - return CGM.GetAddrOfConstantCString("", ".tmp"); - } - case Expr::AddrLabelExprClass: { - assert(CGF && "Invalid address of label expression outside function."); - llvm::Constant *Ptr = - CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); - Ptr = llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType())); - return ConstantAddress(Ptr, CharUnits::One()); - } - case Expr::CallExprClass: { - CallExpr* CE = cast<CallExpr>(E); - unsigned builtin = CE->getBuiltinCallee(); - if (builtin != - Builtin::BI__builtin___CFStringMakeConstantString && - builtin != - Builtin::BI__builtin___NSStringMakeConstantString) - break; - const Expr *Arg = CE->getArg(0)->IgnoreParenCasts(); - const StringLiteral *Literal = cast<StringLiteral>(Arg); - if (builtin == - Builtin::BI__builtin___NSStringMakeConstantString) { - return CGM.getObjCRuntime().GenerateConstantString(Literal); - } - // FIXME: need to deal with UCN conversion issues. - return CGM.GetAddrOfConstantCFString(Literal); - } - case Expr::BlockExprClass: { - StringRef FunctionName; - if (CGF) - FunctionName = CGF->CurFn->getName(); - else - FunctionName = "global"; - - // This is not really an l-value. - llvm::Constant *Ptr = - CGM.GetAddrOfGlobalBlock(cast<BlockExpr>(E), FunctionName); - return ConstantAddress(Ptr, CGM.getPointerAlign()); - } - case Expr::CXXTypeidExprClass: { - CXXTypeidExpr *Typeid = cast<CXXTypeidExpr>(E); - QualType T; - if (Typeid->isTypeOperand()) - T = Typeid->getTypeOperand(CGM.getContext()); - else - T = Typeid->getExprOperand()->getType(); - return ConstantAddress(CGM.GetAddrOfRTTIDescriptor(T), - CGM.getPointerAlign()); - } - case Expr::CXXUuidofExprClass: { - return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E)); - } - case Expr::MaterializeTemporaryExprClass: { - MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E); - assert(MTE->getStorageDuration() == SD_Static); - SmallVector<const Expr *, 2> CommaLHSs; - SmallVector<SubobjectAdjustment, 2> Adjustments; - const Expr *Inner = MTE->GetTemporaryExpr() - ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); - return CGM.GetAddrOfGlobalTemporary(MTE, Inner); - } - } - - return ConstantAddress::invalid(); - } }; } // end anonymous namespace. -bool ConstStructBuilder::Build(ConstExprEmitter *Emitter, +bool ConstStructBuilder::Build(ConstExprEmitter *ExprEmitter, llvm::ConstantStruct *Base, InitListExpr *Updater) { assert(Base && "base expression should not be empty"); @@ -1179,9 +1096,10 @@ bool ConstStructBuilder::Build(ConstExprEmitter *Emitter, if (!Init || isa<NoInitExpr>(Init)) ; // Do nothing. else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init)) - EltInit = Emitter->EmitDesignatedInitUpdater(EltInit, ChildILE); + EltInit = ExprEmitter->EmitDesignatedInitUpdater(EltInit, ChildILE, + Field->getType()); else - EltInit = CGM.EmitConstantExpr(Init, Field->getType(), CGF); + EltInit = Emitter.tryEmitPrivateForMemory(Init, Field->getType()); ++ElementNo; @@ -1200,26 +1118,294 @@ bool ConstStructBuilder::Build(ConstExprEmitter *Emitter, return true; } -llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, - CodeGenFunction *CGF) { +llvm::Constant *ConstantEmitter::validateAndPopAbstract(llvm::Constant *C, + AbstractState saved) { + Abstract = saved.OldValue; + + assert(saved.OldPlaceholdersSize == PlaceholderAddresses.size() && + "created a placeholder while doing an abstract emission?"); + + // No validation necessary for now. + // No cleanup to do for now. + return C; +} + +llvm::Constant * +ConstantEmitter::tryEmitAbstractForInitializer(const VarDecl &D) { + auto state = pushAbstract(); + auto C = tryEmitPrivateForVarInit(D); + return validateAndPopAbstract(C, state); +} + +llvm::Constant * +ConstantEmitter::tryEmitAbstract(const Expr *E, QualType destType) { + auto state = pushAbstract(); + auto C = tryEmitPrivate(E, destType); + return validateAndPopAbstract(C, state); +} + +llvm::Constant * +ConstantEmitter::tryEmitAbstract(const APValue &value, QualType destType) { + auto state = pushAbstract(); + auto C = tryEmitPrivate(value, destType); + return validateAndPopAbstract(C, state); +} + +llvm::Constant * +ConstantEmitter::emitAbstract(const Expr *E, QualType destType) { + auto state = pushAbstract(); + auto C = tryEmitPrivate(E, destType); + C = validateAndPopAbstract(C, state); + if (!C) { + CGM.Error(E->getExprLoc(), + "internal error: could not emit constant value \"abstractly\""); + C = CGM.EmitNullConstant(destType); + } + return C; +} + +llvm::Constant * +ConstantEmitter::emitAbstract(SourceLocation loc, const APValue &value, + QualType destType) { + auto state = pushAbstract(); + auto C = tryEmitPrivate(value, destType); + C = validateAndPopAbstract(C, state); + if (!C) { + CGM.Error(loc, + "internal error: could not emit constant value \"abstractly\""); + C = CGM.EmitNullConstant(destType); + } + return C; +} + +llvm::Constant *ConstantEmitter::tryEmitForInitializer(const VarDecl &D) { + initializeNonAbstract(D.getType().getAddressSpace()); + return markIfFailed(tryEmitPrivateForVarInit(D)); +} + +llvm::Constant *ConstantEmitter::tryEmitForInitializer(const Expr *E, + LangAS destAddrSpace, + QualType destType) { + initializeNonAbstract(destAddrSpace); + return markIfFailed(tryEmitPrivateForMemory(E, destType)); +} + +llvm::Constant *ConstantEmitter::emitForInitializer(const APValue &value, + LangAS destAddrSpace, + QualType destType) { + initializeNonAbstract(destAddrSpace); + auto C = tryEmitPrivateForMemory(value, destType); + assert(C && "couldn't emit constant value non-abstractly?"); + return C; +} + +llvm::GlobalValue *ConstantEmitter::getCurrentAddrPrivate() { + assert(!Abstract && "cannot get current address for abstract constant"); + + + + // Make an obviously ill-formed global that should blow up compilation + // if it survives. + auto global = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty, true, + llvm::GlobalValue::PrivateLinkage, + /*init*/ nullptr, + /*name*/ "", + /*before*/ nullptr, + llvm::GlobalVariable::NotThreadLocal, + CGM.getContext().getTargetAddressSpace(DestAddressSpace)); + + PlaceholderAddresses.push_back(std::make_pair(nullptr, global)); + + return global; +} + +void ConstantEmitter::registerCurrentAddrPrivate(llvm::Constant *signal, + llvm::GlobalValue *placeholder) { + assert(!PlaceholderAddresses.empty()); + assert(PlaceholderAddresses.back().first == nullptr); + assert(PlaceholderAddresses.back().second == placeholder); + PlaceholderAddresses.back().first = signal; +} + +namespace { + struct ReplacePlaceholders { + CodeGenModule &CGM; + + /// The base address of the global. + llvm::Constant *Base; + llvm::Type *BaseValueTy = nullptr; + + /// The placeholder addresses that were registered during emission. + llvm::DenseMap<llvm::Constant*, llvm::GlobalVariable*> PlaceholderAddresses; + + /// The locations of the placeholder signals. + llvm::DenseMap<llvm::GlobalVariable*, llvm::Constant*> Locations; + + /// The current index stack. We use a simple unsigned stack because + /// we assume that placeholders will be relatively sparse in the + /// initializer, but we cache the index values we find just in case. + llvm::SmallVector<unsigned, 8> Indices; + llvm::SmallVector<llvm::Constant*, 8> IndexValues; + + ReplacePlaceholders(CodeGenModule &CGM, llvm::Constant *base, + ArrayRef<std::pair<llvm::Constant*, + llvm::GlobalVariable*>> addresses) + : CGM(CGM), Base(base), + PlaceholderAddresses(addresses.begin(), addresses.end()) { + } + + void replaceInInitializer(llvm::Constant *init) { + // Remember the type of the top-most initializer. + BaseValueTy = init->getType(); + + // Initialize the stack. + Indices.push_back(0); + IndexValues.push_back(nullptr); + + // Recurse into the initializer. + findLocations(init); + + // Check invariants. + assert(IndexValues.size() == Indices.size() && "mismatch"); + assert(Indices.size() == 1 && "didn't pop all indices"); + + // Do the replacement; this basically invalidates 'init'. + assert(Locations.size() == PlaceholderAddresses.size() && + "missed a placeholder?"); + + // We're iterating over a hashtable, so this would be a source of + // non-determinism in compiler output *except* that we're just + // messing around with llvm::Constant structures, which never itself + // does anything that should be visible in compiler output. + for (auto &entry : Locations) { + assert(entry.first->getParent() == nullptr && "not a placeholder!"); + entry.first->replaceAllUsesWith(entry.second); + entry.first->eraseFromParent(); + } + } + + private: + void findLocations(llvm::Constant *init) { + // Recurse into aggregates. + if (auto agg = dyn_cast<llvm::ConstantAggregate>(init)) { + for (unsigned i = 0, e = agg->getNumOperands(); i != e; ++i) { + Indices.push_back(i); + IndexValues.push_back(nullptr); + + findLocations(agg->getOperand(i)); + + IndexValues.pop_back(); + Indices.pop_back(); + } + return; + } + + // Otherwise, check for registered constants. + while (true) { + auto it = PlaceholderAddresses.find(init); + if (it != PlaceholderAddresses.end()) { + setLocation(it->second); + break; + } + + // Look through bitcasts or other expressions. + if (auto expr = dyn_cast<llvm::ConstantExpr>(init)) { + init = expr->getOperand(0); + } else { + break; + } + } + } + + void setLocation(llvm::GlobalVariable *placeholder) { + assert(Locations.find(placeholder) == Locations.end() && + "already found location for placeholder!"); + + // Lazily fill in IndexValues with the values from Indices. + // We do this in reverse because we should always have a strict + // prefix of indices from the start. + assert(Indices.size() == IndexValues.size()); + for (size_t i = Indices.size() - 1; i != size_t(-1); --i) { + if (IndexValues[i]) { +#ifndef NDEBUG + for (size_t j = 0; j != i + 1; ++j) { + assert(IndexValues[j] && + isa<llvm::ConstantInt>(IndexValues[j]) && + cast<llvm::ConstantInt>(IndexValues[j])->getZExtValue() + == Indices[j]); + } +#endif + break; + } + + IndexValues[i] = llvm::ConstantInt::get(CGM.Int32Ty, Indices[i]); + } + + // Form a GEP and then bitcast to the placeholder type so that the + // replacement will succeed. + llvm::Constant *location = + llvm::ConstantExpr::getInBoundsGetElementPtr(BaseValueTy, + Base, IndexValues); + location = llvm::ConstantExpr::getBitCast(location, + placeholder->getType()); + + Locations.insert({placeholder, location}); + } + }; +} + +void ConstantEmitter::finalize(llvm::GlobalVariable *global) { + assert(InitializedNonAbstract && + "finalizing emitter that was used for abstract emission?"); + assert(!Finalized && "finalizing emitter multiple times"); + assert(global->getInitializer()); + + // Note that we might also be Failed. + Finalized = true; + + if (!PlaceholderAddresses.empty()) { + ReplacePlaceholders(CGM, global, PlaceholderAddresses) + .replaceInInitializer(global->getInitializer()); + PlaceholderAddresses.clear(); // satisfy + } +} + +ConstantEmitter::~ConstantEmitter() { + assert((!InitializedNonAbstract || Finalized || Failed) && + "not finalized after being initialized for non-abstract emission"); + assert(PlaceholderAddresses.empty() && "unhandled placeholders"); +} + +static QualType getNonMemoryType(CodeGenModule &CGM, QualType type) { + if (auto AT = type->getAs<AtomicType>()) { + return CGM.getContext().getQualifiedType(AT->getValueType(), + type.getQualifiers()); + } + return type; +} + +llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) { // Make a quick check if variable can be default NULL initialized // and avoid going through rest of code which may do, for c++11, // initialization of memory to all NULLs. if (!D.hasLocalStorage()) { - QualType Ty = D.getType(); - if (Ty->isArrayType()) - Ty = Context.getBaseElementType(Ty); + QualType Ty = CGM.getContext().getBaseElementType(D.getType()); if (Ty->isRecordType()) if (const CXXConstructExpr *E = dyn_cast_or_null<CXXConstructExpr>(D.getInit())) { const CXXConstructorDecl *CD = E->getConstructor(); if (CD->isTrivial() && CD->isDefaultConstructor()) - return EmitNullConstant(D.getType()); + return CGM.EmitNullConstant(D.getType()); } } - - if (const APValue *Value = D.evaluateValue()) - return EmitConstantValueForMemory(*Value, D.getType(), CGF); + + QualType destType = D.getType(); + + // Try to emit the initializer. Note that this can allow some things that + // are not allowed by tryEmitPrivateForMemory alone. + if (auto value = D.evaluateValue()) { + return tryEmitPrivateForMemory(*value, destType); + } // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a // reference is a constant expression, and the reference binds to a temporary, @@ -1227,42 +1413,95 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, // incorrectly emit a prvalue constant in this case, and the calling code // interprets that as the (pointer) value of the reference, rather than the // desired value of the referee. - if (D.getType()->isReferenceType()) + if (destType->isReferenceType()) return nullptr; const Expr *E = D.getInit(); assert(E && "No initializer to emit"); - llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E)); - if (C && C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); - C = llvm::ConstantExpr::getZExt(C, BoolTy); + auto nonMemoryDestType = getNonMemoryType(CGM, destType); + auto C = + ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), nonMemoryDestType); + return (C ? emitForMemory(C, destType) : nullptr); +} + +llvm::Constant * +ConstantEmitter::tryEmitAbstractForMemory(const Expr *E, QualType destType) { + auto nonMemoryDestType = getNonMemoryType(CGM, destType); + auto C = tryEmitAbstract(E, nonMemoryDestType); + return (C ? emitForMemory(C, destType) : nullptr); +} + +llvm::Constant * +ConstantEmitter::tryEmitAbstractForMemory(const APValue &value, + QualType destType) { + auto nonMemoryDestType = getNonMemoryType(CGM, destType); + auto C = tryEmitAbstract(value, nonMemoryDestType); + return (C ? emitForMemory(C, destType) : nullptr); +} + +llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const Expr *E, + QualType destType) { + auto nonMemoryDestType = getNonMemoryType(CGM, destType); + llvm::Constant *C = tryEmitPrivate(E, nonMemoryDestType); + return (C ? emitForMemory(C, destType) : nullptr); +} + +llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const APValue &value, + QualType destType) { + auto nonMemoryDestType = getNonMemoryType(CGM, destType); + auto C = tryEmitPrivate(value, nonMemoryDestType); + return (C ? emitForMemory(C, destType) : nullptr); +} + +llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, + llvm::Constant *C, + QualType destType) { + // For an _Atomic-qualified constant, we may need to add tail padding. + if (auto AT = destType->getAs<AtomicType>()) { + QualType destValueType = AT->getValueType(); + C = emitForMemory(CGM, C, destValueType); + + uint64_t innerSize = CGM.getContext().getTypeSize(destValueType); + uint64_t outerSize = CGM.getContext().getTypeSize(destType); + if (innerSize == outerSize) + return C; + + assert(innerSize < outerSize && "emitted over-large constant for atomic"); + llvm::Constant *elts[] = { + C, + llvm::ConstantAggregateZero::get( + llvm::ArrayType::get(CGM.Int8Ty, (outerSize - innerSize) / 8)) + }; + return llvm::ConstantStruct::getAnon(elts); + } + + // Zero-extend bool. + if (C->getType()->isIntegerTy(1)) { + llvm::Type *boolTy = CGM.getTypes().ConvertTypeForMem(destType); + return llvm::ConstantExpr::getZExt(C, boolTy); } + return C; } -llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, - QualType DestType, - CodeGenFunction *CGF) { +llvm::Constant *ConstantEmitter::tryEmitPrivate(const Expr *E, + QualType destType) { Expr::EvalResult Result; bool Success = false; - if (DestType->isReferenceType()) - Success = E->EvaluateAsLValue(Result, Context); + if (destType->isReferenceType()) + Success = E->EvaluateAsLValue(Result, CGM.getContext()); else - Success = E->EvaluateAsRValue(Result, Context); + Success = E->EvaluateAsRValue(Result, CGM.getContext()); - llvm::Constant *C = nullptr; + llvm::Constant *C; if (Success && !Result.HasSideEffects) - C = EmitConstantValue(Result.Val, DestType, CGF); + C = tryEmitPrivate(Result.Val, destType); else - C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E)); + C = ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), destType); - if (C && C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); - C = llvm::ConstantExpr::getZExt(C, BoolTy); - } return C; } @@ -1270,94 +1509,311 @@ llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T, QualType QT) return getTargetCodeGenInfo().getNullPointer(*this, T, QT); } -llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, - QualType DestType, - CodeGenFunction *CGF) { - // For an _Atomic-qualified constant, we may need to add tail padding. - if (auto *AT = DestType->getAs<AtomicType>()) { - QualType InnerType = AT->getValueType(); - auto *Inner = EmitConstantValue(Value, InnerType, CGF); +namespace { +/// A struct which can be used to peephole certain kinds of finalization +/// that normally happen during l-value emission. +struct ConstantLValue { + llvm::Constant *Value; + bool HasOffsetApplied; - uint64_t InnerSize = Context.getTypeSize(InnerType); - uint64_t OuterSize = Context.getTypeSize(DestType); - if (InnerSize == OuterSize) - return Inner; + /*implicit*/ ConstantLValue(llvm::Constant *value, + bool hasOffsetApplied = false) + : Value(value), HasOffsetApplied(false) {} - assert(InnerSize < OuterSize && "emitted over-large constant for atomic"); - llvm::Constant *Elts[] = { - Inner, - llvm::ConstantAggregateZero::get( - llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8)) - }; - return llvm::ConstantStruct::getAnon(Elts); + /*implicit*/ ConstantLValue(ConstantAddress address) + : ConstantLValue(address.getPointer()) {} +}; + +/// A helper class for emitting constant l-values. +class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter, + ConstantLValue> { + CodeGenModule &CGM; + ConstantEmitter &Emitter; + const APValue &Value; + QualType DestType; + + // Befriend StmtVisitorBase so that we don't have to expose Visit*. + friend StmtVisitorBase; + +public: + ConstantLValueEmitter(ConstantEmitter &emitter, const APValue &value, + QualType destType) + : CGM(emitter.CGM), Emitter(emitter), Value(value), DestType(destType) {} + + llvm::Constant *tryEmit(); + +private: + llvm::Constant *tryEmitAbsolute(llvm::Type *destTy); + ConstantLValue tryEmitBase(const APValue::LValueBase &base); + + ConstantLValue VisitStmt(const Stmt *S) { return nullptr; } + ConstantLValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); + ConstantLValue VisitStringLiteral(const StringLiteral *E); + ConstantLValue VisitObjCEncodeExpr(const ObjCEncodeExpr *E); + ConstantLValue VisitObjCStringLiteral(const ObjCStringLiteral *E); + ConstantLValue VisitPredefinedExpr(const PredefinedExpr *E); + ConstantLValue VisitAddrLabelExpr(const AddrLabelExpr *E); + ConstantLValue VisitCallExpr(const CallExpr *E); + ConstantLValue VisitBlockExpr(const BlockExpr *E); + ConstantLValue VisitCXXTypeidExpr(const CXXTypeidExpr *E); + ConstantLValue VisitCXXUuidofExpr(const CXXUuidofExpr *E); + ConstantLValue VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *E); + + bool hasNonZeroOffset() const { + return !Value.getLValueOffset().isZero(); } - switch (Value.getKind()) { - case APValue::Uninitialized: - llvm_unreachable("Constant expressions should be initialized."); - case APValue::LValue: { - llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); - llvm::Constant *Offset = - llvm::ConstantInt::get(Int64Ty, Value.getLValueOffset().getQuantity()); + /// Return the value offset. + llvm::Constant *getOffset() { + return llvm::ConstantInt::get(CGM.Int64Ty, + Value.getLValueOffset().getQuantity()); + } - llvm::Constant *C = nullptr; + /// Apply the value offset to the given constant. + llvm::Constant *applyOffset(llvm::Constant *C) { + if (!hasNonZeroOffset()) + return C; - if (APValue::LValueBase LVBase = Value.getLValueBase()) { - // An array can be represented as an lvalue referring to the base. - if (isa<llvm::ArrayType>(DestTy)) { - assert(Offset->isNullValue() && "offset on array initializer"); - return ConstExprEmitter(*this, CGF).Visit( - const_cast<Expr*>(LVBase.get<const Expr*>())); - } + llvm::Type *origPtrTy = C->getType(); + unsigned AS = origPtrTy->getPointerAddressSpace(); + llvm::Type *charPtrTy = CGM.Int8Ty->getPointerTo(AS); + C = llvm::ConstantExpr::getBitCast(C, charPtrTy); + C = llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, C, getOffset()); + C = llvm::ConstantExpr::getPointerCast(C, origPtrTy); + return C; + } +}; - C = ConstExprEmitter(*this, CGF).EmitLValue(LVBase).getPointer(); +} - // Apply offset if necessary. - if (!Offset->isNullValue()) { - unsigned AS = C->getType()->getPointerAddressSpace(); - llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS); - llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy); - Casted = llvm::ConstantExpr::getGetElementPtr(Int8Ty, Casted, Offset); - C = llvm::ConstantExpr::getPointerCast(Casted, C->getType()); - } +llvm::Constant *ConstantLValueEmitter::tryEmit() { + const APValue::LValueBase &base = Value.getLValueBase(); - // Convert to the appropriate type; this could be an lvalue for - // an integer. - if (isa<llvm::PointerType>(DestTy)) - return llvm::ConstantExpr::getPointerCast(C, DestTy); + // Certain special array initializers are represented in APValue + // as l-values referring to the base expression which generates the + // array. This happens with e.g. string literals. These should + // probably just get their own representation kind in APValue. + if (DestType->isArrayType()) { + assert(!hasNonZeroOffset() && "offset on array initializer"); + auto expr = const_cast<Expr*>(base.get<const Expr*>()); + return ConstExprEmitter(Emitter).Visit(expr, DestType); + } - return llvm::ConstantExpr::getPtrToInt(C, DestTy); - } else { - C = Offset; + // Otherwise, the destination type should be a pointer or reference + // type, but it might also be a cast thereof. + // + // FIXME: the chain of casts required should be reflected in the APValue. + // We need this in order to correctly handle things like a ptrtoint of a + // non-zero null pointer and addrspace casts that aren't trivially + // represented in LLVM IR. + auto destTy = CGM.getTypes().ConvertTypeForMem(DestType); + assert(isa<llvm::IntegerType>(destTy) || isa<llvm::PointerType>(destTy)); - // Convert to the appropriate type; this could be an lvalue for - // an integer. - if (auto PT = dyn_cast<llvm::PointerType>(DestTy)) { - if (Value.isNullPointer()) - return getNullPointer(PT, DestType); - // Convert the integer to a pointer-sized integer before converting it - // to a pointer. - C = llvm::ConstantExpr::getIntegerCast( - C, getDataLayout().getIntPtrType(DestTy), - /*isSigned=*/false); - return llvm::ConstantExpr::getIntToPtr(C, DestTy); - } + // If there's no base at all, this is a null or absolute pointer, + // possibly cast back to an integer type. + if (!base) { + return tryEmitAbsolute(destTy); + } - // If the types don't match this should only be a truncate. - if (C->getType() != DestTy) - return llvm::ConstantExpr::getTrunc(C, DestTy); + // Otherwise, try to emit the base. + ConstantLValue result = tryEmitBase(base); - return C; + // If that failed, we're done. + llvm::Constant *value = result.Value; + if (!value) return nullptr; + + // Apply the offset if necessary and not already done. + if (!result.HasOffsetApplied) { + value = applyOffset(value); + } + + // Convert to the appropriate type; this could be an lvalue for + // an integer. FIXME: performAddrSpaceCast + if (isa<llvm::PointerType>(destTy)) + return llvm::ConstantExpr::getPointerCast(value, destTy); + + return llvm::ConstantExpr::getPtrToInt(value, destTy); +} + +/// Try to emit an absolute l-value, such as a null pointer or an integer +/// bitcast to pointer type. +llvm::Constant * +ConstantLValueEmitter::tryEmitAbsolute(llvm::Type *destTy) { + auto offset = getOffset(); + + // If we're producing a pointer, this is easy. + if (auto destPtrTy = cast<llvm::PointerType>(destTy)) { + if (Value.isNullPointer()) { + // FIXME: integer offsets from non-zero null pointers. + return CGM.getNullPointer(destPtrTy, DestType); + } + + // Convert the integer to a pointer-sized integer before converting it + // to a pointer. + // FIXME: signedness depends on the original integer type. + auto intptrTy = CGM.getDataLayout().getIntPtrType(destPtrTy); + llvm::Constant *C = offset; + C = llvm::ConstantExpr::getIntegerCast(getOffset(), intptrTy, + /*isSigned*/ false); + C = llvm::ConstantExpr::getIntToPtr(C, destPtrTy); + return C; + } + + // Otherwise, we're basically returning an integer constant. + + // FIXME: this does the wrong thing with ptrtoint of a null pointer, + // but since we don't know the original pointer type, there's not much + // we can do about it. + + auto C = getOffset(); + C = llvm::ConstantExpr::getIntegerCast(C, destTy, /*isSigned*/ false); + return C; +} + +ConstantLValue +ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { + // Handle values. + if (const ValueDecl *D = base.dyn_cast<const ValueDecl*>()) { + if (D->hasAttr<WeakRefAttr>()) + return CGM.GetWeakRefReference(D).getPointer(); + + if (auto FD = dyn_cast<FunctionDecl>(D)) + return CGM.GetAddrOfFunction(FD); + + if (auto VD = dyn_cast<VarDecl>(D)) { + // We can never refer to a variable with local storage. + if (!VD->hasLocalStorage()) { + if (VD->isFileVarDecl() || VD->hasExternalStorage()) + return CGM.GetAddrOfGlobalVar(VD); + + if (VD->isLocalVarDecl()) { + return CGM.getOrCreateStaticVarDecl( + *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false)); + } + } } + + return nullptr; + } + + // Otherwise, it must be an expression. + return Visit(base.get<const Expr*>()); +} + +ConstantLValue +ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return tryEmitGlobalCompoundLiteral(CGM, Emitter.CGF, E); +} + +ConstantLValue +ConstantLValueEmitter::VisitStringLiteral(const StringLiteral *E) { + return CGM.GetAddrOfConstantStringFromLiteral(E); +} + +ConstantLValue +ConstantLValueEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { + return CGM.GetAddrOfConstantStringFromObjCEncode(E); +} + +ConstantLValue +ConstantLValueEmitter::VisitObjCStringLiteral(const ObjCStringLiteral *E) { + auto C = CGM.getObjCRuntime().GenerateConstantString(E->getString()); + return C.getElementBitCast(CGM.getTypes().ConvertTypeForMem(E->getType())); +} + +ConstantLValue +ConstantLValueEmitter::VisitPredefinedExpr(const PredefinedExpr *E) { + if (auto CGF = Emitter.CGF) { + LValue Res = CGF->EmitPredefinedLValue(E); + return cast<ConstantAddress>(Res.getAddress()); + } + + auto kind = E->getIdentType(); + if (kind == PredefinedExpr::PrettyFunction) { + return CGM.GetAddrOfConstantCString("top level", ".tmp"); } + + return CGM.GetAddrOfConstantCString("", ".tmp"); +} + +ConstantLValue +ConstantLValueEmitter::VisitAddrLabelExpr(const AddrLabelExpr *E) { + assert(Emitter.CGF && "Invalid address of label expression outside function"); + llvm::Constant *Ptr = Emitter.CGF->GetAddrOfLabel(E->getLabel()); + Ptr = llvm::ConstantExpr::getBitCast(Ptr, + CGM.getTypes().ConvertType(E->getType())); + return Ptr; +} + +ConstantLValue +ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) { + unsigned builtin = E->getBuiltinCallee(); + if (builtin != Builtin::BI__builtin___CFStringMakeConstantString && + builtin != Builtin::BI__builtin___NSStringMakeConstantString) + return nullptr; + + auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts()); + if (builtin == Builtin::BI__builtin___NSStringMakeConstantString) { + return CGM.getObjCRuntime().GenerateConstantString(literal); + } else { + // FIXME: need to deal with UCN conversion issues. + return CGM.GetAddrOfConstantCFString(literal); + } +} + +ConstantLValue +ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) { + StringRef functionName; + if (auto CGF = Emitter.CGF) + functionName = CGF->CurFn->getName(); + else + functionName = "global"; + + return CGM.GetAddrOfGlobalBlock(E, functionName); +} + +ConstantLValue +ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { + QualType T; + if (E->isTypeOperand()) + T = E->getTypeOperand(CGM.getContext()); + else + T = E->getExprOperand()->getType(); + return CGM.GetAddrOfRTTIDescriptor(T); +} + +ConstantLValue +ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { + return CGM.GetAddrOfUuidDescriptor(E); +} + +ConstantLValue +ConstantLValueEmitter::VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *E) { + assert(E->getStorageDuration() == SD_Static); + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Inner = E->GetTemporaryExpr() + ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + return CGM.GetAddrOfGlobalTemporary(E, Inner); +} + +llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value, + QualType DestType) { + switch (Value.getKind()) { + case APValue::Uninitialized: + llvm_unreachable("Constant expressions should be initialized."); + case APValue::LValue: + return ConstantLValueEmitter(*this, Value, DestType).tryEmit(); case APValue::Int: - return llvm::ConstantInt::get(VMContext, Value.getInt()); + return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt()); case APValue::ComplexInt: { llvm::Constant *Complex[2]; - Complex[0] = llvm::ConstantInt::get(VMContext, + Complex[0] = llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getComplexIntReal()); - Complex[1] = llvm::ConstantInt::get(VMContext, + Complex[1] = llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getComplexIntImag()); // FIXME: the target may want to specify that this is packed. @@ -1368,18 +1824,19 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, case APValue::Float: { const llvm::APFloat &Init = Value.getFloat(); if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf() && - !Context.getLangOpts().NativeHalfType && - !Context.getLangOpts().HalfArgsAndReturns) - return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); + !CGM.getContext().getLangOpts().NativeHalfType && + CGM.getContext().getTargetInfo().useFP16ConversionIntrinsics()) + return llvm::ConstantInt::get(CGM.getLLVMContext(), + Init.bitcastToAPInt()); else - return llvm::ConstantFP::get(VMContext, Init); + return llvm::ConstantFP::get(CGM.getLLVMContext(), Init); } case APValue::ComplexFloat: { llvm::Constant *Complex[2]; - Complex[0] = llvm::ConstantFP::get(VMContext, + Complex[0] = llvm::ConstantFP::get(CGM.getLLVMContext(), Value.getComplexFloatReal()); - Complex[1] = llvm::ConstantFP::get(VMContext, + Complex[1] = llvm::ConstantFP::get(CGM.getLLVMContext(), Value.getComplexFloatImag()); // FIXME: the target may want to specify that this is packed. @@ -1394,9 +1851,9 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, for (unsigned I = 0; I != NumElts; ++I) { const APValue &Elt = Value.getVectorElt(I); if (Elt.isInt()) - Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt()); + Inits[I] = llvm::ConstantInt::get(CGM.getLLVMContext(), Elt.getInt()); else if (Elt.isFloat()) - Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat()); + Inits[I] = llvm::ConstantFP::get(CGM.getLLVMContext(), Elt.getFloat()); else llvm_unreachable("unsupported vector element type"); } @@ -1405,13 +1862,14 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, case APValue::AddrLabelDiff: { const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS(); const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS(); - llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF); - llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF); + llvm::Constant *LHS = tryEmitPrivate(LHSExpr, LHSExpr->getType()); + llvm::Constant *RHS = tryEmitPrivate(RHSExpr, RHSExpr->getType()); + if (!LHS || !RHS) return nullptr; // Compute difference - llvm::Type *ResultType = getTypes().ConvertType(DestType); - LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy); - RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy); + llvm::Type *ResultType = CGM.getTypes().ConvertType(DestType); + LHS = llvm::ConstantExpr::getPtrToInt(LHS, CGM.IntPtrTy); + RHS = llvm::ConstantExpr::getPtrToInt(RHS, CGM.IntPtrTy); llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS); // LLVM is a bit sensitive about the exact format of the @@ -1421,21 +1879,21 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, } case APValue::Struct: case APValue::Union: - return ConstStructBuilder::BuildStruct(*this, CGF, Value, DestType); + return ConstStructBuilder::BuildStruct(*this, Value, DestType); case APValue::Array: { - const ArrayType *CAT = Context.getAsArrayType(DestType); + const ArrayType *CAT = CGM.getContext().getAsArrayType(DestType); unsigned NumElements = Value.getArraySize(); unsigned NumInitElts = Value.getArrayInitializedElts(); // Emit array filler, if there is one. llvm::Constant *Filler = nullptr; if (Value.hasArrayFiller()) - Filler = EmitConstantValueForMemory(Value.getArrayFiller(), - CAT->getElementType(), CGF); + Filler = tryEmitAbstractForMemory(Value.getArrayFiller(), + CAT->getElementType()); // Emit initializer elements. llvm::Type *CommonElementType = - getTypes().ConvertType(CAT->getElementType()); + CGM.getTypes().ConvertType(CAT->getElementType()); // Try to use a ConstantAggregateZero if we can. if (Filler && Filler->isNullValue() && !NumInitElts) { @@ -1444,15 +1902,21 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, return llvm::ConstantAggregateZero::get(AType); } - std::vector<llvm::Constant*> Elts; + SmallVector<llvm::Constant*, 16> Elts; Elts.reserve(NumElements); for (unsigned I = 0; I < NumElements; ++I) { llvm::Constant *C = Filler; - if (I < NumInitElts) - C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I), - CAT->getElementType(), CGF); - else - assert(Filler && "Missing filler for implicit elements of initializer"); + if (I < NumInitElts) { + C = tryEmitPrivateForMemory(Value.getArrayInitializedElt(I), + CAT->getElementType()); + } else if (!Filler) { + assert(Value.hasArrayFiller() && + "Missing filler for implicit elements of initializer"); + C = tryEmitPrivateForMemory(Value.getArrayFiller(), + CAT->getElementType()); + } + if (!C) return nullptr; + if (I == 0) CommonElementType = C->getType(); else if (C->getType() != CommonElementType) @@ -1466,7 +1930,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, Types.reserve(NumElements); for (unsigned i = 0, e = Elts.size(); i < e; ++i) Types.push_back(Elts[i]->getType()); - llvm::StructType *SType = llvm::StructType::get(VMContext, Types, true); + llvm::StructType *SType = + llvm::StructType::get(CGM.getLLVMContext(), Types, true); return llvm::ConstantStruct::get(SType, Elts); } @@ -1475,23 +1940,11 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, return llvm::ConstantArray::get(AType, Elts); } case APValue::MemberPointer: - return getCXXABI().EmitMemberPointer(Value, DestType); + return CGM.getCXXABI().EmitMemberPointer(Value, DestType); } llvm_unreachable("Unknown APValue kind"); } -llvm::Constant * -CodeGenModule::EmitConstantValueForMemory(const APValue &Value, - QualType DestType, - CodeGenFunction *CGF) { - llvm::Constant *C = EmitConstantValue(Value, DestType, CGF); - if (C->getType()->isIntegerTy(1)) { - llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType); - C = llvm::ConstantExpr::getZExt(C, BoolTy); - } - return C; -} - llvm::GlobalVariable *CodeGenModule::getAddrOfConstantCompoundLiteralIfEmitted( const CompoundLiteralExpr *E) { return EmittedCompoundLiterals.lookup(E); @@ -1507,7 +1960,7 @@ void CodeGenModule::setAddrOfConstantCompoundLiteral( ConstantAddress CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) { assert(E->isFileScope() && "not a file-scope compound literal expr"); - return ConstExprEmitter(*this, nullptr).EmitLValue(E); + return tryEmitGlobalCompoundLiteral(*this, nullptr, E); } llvm::Constant * @@ -1629,6 +2082,11 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, return EmitNullConstant(CGM, base, /*asCompleteObject=*/false); } +llvm::Constant *ConstantEmitter::emitNullForMemory(CodeGenModule &CGM, + QualType T) { + return emitForMemory(CGM, CGM.EmitNullConstant(T), T); +} + llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { if (T->getAs<PointerType>()) return getNullPointer( @@ -1643,7 +2101,8 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { QualType ElementTy = CAT->getElementType(); - llvm::Constant *Element = EmitNullConstant(ElementTy); + llvm::Constant *Element = + ConstantEmitter::emitNullForMemory(*this, ElementTy); unsigned NumElements = CAT->getSize().getZExtValue(); SmallVector<llvm::Constant *, 8> Array(NumElements, Element); return llvm::ConstantArray::get(ATy, Array); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp index 1170b014ec7f4..c46215067a68c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -428,14 +428,19 @@ public: return CGF.getOpaqueRValueMapping(E).getScalarVal(); } + Value *emitConstant(const CodeGenFunction::ConstantEmission &Constant, + Expr *E) { + assert(Constant && "not a constant"); + if (Constant.isReference()) + return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E), + E->getExprLoc()); + return Constant.getValue(); + } + // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { - if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { - if (result.isReference()) - return EmitLoadOfLValue(result.getReferenceLValue(CGF, E), - E->getExprLoc()); - return result.getValue(); - } + if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) + return emitConstant(Constant, E); return EmitLoadOfLValue(E); } @@ -946,7 +951,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { // Cast to FP using the intrinsic if the half type itself isn't supported. if (DstTy->isFloatingPointTy()) { - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) return Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, DstTy), Src); @@ -954,7 +959,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // Cast to other types through float, using either the intrinsic or FPExt, // depending on whether the half type itself is supported // (as opposed to operations on half, available with NativeHalfType). - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) { + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) { Src = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, CGF.CGM.FloatTy), @@ -1009,10 +1014,42 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateVectorSplat(NumElements, Src, "splat"); } - // Allow bitcast from vector to integer/fp of the same size. - if (isa<llvm::VectorType>(SrcTy) || - isa<llvm::VectorType>(DstTy)) - return Builder.CreateBitCast(Src, DstTy, "conv"); + if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) { + // Allow bitcast from vector to integer/fp of the same size. + unsigned SrcSize = SrcTy->getPrimitiveSizeInBits(); + unsigned DstSize = DstTy->getPrimitiveSizeInBits(); + if (SrcSize == DstSize) + return Builder.CreateBitCast(Src, DstTy, "conv"); + + // Conversions between vectors of different sizes are not allowed except + // when vectors of half are involved. Operations on storage-only half + // vectors require promoting half vector operands to float vectors and + // truncating the result, which is either an int or float vector, to a + // short or half vector. + + // Source and destination are both expected to be vectors. + llvm::Type *SrcElementTy = SrcTy->getVectorElementType(); + llvm::Type *DstElementTy = DstTy->getVectorElementType(); + (void)DstElementTy; + + assert(((SrcElementTy->isIntegerTy() && + DstElementTy->isIntegerTy()) || + (SrcElementTy->isFloatingPointTy() && + DstElementTy->isFloatingPointTy())) && + "unexpected conversion between a floating-point vector and an " + "integer vector"); + + // Truncate an i32 vector to an i16 vector. + if (SrcElementTy->isIntegerTy()) + return Builder.CreateIntCast(Src, DstTy, false, "conv"); + + // Truncate a float vector to a half vector. + if (SrcSize > DstSize) + return Builder.CreateFPTrunc(Src, DstTy, "conv"); + + // Promote a half vector to a float vector. + return Builder.CreateFPExt(Src, DstTy, "conv"); + } // Finally, we have the arithmetic types: real int/float. Value *Res = nullptr; @@ -1031,7 +1068,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (SrcTy->isFloatingPointTy()) { // Use the intrinsic if the half type itself isn't supported // (as opposed to operations on half, available with NativeHalfType). - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) return Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, SrcTy), Src); // If the half type is supported, just use an fptrunc. @@ -1067,7 +1104,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, } if (DstTy != ResTy) { - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) { + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) { assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion"); Res = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy), @@ -1299,13 +1336,15 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) { } Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { - llvm::APSInt Value; - if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { - if (E->isArrow()) - CGF.EmitScalarExpr(E->getBase()); - else - EmitLValue(E->getBase()); - return Builder.getInt(Value); + if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) { + CGF.EmitIgnoredExpr(E->getBase()); + return emitConstant(Constant, E); + } else { + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { + CGF.EmitIgnoredExpr(E->getBase()); + return Builder.getInt(Value); + } } return EmitLoadOfLValue(E); @@ -1778,7 +1817,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } case CK_IntToOCLSampler: - return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+ return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF); } // end of switch @@ -1989,7 +2028,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { // Another special case: half FP increment should be done via float - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) { + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) { value = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, CGF.CGM.FloatTy), @@ -2024,7 +2063,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { - if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) { + if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) { value = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy), @@ -2671,6 +2710,30 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth(); auto &DL = CGF.CGM.getDataLayout(); auto PtrTy = cast<llvm::PointerType>(pointer->getType()); + + // Some versions of glibc and gcc use idioms (particularly in their malloc + // routines) that add a pointer-sized integer (known to be a pointer value) + // to a null pointer in order to cast the value back to an integer or as + // part of a pointer alignment algorithm. This is undefined behavior, but + // we'd like to be able to compile programs that use it. + // + // Normally, we'd generate a GEP with a null-pointer base here in response + // to that code, but it's also UB to dereference a pointer created that + // way. Instead (as an acknowledged hack to tolerate the idiom) we will + // generate a direct cast of the integer value to a pointer. + // + // The idiom (p = nullptr + N) is not met if any of the following are true: + // + // The operation is subtraction. + // The index is not pointer-sized. + // The pointer type is not byte-sized. + // + if (BinaryOperator::isNullPointerArithmeticExtension(CGF.getContext(), + op.Opcode, + expr->getLHS(), + expr->getRHS())) + return CGF.Builder.CreateIntToPtr(index, pointer->getType()); + if (width != DL.getTypeSizeInBits(PtrTy)) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. @@ -3057,16 +3120,25 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT, return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p : llvm::Intrinsic::ppc_altivec_vcmpgtsh_p; case BuiltinType::UInt: - case BuiltinType::ULong: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : llvm::Intrinsic::ppc_altivec_vcmpgtuw_p; case BuiltinType::Int: - case BuiltinType::Long: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : llvm::Intrinsic::ppc_altivec_vcmpgtsw_p; + case BuiltinType::ULong: + case BuiltinType::ULongLong: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p : + llvm::Intrinsic::ppc_altivec_vcmpgtud_p; + case BuiltinType::Long: + case BuiltinType::LongLong: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p : + llvm::Intrinsic::ppc_altivec_vcmpgtsd_p; case BuiltinType::Float: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p : llvm::Intrinsic::ppc_altivec_vcmpgtfp_p; + case BuiltinType::Double: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_vsx_xvcmpeqdp_p : + llvm::Intrinsic::ppc_vsx_xvcmpgtdp_p; } } @@ -3151,6 +3223,16 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, Value *CR6Param = Builder.getInt32(CR6); llvm::Function *F = CGF.CGM.getIntrinsic(ID); Result = Builder.CreateCall(F, {CR6Param, FirstVecArg, SecondVecArg}); + + // The result type of intrinsic may not be same as E->getType(). + // If E->getType() is not BoolTy, EmitScalarConversion will do the + // conversion work. If E->getType() is BoolTy, EmitScalarConversion will + // do nothing, if ResultTy is not i1 at the same time, it will cause + // crash later. + llvm::IntegerType *ResultTy = cast<llvm::IntegerType>(Result->getType()); + if (ResultTy->getBitWidth() > 1 && + E->getType() == CGF.getContext().BoolTy) + Result = Builder.CreateTrunc(Result, Builder.getInt1Ty()); return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType(), E->getExprLoc()); } @@ -3840,6 +3922,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue( case BO_GE: case BO_EQ: case BO_NE: + case BO_Cmp: case BO_And: case BO_Xor: case BO_Or: diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp index 90fcad2614154..f26263d9472d3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp @@ -162,7 +162,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, const Expr *Rhs = ALE->getElement(i); LValue LV = MakeAddrLValue( Builder.CreateConstArrayGEP(Objects, i, getPointerSize()), - ElementType, LValueBaseInfo(AlignmentSource::Decl, false)); + ElementType, AlignmentSource::Decl); llvm::Value *value = EmitScalarExpr(Rhs); EmitStoreThroughLValue(RValue::get(value), LV, true); @@ -174,7 +174,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, const Expr *Key = DLE->getKeyValueElement(i).Key; LValue KeyLV = MakeAddrLValue( Builder.CreateConstArrayGEP(Keys, i, getPointerSize()), - ElementType, LValueBaseInfo(AlignmentSource::Decl, false)); + ElementType, AlignmentSource::Decl); llvm::Value *keyValue = EmitScalarExpr(Key); EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true); @@ -182,7 +182,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, const Expr *Value = DLE->getKeyValueElement(i).Value; LValue ValueLV = MakeAddrLValue( Builder.CreateConstArrayGEP(Objects, i, getPointerSize()), - ElementType, LValueBaseInfo(AlignmentSource::Decl, false)); + ElementType, AlignmentSource::Decl); llvm::Value *valueValue = EmitScalarExpr(Value); EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true); if (TrackNeededObjects) { @@ -1546,16 +1546,15 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. - llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); - llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems); - Args.add(RValue::get(Count), getContext().UnsignedLongTy); + llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType()); + llvm::Constant *Count = llvm::ConstantInt::get(NSUIntegerTy, NumItems); + Args.add(RValue::get(Count), getContext().getNSUIntegerType()); // Start the enumeration. RValue CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), - getContext().UnsignedLongTy, - FastEnumSel, - Collection, Args); + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().getNSUIntegerType(), + FastEnumSel, Collection, Args); // The initial number of objects that were returned in the buffer. llvm::Value *initialBufferLimit = CountRV.getScalarVal(); @@ -1563,7 +1562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::BasicBlock *EmptyBB = createBasicBlock("forcoll.empty"); llvm::BasicBlock *LoopInitBB = createBasicBlock("forcoll.loopinit"); - llvm::Value *zero = llvm::Constant::getNullValue(UnsignedLongLTy); + llvm::Value *zero = llvm::Constant::getNullValue(NSUIntegerTy); // If the limit pointer was zero to begin with, the collection is // empty; skip all this. Set the branch weight assuming this has the same @@ -1595,11 +1594,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(LoopBodyBB); // The current index into the buffer. - llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index"); + llvm::PHINode *index = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.index"); index->addIncoming(zero, LoopInitBB); // The current buffer size. - llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count"); + llvm::PHINode *count = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.count"); count->addIncoming(initialBufferLimit, LoopInitBB); incrementProfileCounter(&S); @@ -1709,8 +1708,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch"); // First we check in the local buffer. - llvm::Value *indexPlusOne - = Builder.CreateAdd(index, llvm::ConstantInt::get(UnsignedLongLTy, 1)); + llvm::Value *indexPlusOne = + Builder.CreateAdd(index, llvm::ConstantInt::get(NSUIntegerTy, 1)); // If we haven't overrun the buffer yet, we can continue. // Set the branch weights based on the simplifying assumption that this is @@ -1727,10 +1726,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(FetchMoreBB); CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), - getContext().UnsignedLongTy, - FastEnumSel, - Collection, Args); + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().getNSUIntegerType(), + FastEnumSel, Collection, Args); // If we got a zero count, we're done. llvm::Value *refetchCount = CountRV.getScalarVal(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 98435fefbd2ea..ef4e6cd4f01b3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -4885,10 +4885,7 @@ void CGObjCCommonMac::EmitImageInfo() { } // Indicate whether we're compiling this to run on a simulator. - const llvm::Triple &Triple = CGM.getTarget().getTriple(); - if ((Triple.isiOS() || Triple.isWatchOS()) && - (Triple.getArch() == llvm::Triple::x86 || - Triple.getArch() == llvm::Triple::x86_64)) + if (CGM.getTarget().getTriple().isSimulatorEnvironment()) Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated", eImageInfo_ImageIsSimulated); @@ -5084,6 +5081,11 @@ void IvarLayoutBuilder::visitField(const FieldDecl *field, // Drill down into arrays. uint64_t numElts = 1; + if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) { + numElts = 0; + fieldType = arrayType->getElementType(); + } + // Unlike incomplete arrays, constant arrays can be nested. while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) { numElts *= arrayType->getSize().getZExtValue(); fieldType = arrayType->getElementType(); @@ -6615,10 +6617,14 @@ CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, Ivar->getAccessControl() == ObjCIvarDecl::Private || Ivar->getAccessControl() == ObjCIvarDecl::Package; - if (ID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage) - IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); - else if (ID->hasAttr<DLLImportAttr>()) - IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface(); + + if (ContainingID->hasAttr<DLLImportAttr>()) + IvarOffsetGV + ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + else if (ContainingID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage) + IvarOffsetGV + ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); } } return IvarOffsetGV; @@ -7549,8 +7555,9 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2); ConstantInitBuilder builder(CGM); auto values = builder.beginStruct(ObjCTypes.EHTypeTy); - values.add(llvm::ConstantExpr::getGetElementPtr(VTableGV->getValueType(), - VTableGV, VTableIdx)); + values.add( + llvm::ConstantExpr::getInBoundsGetElementPtr(VTableGV->getValueType(), + VTableGV, VTableIdx)); values.add(GetClassName(ClassName)); values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition)); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp index 4cfddcb107cb3..2f886fd82caa7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -110,7 +110,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, llvm::Type::getIntNTy(CGF.getLLVMContext(), Info->StorageSize)); return LValue::MakeBitfield(Addr, *Info, IvarTy, - LValueBaseInfo(AlignmentSource::Decl, false)); + LValueBaseInfo(AlignmentSource::Decl), + TBAAAccessInfo()); } namespace { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp index db02c631c9e64..d140e7f09e9a6 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -16,6 +16,7 @@ #include "CGOpenCLRuntime.h" #include "CodeGenFunction.h" #include "TargetInfo.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" #include <assert.h> @@ -35,8 +36,8 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) { "Not an OpenCL specific type!"); llvm::LLVMContext& Ctx = CGM.getLLVMContext(); - uint32_t ImgAddrSpc = CGM.getContext().getTargetAddressSpace( - CGM.getTarget().getOpenCLImageAddrSpace()); + uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace( + CGM.getContext().getOpenCLTypeAddrSpace(T)); switch (cast<BuiltinType>(T)->getKind()) { default: llvm_unreachable("Unexpected opencl builtin type!"); @@ -45,29 +46,29 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) { case BuiltinType::Id: \ return llvm::PointerType::get( \ llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \ - ImgAddrSpc); + AddrSpc); #include "clang/Basic/OpenCLImageTypes.def" case BuiltinType::OCLSampler: - return getSamplerType(); + return getSamplerType(T); case BuiltinType::OCLEvent: - return llvm::PointerType::get(llvm::StructType::create( - Ctx, "opencl.event_t"), 0); + return llvm::PointerType::get( + llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc); case BuiltinType::OCLClkEvent: return llvm::PointerType::get( - llvm::StructType::create(Ctx, "opencl.clk_event_t"), 0); + llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc); case BuiltinType::OCLQueue: return llvm::PointerType::get( - llvm::StructType::create(Ctx, "opencl.queue_t"), 0); + llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc); case BuiltinType::OCLReserveID: return llvm::PointerType::get( - llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0); + llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc); } } -llvm::Type *CGOpenCLRuntime::getPipeType() { +llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) { if (!PipeTy){ - uint32_t PipeAddrSpc = - CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + uint32_t PipeAddrSpc = CGM.getContext().getTargetAddressSpace( + CGM.getContext().getOpenCLTypeAddrSpace(T)); PipeTy = llvm::PointerType::get(llvm::StructType::create( CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc); } @@ -75,12 +76,12 @@ llvm::Type *CGOpenCLRuntime::getPipeType() { return PipeTy; } -llvm::PointerType *CGOpenCLRuntime::getSamplerType() { +llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) { if (!SamplerTy) SamplerTy = llvm::PointerType::get(llvm::StructType::create( CGM.getLLVMContext(), "opencl.sampler_t"), CGM.getContext().getTargetAddressSpace( - LangAS::opencl_constant)); + CGM.getContext().getOpenCLTypeAddrSpace(T))); return SamplerTy; } @@ -103,3 +104,45 @@ llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) { .getQuantity(); return llvm::ConstantInt::get(Int32Ty, TypeSize, false); } + +llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() { + assert(CGM.getLangOpts().OpenCL); + return llvm::IntegerType::getInt8PtrTy( + CGM.getLLVMContext(), + CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic)); +} + +CGOpenCLRuntime::EnqueuedBlockInfo +CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) { + // The block literal may be assigned to a const variable. Chasing down + // to get the block literal. + if (auto DR = dyn_cast<DeclRefExpr>(E)) { + E = cast<VarDecl>(DR->getDecl())->getInit(); + } + if (auto Cast = dyn_cast<CastExpr>(E)) { + E = Cast->getSubExpr(); + } + auto *Block = cast<BlockExpr>(E); + + // The same block literal may be enqueued multiple times. Cache it if + // possible. + auto Loc = EnqueuedBlockMap.find(Block); + if (Loc != EnqueuedBlockMap.end()) { + return Loc->second; + } + + // Emit block literal as a common block expression and get the block invoke + // function. + llvm::Function *Invoke; + auto *V = CGF.EmitBlockLiteral(cast<BlockExpr>(Block), &Invoke); + auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel( + CGF, Invoke, V->stripPointerCasts()); + + // The common part of the post-processing of the kernel goes here. + F->addFnAttr(llvm::Attribute::NoUnwind); + F->setCallingConv( + CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel)); + EnqueuedBlockInfo Info{F, V}; + EnqueuedBlockMap[Block] = Info; + return Info; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h index ee3cb3dda0631..ead303d1d0d5e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h @@ -17,11 +17,13 @@ #define LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H #include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" namespace clang { +class Expr; class VarDecl; namespace CodeGen { @@ -35,6 +37,14 @@ protected: llvm::Type *PipeTy; llvm::PointerType *SamplerTy; + /// Structure for enqueued block information. + struct EnqueuedBlockInfo { + llvm::Function *Kernel; /// Enqueued block kernel. + llvm::Value *BlockArg; /// The first argument to enqueued block kernel. + }; + /// Maps block expression to block information. + llvm::DenseMap<const Expr *, EnqueuedBlockInfo> EnqueuedBlockMap; + public: CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr), SamplerTy(nullptr) {} @@ -48,9 +58,9 @@ public: virtual llvm::Type *convertOpenCLSpecificType(const Type *T); - virtual llvm::Type *getPipeType(); + virtual llvm::Type *getPipeType(const PipeType *T); - llvm::PointerType *getSamplerType(); + llvm::PointerType *getSamplerType(const Type *T); // \brief Returnes a value which indicates the size in bytes of the pipe // element. @@ -59,6 +69,13 @@ public: // \brief Returnes a value which indicates the alignment in bytes of the pipe // element. virtual llvm::Value *getPipeElemAlign(const Expr *PipeArg); + + /// \return __generic void* type. + llvm::PointerType *getGenericVoidPointerType(); + + /// \return enqueued block information for enqueued block. + EnqueuedBlockInfo emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, + const Expr *E); }; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 9f8aa6c8d964c..5db29eb6004d7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/StmtOpenMP.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DerivedTypes.h" @@ -427,7 +428,7 @@ public: /// \brief Values for bit flags used in the ident_t to describe the fields. /// All enumeric elements are named and described in accordance with the code /// from http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h -enum OpenMPLocationFlags { +enum OpenMPLocationFlags : unsigned { /// \brief Use trampoline for internal microtask. OMP_IDENT_IMD = 0x01, /// \brief Use c-style ident structure. @@ -443,7 +444,14 @@ enum OpenMPLocationFlags { /// \brief Implicit barrier in 'sections' directive. OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0, /// \brief Implicit barrier in 'single' directive. - OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140 + OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140, + /// Call of __kmp_for_static_init for static loop. + OMP_IDENT_WORK_LOOP = 0x200, + /// Call of __kmp_for_static_init for sections. + OMP_IDENT_WORK_SECTIONS = 0x400, + /// Call of __kmp_for_static_init for distribute. + OMP_IDENT_WORK_DISTRIBUTE = 0x800, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE) }; /// \brief Describes ident structure that describes a source location. @@ -660,27 +668,47 @@ enum OpenMPRTLFunction { // // Offloading related calls // - // Call to int32_t __tgt_target(int32_t device_id, void *host_ptr, int32_t - // arg_num, void** args_base, void **args, size_t *arg_sizes, int32_t + // Call to int32_t __tgt_target(int64_t device_id, void *host_ptr, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t // *arg_types); OMPRTL__tgt_target, - // Call to int32_t __tgt_target_teams(int32_t device_id, void *host_ptr, - // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, - // int32_t *arg_types, int32_t num_teams, int32_t thread_limit); + // Call to int32_t __tgt_target_nowait(int64_t device_id, void *host_ptr, + // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + OMPRTL__tgt_target_nowait, + // Call to int32_t __tgt_target_teams(int64_t device_id, void *host_ptr, + // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types, int32_t num_teams, int32_t thread_limit); OMPRTL__tgt_target_teams, + // Call to int32_t __tgt_target_teams_nowait(int64_t device_id, void + // *host_ptr, int32_t arg_num, void** args_base, void **args, size_t + // *arg_sizes, int64_t *arg_types, int32_t num_teams, int32_t thread_limit); + OMPRTL__tgt_target_teams_nowait, // Call to void __tgt_register_lib(__tgt_bin_desc *desc); OMPRTL__tgt_register_lib, // Call to void __tgt_unregister_lib(__tgt_bin_desc *desc); OMPRTL__tgt_unregister_lib, - // Call to void __tgt_target_data_begin(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); + // Call to void __tgt_target_data_begin(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); OMPRTL__tgt_target_data_begin, - // Call to void __tgt_target_data_end(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); + // Call to void __tgt_target_data_begin_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + OMPRTL__tgt_target_data_begin_nowait, + // Call to void __tgt_target_data_end(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); OMPRTL__tgt_target_data_end, - // Call to void __tgt_target_data_update(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); + // Call to void __tgt_target_data_end_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + OMPRTL__tgt_target_data_end_nowait, + // Call to void __tgt_target_data_update(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); OMPRTL__tgt_target_data_update, + // Call to void __tgt_target_data_update_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + OMPRTL__tgt_target_data_update_nowait, }; /// A basic class for pre|post-action for advanced codegen sequence for OpenMP @@ -862,18 +890,7 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, } LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) { - if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(E)) - return CGF.EmitOMPArraySectionExpr(OASE); - if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) - return CGF.EmitLValue(ASE); - auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); - DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD), - CGF.CapturedStmtInfo && - CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr, - E->getType(), VK_LValue, E->getExprLoc()); - // Store the address of the original variable associated with the LHS - // implicit variable. - return CGF.EmitLValue(&DRE); + return CGF.EmitOMPSharedLValue(E); } LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF, @@ -919,8 +936,9 @@ ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds, void ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, unsigned N) { assert(SharedAddresses.size() == N && "Number of generated lvalues must be exactly N."); - SharedAddresses.emplace_back(emitSharedLValue(CGF, ClausesData[N].Ref), - emitSharedLValueUB(CGF, ClausesData[N].Ref)); + LValue First = emitSharedLValue(CGF, ClausesData[N].Ref); + LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref); + SharedAddresses.emplace_back(First, Second); } void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { @@ -928,7 +946,7 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { Sizes.emplace_back( CGF.getTypeSize( SharedAddresses[N].first.getType().getNonReferenceType()), @@ -966,10 +984,9 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N, auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); - bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { assert(!Size && !Sizes[N].second && - "Size should be nullptr for non-variably modified redution " + "Size should be nullptr for non-variably modified reduction " "items."); return; } @@ -995,9 +1012,9 @@ void ReductionCodeGen::emitInitialization( SharedLVal = CGF.MakeAddrLValue( CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(), CGF.ConvertTypeForMem(SharedType)), - SharedType, SharedAddresses[N].first.getBaseInfo()); - if (isa<OMPArraySectionExpr>(ClausesData[N].Ref) || - CGF.getContext().getAsArrayType(PrivateVD->getType())) { + SharedType, SharedAddresses[N].first.getBaseInfo(), + CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType)); + if (CGF.getContext().getAsArrayType(PrivateVD->getType())) { emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD); } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp, @@ -1040,15 +1057,16 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, if (auto *PtrTy = BaseTy->getAs<PointerType>()) BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy); else { - BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(), - BaseTy->castAs<ReferenceType>()); + LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy); + BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal); } BaseTy = BaseTy->getPointeeType(); } return CGF.MakeAddrLValue( CGF.Builder.CreateElementBitCast(BaseLV.getAddress(), CGF.ConvertTypeForMem(ElTy)), - BaseLV.getType(), BaseLV.getBaseInfo()); + BaseLV.getType(), BaseLV.getBaseInfo(), + CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType())); } static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, @@ -1106,11 +1124,14 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, OriginalBaseLValue); llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff( BaseLValue.getPointer(), SharedAddresses[N].first.getPointer()); - llvm::Value *Ptr = - CGF.Builder.CreateGEP(PrivateAddr.getPointer(), Adjustment); + llvm::Value *PrivatePointer = + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + PrivateAddr.getPointer(), + SharedAddresses[N].first.getAddress().getType()); + llvm::Value *Ptr = CGF.Builder.CreateGEP(PrivatePointer, Adjustment); return castToBase(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(), - OriginalBaseLValue.getPointer()->getType(), + OriginalBaseLValue.getAddress().getType(), OriginalBaseLValue.getAlignment(), Ptr); } BaseDecls.emplace_back( @@ -1146,7 +1167,7 @@ LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue( CodeGenFunction &CGF) { return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()), getThreadIDVariable()->getType(), - LValueBaseInfo(AlignmentSource::Decl, false)); + AlignmentSource::Decl); } CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) @@ -1204,7 +1225,14 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty, .getAddress(); }); (void)Scope.Privatize(); - CGF.EmitIgnoredExpr(CombinerInitializer); + if (!IsCombiner && Out->hasInit() && + !CGF.isTrivialInitializer(Out->getInit())) { + CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out), + Out->getType().getQualifiers(), + /*IsInitializer=*/true); + } + if (CombinerInitializer) + CGF.EmitIgnoredExpr(CombinerInitializer); Scope.ForceCleanup(); CGF.FinishFunction(); return Fn; @@ -1230,7 +1258,10 @@ void CGOpenMPRuntime::emitUserDefinedReduction( Orig = &C.Idents.get("omp_orig"); } Initializer = emitCombinerOrInitializer( - CGM, D->getType(), Init, cast<VarDecl>(D->lookup(Orig).front()), + CGM, D->getType(), + D->getInitializerKind() == OMPDeclareReductionDecl::CallInit ? Init + : nullptr, + cast<VarDecl>(D->lookup(Orig).front()), cast<VarDecl>(D->lookup(Priv).front()), /*IsCombiner=*/false); } @@ -1283,6 +1314,15 @@ static llvm::Value *emitParallelOrTeamsOutlinedFunction( HasCancel = OPSD->hasCancel(); else if (auto *OPFD = dyn_cast<OMPParallelForDirective>(&D)) HasCancel = OPFD->hasCancel(); + else if (auto *OPFD = dyn_cast<OMPTargetParallelForDirective>(&D)) + HasCancel = OPFD->hasCancel(); + else if (auto *OPFD = dyn_cast<OMPDistributeParallelForDirective>(&D)) + HasCancel = OPFD->hasCancel(); + else if (auto *OPFD = dyn_cast<OMPTeamsDistributeParallelForDirective>(&D)) + HasCancel = OPFD->hasCancel(); + else if (auto *OPFD = + dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D)) + HasCancel = OPFD->hasCancel(); CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind, HasCancel, OutlinedHelperName); CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); @@ -1442,19 +1482,24 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF, if (ThreadID != nullptr) return ThreadID; } - if (auto *OMPRegionInfo = - dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { - if (OMPRegionInfo->getThreadIDVariable()) { - // Check if this an outlined function with thread id passed as argument. - auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF); - ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal(); - // If value loaded in entry block, cache it and use it everywhere in - // function. - if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) { - auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); - Elem.second.ThreadID = ThreadID; + // If exceptions are enabled, do not use parameter to avoid possible crash. + if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions || + !CGF.getLangOpts().CXXExceptions || + CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) { + if (auto *OMPRegionInfo = + dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { + if (OMPRegionInfo->getThreadIDVariable()) { + // Check if this an outlined function with thread id passed as argument. + auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF); + ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal(); + // If value loaded in entry block, cache it and use it everywhere in + // function. + if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) { + auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); + Elem.second.ThreadID = ThreadID; + } + return ThreadID; } - return ThreadID; } } @@ -1464,12 +1509,13 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF, // function. CGBuilderTy::InsertPointGuard IPG(CGF.Builder); CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); - ThreadID = - CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_global_thread_num), - emitUpdateLocation(CGF, Loc)); + auto *Call = CGF.Builder.CreateCall( + createRuntimeFunction(OMPRTL__kmpc_global_thread_num), + emitUpdateLocation(CGF, Loc)); + Call->setCallingConv(CGF.getRuntimeCC()); auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); - Elem.second.ThreadID = ThreadID; - return ThreadID; + Elem.second.ThreadID = Call; + return Call; } void CGOpenMPRuntime::functionFinished(CodeGenFunction &CGF) { @@ -2001,32 +2047,48 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) { break; } case OMPRTL__tgt_target: { - // Build int32_t __tgt_target(int32_t device_id, void *host_ptr, int32_t - // arg_num, void** args_base, void **args, size_t *arg_sizes, int32_t + // Build int32_t __tgt_target(int64_t device_id, void *host_ptr, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t // *arg_types); - llvm::Type *TypeParams[] = {CGM.Int32Ty, + llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.VoidPtrTy, CGM.Int32Ty, CGM.VoidPtrPtrTy, CGM.VoidPtrPtrTy, CGM.SizeTy->getPointerTo(), - CGM.Int32Ty->getPointerTo()}; + CGM.Int64Ty->getPointerTo()}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target"); break; } + case OMPRTL__tgt_target_nowait: { + // Build int32_t __tgt_target_nowait(int64_t device_id, void *host_ptr, + // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, + // int64_t *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, + CGM.VoidPtrTy, + CGM.Int32Ty, + CGM.VoidPtrPtrTy, + CGM.VoidPtrPtrTy, + CGM.SizeTy->getPointerTo(), + CGM.Int64Ty->getPointerTo()}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_nowait"); + break; + } case OMPRTL__tgt_target_teams: { - // Build int32_t __tgt_target_teams(int32_t device_id, void *host_ptr, + // Build int32_t __tgt_target_teams(int64_t device_id, void *host_ptr, // int32_t arg_num, void** args_base, void **args, size_t *arg_sizes, - // int32_t *arg_types, int32_t num_teams, int32_t thread_limit); - llvm::Type *TypeParams[] = {CGM.Int32Ty, + // int64_t *arg_types, int32_t num_teams, int32_t thread_limit); + llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.VoidPtrTy, CGM.Int32Ty, CGM.VoidPtrPtrTy, CGM.VoidPtrPtrTy, CGM.SizeTy->getPointerTo(), - CGM.Int32Ty->getPointerTo(), + CGM.Int64Ty->getPointerTo(), CGM.Int32Ty, CGM.Int32Ty}; llvm::FunctionType *FnTy = @@ -2034,6 +2096,24 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_teams"); break; } + case OMPRTL__tgt_target_teams_nowait: { + // Build int32_t __tgt_target_teams_nowait(int64_t device_id, void + // *host_ptr, int32_t arg_num, void** args_base, void **args, size_t + // *arg_sizes, int64_t *arg_types, int32_t num_teams, int32_t thread_limit); + llvm::Type *TypeParams[] = {CGM.Int64Ty, + CGM.VoidPtrTy, + CGM.Int32Ty, + CGM.VoidPtrPtrTy, + CGM.VoidPtrPtrTy, + CGM.SizeTy->getPointerTo(), + CGM.Int64Ty->getPointerTo(), + CGM.Int32Ty, + CGM.Int32Ty}; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_teams_nowait"); + break; + } case OMPRTL__tgt_register_lib: { // Build void __tgt_register_lib(__tgt_bin_desc *desc); QualType ParamTy = @@ -2055,47 +2135,92 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) { break; } case OMPRTL__tgt_target_data_begin: { - // Build void __tgt_target_data_begin(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); - llvm::Type *TypeParams[] = {CGM.Int32Ty, + // Build void __tgt_target_data_begin(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int32Ty, CGM.VoidPtrPtrTy, CGM.VoidPtrPtrTy, CGM.SizeTy->getPointerTo(), - CGM.Int32Ty->getPointerTo()}; + CGM.Int64Ty->getPointerTo()}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_begin"); break; } + case OMPRTL__tgt_target_data_begin_nowait: { + // Build void __tgt_target_data_begin_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, + CGM.Int32Ty, + CGM.VoidPtrPtrTy, + CGM.VoidPtrPtrTy, + CGM.SizeTy->getPointerTo(), + CGM.Int64Ty->getPointerTo()}; + auto *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_begin_nowait"); + break; + } case OMPRTL__tgt_target_data_end: { - // Build void __tgt_target_data_end(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); - llvm::Type *TypeParams[] = {CGM.Int32Ty, + // Build void __tgt_target_data_end(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int32Ty, CGM.VoidPtrPtrTy, CGM.VoidPtrPtrTy, CGM.SizeTy->getPointerTo(), - CGM.Int32Ty->getPointerTo()}; + CGM.Int64Ty->getPointerTo()}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_end"); break; } + case OMPRTL__tgt_target_data_end_nowait: { + // Build void __tgt_target_data_end_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, + CGM.Int32Ty, + CGM.VoidPtrPtrTy, + CGM.VoidPtrPtrTy, + CGM.SizeTy->getPointerTo(), + CGM.Int64Ty->getPointerTo()}; + auto *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_end_nowait"); + break; + } case OMPRTL__tgt_target_data_update: { - // Build void __tgt_target_data_update(int32_t device_id, int32_t arg_num, - // void** args_base, void **args, size_t *arg_sizes, int32_t *arg_types); - llvm::Type *TypeParams[] = {CGM.Int32Ty, + // Build void __tgt_target_data_update(int64_t device_id, int32_t arg_num, + // void** args_base, void **args, size_t *arg_sizes, int64_t *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int32Ty, CGM.VoidPtrPtrTy, CGM.VoidPtrPtrTy, CGM.SizeTy->getPointerTo(), - CGM.Int32Ty->getPointerTo()}; + CGM.Int64Ty->getPointerTo()}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_update"); break; } + case OMPRTL__tgt_target_data_update_nowait: { + // Build void __tgt_target_data_update_nowait(int64_t device_id, int32_t + // arg_num, void** args_base, void **args, size_t *arg_sizes, int64_t + // *arg_types); + llvm::Type *TypeParams[] = {CGM.Int64Ty, + CGM.Int32Ty, + CGM.VoidPtrPtrTy, + CGM.VoidPtrPtrTy, + CGM.SizeTy->getPointerTo(), + CGM.Int64Ty->getPointerTo()}; + auto *FnTy = + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_update_nowait"); + break; + } } assert(RTLFn && "Unable to find OpenMP runtime function"); return RTLFn; @@ -2459,7 +2584,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, OutlinedFnArgs.push_back(ThreadIDAddr.getPointer()); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); - CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs); + RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); // __kmpc_end_serialized_parallel(&Loc, GTid); llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID}; @@ -2968,87 +3093,101 @@ static void emitForStaticInitCall( CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId, llvm::Constant *ForStaticInitFunction, OpenMPSchedType Schedule, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, - unsigned IVSize, bool Ordered, Address IL, Address LB, Address UB, - Address ST, llvm::Value *Chunk) { + const CGOpenMPRuntime::StaticRTInput &Values) { if (!CGF.HaveInsertPoint()) - return; + return; - assert(!Ordered); - assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked || - Schedule == OMP_sch_static_balanced_chunked || - Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked || - Schedule == OMP_dist_sch_static || - Schedule == OMP_dist_sch_static_chunked); + assert(!Values.Ordered); + assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked || + Schedule == OMP_sch_static_balanced_chunked || + Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked || + Schedule == OMP_dist_sch_static || + Schedule == OMP_dist_sch_static_chunked); - // Call __kmpc_for_static_init( - // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype, - // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower, - // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride, - // kmp_int[32|64] incr, kmp_int[32|64] chunk); - if (Chunk == nullptr) { - assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static || - Schedule == OMP_dist_sch_static) && - "expected static non-chunked schedule"); - // If the Chunk was not specified in the clause - use default value 1. - Chunk = CGF.Builder.getIntN(IVSize, 1); - } else { - assert((Schedule == OMP_sch_static_chunked || - Schedule == OMP_sch_static_balanced_chunked || - Schedule == OMP_ord_static_chunked || - Schedule == OMP_dist_sch_static_chunked) && - "expected static chunked schedule"); - } - llvm::Value *Args[] = { - UpdateLocation, ThreadId, CGF.Builder.getInt32(addMonoNonMonoModifier( - Schedule, M1, M2)), // Schedule type - IL.getPointer(), // &isLastIter - LB.getPointer(), // &LB - UB.getPointer(), // &UB - ST.getPointer(), // &Stride - CGF.Builder.getIntN(IVSize, 1), // Incr - Chunk // Chunk - }; - CGF.EmitRuntimeCall(ForStaticInitFunction, Args); + // Call __kmpc_for_static_init( + // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype, + // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower, + // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride, + // kmp_int[32|64] incr, kmp_int[32|64] chunk); + llvm::Value *Chunk = Values.Chunk; + if (Chunk == nullptr) { + assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static || + Schedule == OMP_dist_sch_static) && + "expected static non-chunked schedule"); + // If the Chunk was not specified in the clause - use default value 1. + Chunk = CGF.Builder.getIntN(Values.IVSize, 1); + } else { + assert((Schedule == OMP_sch_static_chunked || + Schedule == OMP_sch_static_balanced_chunked || + Schedule == OMP_ord_static_chunked || + Schedule == OMP_dist_sch_static_chunked) && + "expected static chunked schedule"); + } + llvm::Value *Args[] = { + UpdateLocation, + ThreadId, + CGF.Builder.getInt32(addMonoNonMonoModifier(Schedule, M1, + M2)), // Schedule type + Values.IL.getPointer(), // &isLastIter + Values.LB.getPointer(), // &LB + Values.UB.getPointer(), // &UB + Values.ST.getPointer(), // &Stride + CGF.Builder.getIntN(Values.IVSize, 1), // Incr + Chunk // Chunk + }; + CGF.EmitRuntimeCall(ForStaticInitFunction, Args); } void CGOpenMPRuntime::emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind DKind, const OpenMPScheduleTy &ScheduleKind, - unsigned IVSize, bool IVSigned, - bool Ordered, Address IL, Address LB, - Address UB, Address ST, - llvm::Value *Chunk) { - OpenMPSchedType ScheduleNum = - getRuntimeSchedule(ScheduleKind.Schedule, Chunk != nullptr, Ordered); - auto *UpdatedLocation = emitUpdateLocation(CGF, Loc); + const StaticRTInput &Values) { + OpenMPSchedType ScheduleNum = getRuntimeSchedule( + ScheduleKind.Schedule, Values.Chunk != nullptr, Values.Ordered); + assert(isOpenMPWorksharingDirective(DKind) && + "Expected loop-based or sections-based directive."); + auto *UpdatedLocation = emitUpdateLocation(CGF, Loc, + isOpenMPLoopDirective(DKind) + ? OMP_IDENT_WORK_LOOP + : OMP_IDENT_WORK_SECTIONS); auto *ThreadId = getThreadID(CGF, Loc); - auto *StaticInitFunction = createForStaticInitFunction(IVSize, IVSigned); + auto *StaticInitFunction = + createForStaticInitFunction(Values.IVSize, Values.IVSigned); emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction, - ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, IVSize, - Ordered, IL, LB, UB, ST, Chunk); + ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values); } void CGOpenMPRuntime::emitDistributeStaticInit( CodeGenFunction &CGF, SourceLocation Loc, - OpenMPDistScheduleClauseKind SchedKind, unsigned IVSize, bool IVSigned, - bool Ordered, Address IL, Address LB, Address UB, Address ST, - llvm::Value *Chunk) { - OpenMPSchedType ScheduleNum = getRuntimeSchedule(SchedKind, Chunk != nullptr); - auto *UpdatedLocation = emitUpdateLocation(CGF, Loc); + OpenMPDistScheduleClauseKind SchedKind, + const CGOpenMPRuntime::StaticRTInput &Values) { + OpenMPSchedType ScheduleNum = + getRuntimeSchedule(SchedKind, Values.Chunk != nullptr); + auto *UpdatedLocation = + emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE); auto *ThreadId = getThreadID(CGF, Loc); - auto *StaticInitFunction = createForStaticInitFunction(IVSize, IVSigned); + auto *StaticInitFunction = + createForStaticInitFunction(Values.IVSize, Values.IVSigned); emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction, ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown, - OMPC_SCHEDULE_MODIFIER_unknown, IVSize, Ordered, IL, LB, - UB, ST, Chunk); + OMPC_SCHEDULE_MODIFIER_unknown, Values); } void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF, - SourceLocation Loc) { + SourceLocation Loc, + OpenMPDirectiveKind DKind) { if (!CGF.HaveInsertPoint()) return; // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid); - llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)}; + llvm::Value *Args[] = { + emitUpdateLocation(CGF, Loc, + isOpenMPDistributeDirective(DKind) + ? OMP_IDENT_WORK_DISTRIBUTE + : isOpenMPLoopDirective(DKind) + ? OMP_IDENT_WORK_LOOP + : OMP_IDENT_WORK_SECTIONS), + getThreadID(CGF, Loc)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_for_static_fini), Args); } @@ -3360,14 +3499,14 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() { auto *UnRegFn = createOffloadingBinaryDescriptorFunction( CGM, ".omp_offloading.descriptor_unreg", [&](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_unregister_lib), - Desc); + CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_unregister_lib), + Desc); }); auto *RegFn = createOffloadingBinaryDescriptorFunction( CGM, ".omp_offloading.descriptor_reg", [&](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_register_lib), - Desc); + CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_register_lib), + Desc); CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc); }); if (CGM.supportsCOMDAT()) { @@ -3802,7 +3941,6 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, ".omp_task_entry.", &CGM.getModule()); CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskEntry, TaskEntryFnInfo); CodeGenFunction CGF(CGM); - CGF.disableDebugInfo(); CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args); // TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map, @@ -3871,7 +4009,8 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, } CallArgs.push_back(SharedsParam); - CGF.EmitCallOrInvoke(TaskFunction, CallArgs); + CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction, + CallArgs); CGF.EmitStoreThroughLValue( RValue::get(CGF.Builder.getInt32(/*C=*/0)), CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty)); @@ -3893,7 +4032,6 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM, ImplicitParamDecl::Other); Args.push_back(&GtidArg); Args.push_back(&TaskTypeArg); - FunctionType::ExtInfo Info; auto &DestructorFnInfo = CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args); auto *DestructorFnTy = CGM.getTypes().GetFunctionType(DestructorFnInfo); @@ -4020,9 +4158,9 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, return TaskPrivatesMap; } -static int array_pod_sort_comparator(const PrivateDataTy *P1, - const PrivateDataTy *P2) { - return P1->first < P2->first ? 1 : (P2->first < P1->first ? -1 : 0); +static bool stable_sort_comparator(const PrivateDataTy P1, + const PrivateDataTy P2) { + return P1.first > P2.first; } /// Emit initialization for private variables in task-based directives. @@ -4059,8 +4197,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF, SharedRefLValue = CGF.MakeAddrLValue( Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)), SharedRefLValue.getType(), - LValueBaseInfo(AlignmentSource::Decl, - SharedRefLValue.getBaseInfo().getMayAlias())); + LValueBaseInfo(AlignmentSource::Decl), + SharedRefLValue.getTBAAInfo()); QualType Type = OriginalVD->getType(); if (Type->isArrayType()) { // Initialize firstprivate array. @@ -4250,8 +4388,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, /*PrivateElemInit=*/nullptr))); ++I; } - llvm::array_pod_sort(Privates.begin(), Privates.end(), - array_pod_sort_comparator); + std::stable_sort(Privates.begin(), Privates.end(), stable_sort_comparator); auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); // Build type kmp_routine_entry_t (if not built yet). emitKmpRoutineEntryT(KmpInt32Ty); @@ -4262,7 +4399,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy)); } KmpTaskTQTy = SavedKmpTaskloopTQTy; - } else if (D.getDirectiveKind() == OMPD_task) { + } else { assert(D.getDirectiveKind() == OMPD_task && "Expected taskloop or task directive"); if (SavedKmpTaskTQTy.isNull()) { @@ -4557,8 +4694,8 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); } auto &&ElseCodeGen = [&TaskArgs, ThreadID, NewTaskNewTaskTTy, TaskEntry, - NumDependencies, &DepWaitTaskArgs](CodeGenFunction &CGF, - PrePostActionTy &) { + NumDependencies, &DepWaitTaskArgs, + Loc](CodeGenFunction &CGF, PrePostActionTy &) { auto &RT = CGF.CGM.getOpenMPRuntime(); CodeGenFunction::RunCleanupsScope LocalScope(CGF); // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid, @@ -4569,11 +4706,12 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, CGF.EmitRuntimeCall(RT.createRuntimeFunction(OMPRTL__kmpc_omp_wait_deps), DepWaitTaskArgs); // Call proxy_task_entry(gtid, new_task); - auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy]( - CodeGenFunction &CGF, PrePostActionTy &Action) { + auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy, + Loc](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy}; - CGF.EmitCallOrInvoke(TaskEntry, OutlinedFnArgs); + CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry, + OutlinedFnArgs); }; // Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid, @@ -5805,21 +5943,21 @@ emitNumTeamsForTargetDirective(CGOpenMPRuntime &OMPRuntime, const CapturedStmt &CS = *cast<CapturedStmt>(D.getAssociatedStmt()); - // FIXME: Accommodate other combined directives with teams when they become - // available. - if (auto *TeamsDir = dyn_cast_or_null<OMPTeamsDirective>( + if (auto *TeamsDir = dyn_cast_or_null<OMPExecutableDirective>( ignoreCompoundStmts(CS.getCapturedStmt()))) { - if (auto *NTE = TeamsDir->getSingleClause<OMPNumTeamsClause>()) { - CGOpenMPInnerExprInfo CGInfo(CGF, CS); - CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); - llvm::Value *NumTeams = CGF.EmitScalarExpr(NTE->getNumTeams()); - return Bld.CreateIntCast(NumTeams, CGF.Int32Ty, - /*IsSigned=*/true); - } + if (isOpenMPTeamsDirective(TeamsDir->getDirectiveKind())) { + if (auto *NTE = TeamsDir->getSingleClause<OMPNumTeamsClause>()) { + CGOpenMPInnerExprInfo CGInfo(CGF, CS); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); + llvm::Value *NumTeams = CGF.EmitScalarExpr(NTE->getNumTeams()); + return Bld.CreateIntCast(NumTeams, CGF.Int32Ty, + /*IsSigned=*/true); + } - // If we have an enclosed teams directive but no num_teams clause we use - // the default value 0. - return Bld.getInt32(0); + // If we have an enclosed teams directive but no num_teams clause we use + // the default value 0. + return Bld.getInt32(0); + } } // No teams associated with the directive. @@ -5908,21 +6046,21 @@ emitNumThreadsForTargetDirective(CGOpenMPRuntime &OMPRuntime, const CapturedStmt &CS = *cast<CapturedStmt>(D.getAssociatedStmt()); - // FIXME: Accommodate other combined directives with teams when they become - // available. - if (auto *TeamsDir = dyn_cast_or_null<OMPTeamsDirective>( + if (auto *TeamsDir = dyn_cast_or_null<OMPExecutableDirective>( ignoreCompoundStmts(CS.getCapturedStmt()))) { - if (auto *TLE = TeamsDir->getSingleClause<OMPThreadLimitClause>()) { - CGOpenMPInnerExprInfo CGInfo(CGF, CS); - CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); - llvm::Value *ThreadLimit = CGF.EmitScalarExpr(TLE->getThreadLimit()); - return CGF.Builder.CreateIntCast(ThreadLimit, CGF.Int32Ty, - /*IsSigned=*/true); - } + if (isOpenMPTeamsDirective(TeamsDir->getDirectiveKind())) { + if (auto *TLE = TeamsDir->getSingleClause<OMPThreadLimitClause>()) { + CGOpenMPInnerExprInfo CGInfo(CGF, CS); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); + llvm::Value *ThreadLimit = CGF.EmitScalarExpr(TLE->getThreadLimit()); + return CGF.Builder.CreateIntCast(ThreadLimit, CGF.Int32Ty, + /*IsSigned=*/true); + } - // If we have an enclosed teams directive but no thread_limit clause we use - // the default value 0. - return CGF.Builder.getInt32(0); + // If we have an enclosed teams directive but no thread_limit clause we + // use the default value 0. + return CGF.Builder.getInt32(0); + } } // No teams associated with the directive. @@ -5949,22 +6087,23 @@ public: /// \brief Delete the element from the device environment, ignoring the /// current reference count associated with the element. OMP_MAP_DELETE = 0x08, - /// \brief The element being mapped is a pointer, therefore the pointee - /// should be mapped as well. - OMP_MAP_IS_PTR = 0x10, - /// \brief This flags signals that an argument is the first one relating to - /// a map/private clause expression. For some cases a single - /// map/privatization results in multiple arguments passed to the runtime - /// library. - OMP_MAP_FIRST_REF = 0x20, + /// \brief The element being mapped is a pointer-pointee pair; both the + /// pointer and the pointee should be mapped. + OMP_MAP_PTR_AND_OBJ = 0x10, + /// \brief This flags signals that the base address of an entry should be + /// passed to the target kernel as an argument. + OMP_MAP_TARGET_PARAM = 0x20, /// \brief Signal that the runtime library has to return the device pointer - /// in the current position for the data being mapped. - OMP_MAP_RETURN_PTR = 0x40, + /// in the current position for the data being mapped. Used when we have the + /// use_device_ptr clause. + OMP_MAP_RETURN_PARAM = 0x40, /// \brief This flag signals that the reference being passed is a pointer to /// private data. - OMP_MAP_PRIVATE_PTR = 0x80, + OMP_MAP_PRIVATE = 0x80, /// \brief Pass the element to the device by value. - OMP_MAP_PRIVATE_VAL = 0x100, + OMP_MAP_LITERAL = 0x100, + /// Implicit map + OMP_MAP_IMPLICIT = 0x200, }; /// Class that associates information with a base pointer to be passed to the @@ -5986,7 +6125,7 @@ public: typedef SmallVector<BasePointerInfo, 16> MapBaseValuesArrayTy; typedef SmallVector<llvm::Value *, 16> MapValuesArrayTy; - typedef SmallVector<unsigned, 16> MapFlagsArrayTy; + typedef SmallVector<uint64_t, 16> MapFlagsArrayTy; private: /// \brief Directive from where the map clauses were extracted. @@ -5997,6 +6136,8 @@ private: /// \brief Set of all first private variables in the current directive. llvm::SmallPtrSet<const VarDecl *, 8> FirstPrivateDecls; + /// Set of all reduction variables in the current directive. + llvm::SmallPtrSet<const VarDecl *, 8> ReductionDecls; /// Map between device pointer declarations and their expression components. /// The key value for declarations in 'this' is null. @@ -6051,10 +6192,10 @@ private: /// a flag marking the map as a pointer if requested. Add a flag marking the /// map as the first one of a series of maps that relate to the same map /// expression. - unsigned getMapTypeBits(OpenMPMapClauseKind MapType, + uint64_t getMapTypeBits(OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapTypeModifier, bool AddPtrFlag, - bool AddIsFirstFlag) const { - unsigned Bits = 0u; + bool AddIsTargetParamFlag) const { + uint64_t Bits = 0u; switch (MapType) { case OMPC_MAP_alloc: case OMPC_MAP_release: @@ -6080,9 +6221,9 @@ private: break; } if (AddPtrFlag) - Bits |= OMP_MAP_IS_PTR; - if (AddIsFirstFlag) - Bits |= OMP_MAP_FIRST_REF; + Bits |= OMP_MAP_PTR_AND_OBJ; + if (AddIsTargetParamFlag) + Bits |= OMP_MAP_TARGET_PARAM; if (MapTypeModifier == OMPC_MAP_always) Bits |= OMP_MAP_ALWAYS; return Bits; @@ -6135,7 +6276,7 @@ private: OMPClauseMappableExprCommon::MappableExprComponentListRef Components, MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers, MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types, - bool IsFirstComponentList) const { + bool IsFirstComponentList, bool IsImplicit) const { // The following summarizes what has to be generated for each map and the // types bellow. The generated information is expressed in this order: @@ -6189,28 +6330,28 @@ private: // // map(s.p[:22], s.a s.b) // &s, &(s.p), sizeof(double*), noflags - // &(s.p), &(s.p[0]), 22*sizeof(double), ptr_flag + extra_flag + // &(s.p), &(s.p[0]), 22*sizeof(double), ptr_flag // // map(s.ps) // &s, &(s.ps), sizeof(S2*), noflags // // map(s.ps->s.i) // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->s.i), sizeof(int), ptr_flag + extra_flag + // &(s.ps), &(s.ps->s.i), sizeof(int), ptr_flag // // map(s.ps->ps) // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + extra_flag + // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag // // map(s.ps->ps->ps) // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + extra_flag - // &(s.ps->ps), &(s.ps->ps->ps), sizeof(S2*), ptr_flag + extra_flag + // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + // &(s.ps->ps), &(s.ps->ps->ps), sizeof(S2*), ptr_flag // // map(s.ps->ps->s.f[:22]) // &s, &(s.ps), sizeof(S2*), noflags - // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + extra_flag - // &(s.ps->ps), &(s.ps->ps->s.f[0]), 22*sizeof(float), ptr_flag + extra_flag + // &(s.ps), &(s.ps->ps), sizeof(S2*), ptr_flag + // &(s.ps->ps), &(s.ps->ps->s.f[0]), 22*sizeof(float), ptr_flag // // map(ps) // &ps, &ps, sizeof(S2*), noflags @@ -6226,29 +6367,28 @@ private: // // map(ps->p[:22]) // ps, &(ps->p), sizeof(double*), noflags - // &(ps->p), &(ps->p[0]), 22*sizeof(double), ptr_flag + extra_flag + // &(ps->p), &(ps->p[0]), 22*sizeof(double), ptr_flag // // map(ps->ps) // ps, &(ps->ps), sizeof(S2*), noflags // // map(ps->ps->s.i) // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->s.i), sizeof(int), ptr_flag + extra_flag + // &(ps->ps), &(ps->ps->s.i), sizeof(int), ptr_flag // // map(ps->ps->ps) // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + extra_flag + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag // // map(ps->ps->ps->ps) // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + extra_flag - // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(S2*), ptr_flag + extra_flag + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(S2*), ptr_flag // // map(ps->ps->ps->s.f[:22]) // ps, &(ps->ps), sizeof(S2*), noflags - // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + extra_flag - // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), 22*sizeof(float), ptr_flag + - // extra_flag + // &(ps->ps), &(ps->ps->ps), sizeof(S2*), ptr_flag + // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), 22*sizeof(float), ptr_flag // Track if the map information being generated is the first for a capture. bool IsCaptureFirstInfo = IsFirstComponentList; @@ -6270,8 +6410,7 @@ private: } else { // The base is the reference to the variable. // BP = &Var. - BP = CGF.EmitLValue(cast<DeclRefExpr>(I->getAssociatedExpression())) - .getPointer(); + BP = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer(); // If the variable is a pointer and is being dereferenced (i.e. is not // the last component), the base has to be the pointer itself, not its @@ -6290,6 +6429,7 @@ private: } } + uint64_t DefaultFlags = IsImplicit ? OMP_MAP_IMPLICIT : 0; for (; I != CE; ++I) { auto Next = std::next(I); @@ -6324,7 +6464,8 @@ private: isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) && "Unexpected expression"); - auto *LB = CGF.EmitLValue(I->getAssociatedExpression()).getPointer(); + llvm::Value *LB = + CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer(); auto *Size = getExprTypeSize(I->getAssociatedExpression()); // If we have a member expression and the current component is a @@ -6339,9 +6480,11 @@ private: BasePointers.push_back(BP); Pointers.push_back(RefAddr); Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy)); - Types.push_back(getMapTypeBits( - /*MapType*/ OMPC_MAP_alloc, /*MapTypeModifier=*/OMPC_MAP_unknown, - !IsExpressionFirstInfo, IsCaptureFirstInfo)); + Types.push_back(DefaultFlags | + getMapTypeBits( + /*MapType*/ OMPC_MAP_alloc, + /*MapTypeModifier=*/OMPC_MAP_unknown, + !IsExpressionFirstInfo, IsCaptureFirstInfo)); IsExpressionFirstInfo = false; IsCaptureFirstInfo = false; // The reference will be the next base address. @@ -6356,9 +6499,9 @@ private: // same expression except for the first one. We also need to signal // this map is the first one that relates with the current capture // (there is a set of entries for each capture). - Types.push_back(getMapTypeBits(MapType, MapTypeModifier, - !IsExpressionFirstInfo, - IsCaptureFirstInfo)); + Types.push_back(DefaultFlags | getMapTypeBits(MapType, MapTypeModifier, + !IsExpressionFirstInfo, + IsCaptureFirstInfo)); // If we have a final array section, we are done with this expression. if (IsFinalArraySection) @@ -6370,7 +6513,6 @@ private: IsExpressionFirstInfo = false; IsCaptureFirstInfo = false; - continue; } } } @@ -6386,8 +6528,14 @@ private: // 'private ptr' and 'map to' flag. Return the right flags if the captured // declaration is known as first-private in this handler. if (FirstPrivateDecls.count(Cap.getCapturedVar())) - return MappableExprsHandler::OMP_MAP_PRIVATE_PTR | + return MappableExprsHandler::OMP_MAP_PRIVATE | MappableExprsHandler::OMP_MAP_TO; + // Reduction variable will use only the 'private ptr' and 'map to_from' + // flag. + if (ReductionDecls.count(Cap.getCapturedVar())) { + return MappableExprsHandler::OMP_MAP_TO | + MappableExprsHandler::OMP_MAP_FROM; + } // We didn't modify anything. return CurrentModifiers; @@ -6401,6 +6549,12 @@ public: for (const auto *D : C->varlists()) FirstPrivateDecls.insert( cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl()); + for (const auto *C : Dir.getClausesOfKind<OMPReductionClause>()) { + for (const auto *D : C->varlists()) { + ReductionDecls.insert( + cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl()); + } + } // Extract device pointer clause information. for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>()) for (auto L : C->component_lists()) @@ -6432,20 +6586,19 @@ public: RPK_MemberReference, }; OMPClauseMappableExprCommon::MappableExprComponentListRef Components; - OpenMPMapClauseKind MapType; - OpenMPMapClauseKind MapTypeModifier; - ReturnPointerKind ReturnDevicePointer; + OpenMPMapClauseKind MapType = OMPC_MAP_unknown; + OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; + ReturnPointerKind ReturnDevicePointer = RPK_None; + bool IsImplicit = false; - MapInfo() - : MapType(OMPC_MAP_unknown), MapTypeModifier(OMPC_MAP_unknown), - ReturnDevicePointer(RPK_None) {} + MapInfo() = default; MapInfo( OMPClauseMappableExprCommon::MappableExprComponentListRef Components, OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapTypeModifier, - ReturnPointerKind ReturnDevicePointer) + ReturnPointerKind ReturnDevicePointer, bool IsImplicit) : Components(Components), MapType(MapType), MapTypeModifier(MapTypeModifier), - ReturnDevicePointer(ReturnDevicePointer) {} + ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit) {} }; // We have to process the component lists that relate with the same @@ -6459,25 +6612,29 @@ public: const ValueDecl *D, OMPClauseMappableExprCommon::MappableExprComponentListRef L, OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapModifier, - MapInfo::ReturnPointerKind ReturnDevicePointer) { + MapInfo::ReturnPointerKind ReturnDevicePointer, bool IsImplicit) { const ValueDecl *VD = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr; - Info[VD].push_back({L, MapType, MapModifier, ReturnDevicePointer}); + Info[VD].emplace_back(L, MapType, MapModifier, ReturnDevicePointer, + IsImplicit); }; // FIXME: MSVC 2013 seems to require this-> to find member CurDir. for (auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) - for (auto L : C->component_lists()) + for (auto L : C->component_lists()) { InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifier(), - MapInfo::RPK_None); + MapInfo::RPK_None, C->isImplicit()); + } for (auto *C : this->CurDir.getClausesOfKind<OMPToClause>()) - for (auto L : C->component_lists()) + for (auto L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_to, OMPC_MAP_unknown, - MapInfo::RPK_None); + MapInfo::RPK_None, C->isImplicit()); + } for (auto *C : this->CurDir.getClausesOfKind<OMPFromClause>()) - for (auto L : C->component_lists()) + for (auto L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_from, OMPC_MAP_unknown, - MapInfo::RPK_None); + MapInfo::RPK_None, C->isImplicit()); + } // Look at the use_device_ptr clause information and mark the existing map // entries as such. If there is no map information for an entry in the @@ -6524,7 +6681,7 @@ public: BasePointers.push_back({Ptr, VD}); Pointers.push_back(Ptr); Sizes.push_back(llvm::Constant::getNullValue(this->CGF.SizeTy)); - Types.push_back(OMP_MAP_RETURN_PTR | OMP_MAP_FIRST_REF); + Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM); } for (auto &M : Info) { @@ -6538,9 +6695,9 @@ public: // Remember the current base pointer index. unsigned CurrentBasePointersIdx = BasePointers.size(); // FIXME: MSVC 2013 seems to require this-> to find the member method. - this->generateInfoForComponentList(L.MapType, L.MapTypeModifier, - L.Components, BasePointers, Pointers, - Sizes, Types, IsFirstComponentList); + this->generateInfoForComponentList( + L.MapType, L.MapTypeModifier, L.Components, BasePointers, Pointers, + Sizes, Types, IsFirstComponentList, L.IsImplicit); // If this entry relates with a device pointer, set the relevant // declaration and add the 'return pointer' flag. @@ -6562,7 +6719,7 @@ public: "No relevant declaration related with device pointer??"); BasePointers[CurrentBasePointersIdx].setDevicePtrDecl(RelevantVD); - Types[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PTR; + Types[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PARAM; } IsFirstComponentList = false; } @@ -6604,7 +6761,8 @@ public: for (auto L : It->second) { generateInfoForComponentList( /*MapType=*/OMPC_MAP_to, /*MapTypeModifier=*/OMPC_MAP_unknown, L, - BasePointers, Pointers, Sizes, Types, IsFirstComponentList); + BasePointers, Pointers, Sizes, Types, IsFirstComponentList, + /*IsImplicit=*/false); IsFirstComponentList = false; } return; @@ -6613,7 +6771,7 @@ public: BasePointers.push_back({Arg, VD}); Pointers.push_back(Arg); Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy)); - Types.push_back(OMP_MAP_PRIVATE_VAL | OMP_MAP_FIRST_REF); + Types.push_back(OMP_MAP_LITERAL | OMP_MAP_TARGET_PARAM); return; } @@ -6624,9 +6782,9 @@ public: "We got information for the wrong declaration??"); assert(!L.second.empty() && "Not expecting declaration with no component lists."); - generateInfoForComponentList(C->getMapType(), C->getMapTypeModifier(), - L.second, BasePointers, Pointers, Sizes, - Types, IsFirstComponentList); + generateInfoForComponentList( + C->getMapType(), C->getMapTypeModifier(), L.second, BasePointers, + Pointers, Sizes, Types, IsFirstComponentList, C->isImplicit()); IsFirstComponentList = false; } @@ -6656,7 +6814,7 @@ public: if (!RI.getType()->isAnyPointerType()) { // We have to signal to the runtime captures passed by value that are // not pointers. - CurMapTypes.push_back(OMP_MAP_PRIVATE_VAL); + CurMapTypes.push_back(OMP_MAP_LITERAL); CurSizes.push_back(CGF.getTypeSize(RI.getType())); } else { // Pointers are implicitly mapped with a zero size and no flags @@ -6676,19 +6834,12 @@ public: // The default map type for a scalar/complex type is 'to' because by // default the value doesn't have to be retrieved. For an aggregate // type, the default is 'tofrom'. - CurMapTypes.push_back(ElementType->isAggregateType() - ? (OMP_MAP_TO | OMP_MAP_FROM) - : OMP_MAP_TO); - - // If we have a capture by reference we may need to add the private - // pointer flag if the base declaration shows in some first-private - // clause. - CurMapTypes.back() = - adjustMapModifiersForPrivateClauses(CI, CurMapTypes.back()); + CurMapTypes.emplace_back(adjustMapModifiersForPrivateClauses( + CI, ElementType->isAggregateType() ? (OMP_MAP_TO | OMP_MAP_FROM) + : OMP_MAP_TO)); } - // Every default map produces a single argument, so, it is always the - // first one. - CurMapTypes.back() |= OMP_MAP_FIRST_REF; + // Every default map produces a single argument which is a target parameter. + CurMapTypes.back() |= OMP_MAP_TARGET_PARAM; } }; @@ -6831,7 +6982,7 @@ static void emitOffloadingArraysArgument( llvm::ArrayType::get(CGM.SizeTy, Info.NumberOfPtrs), Info.SizesArray, /*Idx0=*/0, /*Idx1=*/0); MapTypesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32( - llvm::ArrayType::get(CGM.Int32Ty, Info.NumberOfPtrs), + llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs), Info.MapTypesArray, /*Idx0=*/0, /*Idx1=*/0); @@ -6840,7 +6991,7 @@ static void emitOffloadingArraysArgument( PointersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy); SizesArrayArg = llvm::ConstantPointerNull::get(CGM.SizeTy->getPointerTo()); MapTypesArrayArg = - llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo()); + llvm::ConstantPointerNull::get(CGM.Int64Ty->getPointerTo()); } } @@ -6855,8 +7006,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, assert(OutlinedFn && "Invalid outlined function!"); - auto &Ctx = CGF.getContext(); - // Fill up the arrays with all the captured variables. MappableExprsHandler::MapValuesArrayTy KernelArgs; MappableExprsHandler::MapBaseValuesArrayTy BasePointers; @@ -6878,9 +7027,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, for (CapturedStmt::const_capture_iterator CI = CS.capture_begin(), CE = CS.capture_end(); CI != CE; ++CI, ++RI, ++CV) { - StringRef Name; - QualType Ty; - CurBasePointers.clear(); CurPointers.clear(); CurSizes.clear(); @@ -6893,8 +7039,8 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, CurPointers.push_back(*CV); CurSizes.push_back(CGF.getTypeSize(RI->getType())); // Copy to the device as an argument. No need to retrieve it. - CurMapTypes.push_back(MappableExprsHandler::OMP_MAP_PRIVATE_VAL | - MappableExprsHandler::OMP_MAP_FIRST_REF); + CurMapTypes.push_back(MappableExprsHandler::OMP_MAP_LITERAL | + MappableExprsHandler::OMP_MAP_TARGET_PARAM); } else { // If we have any information in the map clause, we use it, otherwise we // just do a default mapping. @@ -6921,19 +7067,10 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, MapTypes.append(CurMapTypes.begin(), CurMapTypes.end()); } - // Keep track on whether the host function has to be executed. - auto OffloadErrorQType = - Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true); - auto OffloadError = CGF.MakeAddrLValue( - CGF.CreateMemTemp(OffloadErrorQType, ".run_host_version"), - OffloadErrorQType); - CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.Int32Ty), - OffloadError); - // Fill up the pointer arrays and transfer execution to the device. - auto &&ThenGen = [&BasePointers, &Pointers, &Sizes, &MapTypes, Device, - OutlinedFnID, OffloadError, - &D](CodeGenFunction &CGF, PrePostActionTy &) { + auto &&ThenGen = [this, &BasePointers, &Pointers, &Sizes, &MapTypes, Device, + OutlinedFn, OutlinedFnID, &D, + &KernelArgs](CodeGenFunction &CGF, PrePostActionTy &) { auto &RT = CGF.CGM.getOpenMPRuntime(); // Emit the offloading arrays. TargetDataInfo Info; @@ -6956,11 +7093,12 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, // Emit device ID if any. llvm::Value *DeviceID; - if (Device) + if (Device) { DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device), - CGF.Int32Ty, /*isSigned=*/true); - else - DeviceID = CGF.Builder.getInt32(OMP_DEVICEID_UNDEF); + CGF.Int64Ty, /*isSigned=*/true); + } else { + DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF); + } // Emit the number of elements in the offloading arrays. llvm::Value *PointerNum = CGF.Builder.getInt32(BasePointers.size()); @@ -6971,6 +7109,7 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, auto *NumTeams = emitNumTeamsForTargetDirective(RT, CGF, D); auto *NumThreads = emitNumThreadsForTargetDirective(RT, CGF, D); + bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>(); // The target region is an outlined function launched by the runtime // via calls __tgt_target() or __tgt_target_teams(). // @@ -7013,24 +7152,41 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, Info.MapTypesArray, NumTeams, NumThreads}; Return = CGF.EmitRuntimeCall( - RT.createRuntimeFunction(OMPRTL__tgt_target_teams), OffloadingArgs); + RT.createRuntimeFunction(HasNowait ? OMPRTL__tgt_target_teams_nowait + : OMPRTL__tgt_target_teams), + OffloadingArgs); } else { llvm::Value *OffloadingArgs[] = { DeviceID, OutlinedFnID, PointerNum, Info.BasePointersArray, Info.PointersArray, Info.SizesArray, Info.MapTypesArray}; - Return = CGF.EmitRuntimeCall(RT.createRuntimeFunction(OMPRTL__tgt_target), - OffloadingArgs); + Return = CGF.EmitRuntimeCall( + RT.createRuntimeFunction(HasNowait ? OMPRTL__tgt_target_nowait + : OMPRTL__tgt_target), + OffloadingArgs); } - CGF.EmitStoreOfScalar(Return, OffloadError); + // Check the error code and execute the host version if required. + llvm::BasicBlock *OffloadFailedBlock = + CGF.createBasicBlock("omp_offload.failed"); + llvm::BasicBlock *OffloadContBlock = + CGF.createBasicBlock("omp_offload.cont"); + llvm::Value *Failed = CGF.Builder.CreateIsNotNull(Return); + CGF.Builder.CreateCondBr(Failed, OffloadFailedBlock, OffloadContBlock); + + CGF.EmitBlock(OffloadFailedBlock); + emitOutlinedFunctionCall(CGF, D.getLocStart(), OutlinedFn, KernelArgs); + CGF.EmitBranch(OffloadContBlock); + + CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true); }; // Notify that the host version must be executed. - auto &&ElseGen = [OffloadError](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.Int32Ty, /*V=*/-1u), - OffloadError); + auto &&ElseGen = [this, &D, OutlinedFn, &KernelArgs](CodeGenFunction &CGF, + PrePostActionTy &) { + emitOutlinedFunctionCall(CGF, D.getLocStart(), OutlinedFn, + KernelArgs); }; // If we have a target function ID it means that we need to support @@ -7048,19 +7204,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF, RegionCodeGenTy ElseRCG(ElseGen); ElseRCG(CGF); } - - // Check the error code and execute the host version if required. - auto OffloadFailedBlock = CGF.createBasicBlock("omp_offload.failed"); - auto OffloadContBlock = CGF.createBasicBlock("omp_offload.cont"); - auto OffloadErrorVal = CGF.EmitLoadOfScalar(OffloadError, SourceLocation()); - auto Failed = CGF.Builder.CreateIsNotNull(OffloadErrorVal); - CGF.Builder.CreateCondBr(Failed, OffloadFailedBlock, OffloadContBlock); - - CGF.EmitBlock(OffloadFailedBlock); - CGF.Builder.CreateCall(OutlinedFn, KernelArgs); - CGF.EmitBranch(OffloadContBlock); - - CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true); } void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, @@ -7101,6 +7244,26 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, CodeGenFunction::EmitOMPTargetTeamsDeviceFunction( CGM, ParentName, cast<OMPTargetTeamsDirective>(*S)); break; + case Stmt::OMPTargetTeamsDistributeDirectiveClass: + CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction( + CGM, ParentName, cast<OMPTargetTeamsDistributeDirective>(*S)); + break; + case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: + CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction( + CGM, ParentName, cast<OMPTargetTeamsDistributeSimdDirective>(*S)); + break; + case Stmt::OMPTargetParallelForDirectiveClass: + CodeGenFunction::EmitOMPTargetParallelForDeviceFunction( + CGM, ParentName, cast<OMPTargetParallelForDirective>(*S)); + break; + case Stmt::OMPTargetParallelForSimdDirectiveClass: + CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction( + CGM, ParentName, cast<OMPTargetParallelForSimdDirective>(*S)); + break; + case Stmt::OMPTargetSimdDirectiveClass: + CodeGenFunction::EmitOMPTargetSimdDeviceFunction( + CGM, ParentName, cast<OMPTargetSimdDirective>(*S)); + break; default: llvm_unreachable("Unknown target directive for OpenMP device codegen."); } @@ -7278,11 +7441,12 @@ void CGOpenMPRuntime::emitTargetDataCalls( // Emit device ID if any. llvm::Value *DeviceID = nullptr; - if (Device) + if (Device) { DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device), - CGF.Int32Ty, /*isSigned=*/true); - else - DeviceID = CGF.Builder.getInt32(OMP_DEVICEID_UNDEF); + CGF.Int64Ty, /*isSigned=*/true); + } else { + DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF); + } // Emit the number of elements in the offloading arrays. auto *PointerNum = CGF.Builder.getInt32(Info.NumberOfPtrs); @@ -7313,11 +7477,12 @@ void CGOpenMPRuntime::emitTargetDataCalls( // Emit device ID if any. llvm::Value *DeviceID = nullptr; - if (Device) + if (Device) { DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device), - CGF.Int32Ty, /*isSigned=*/true); - else - DeviceID = CGF.Builder.getInt32(OMP_DEVICEID_UNDEF); + CGF.Int64Ty, /*isSigned=*/true); + } else { + DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF); + } // Emit the number of elements in the offloading arrays. auto *PointerNum = CGF.Builder.getInt32(Info.NumberOfPtrs); @@ -7399,11 +7564,12 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( // Emit device ID if any. llvm::Value *DeviceID = nullptr; - if (Device) + if (Device) { DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device), - CGF.Int32Ty, /*isSigned=*/true); - else - DeviceID = CGF.Builder.getInt32(OMP_DEVICEID_UNDEF); + CGF.Int64Ty, /*isSigned=*/true); + } else { + DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF); + } // Emit the number of elements in the offloading arrays. auto *PointerNum = CGF.Builder.getInt32(BasePointers.size()); @@ -7415,19 +7581,23 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( auto &RT = CGF.CGM.getOpenMPRuntime(); // Select the right runtime function call for each expected standalone // directive. + const bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>(); OpenMPRTLFunction RTLFn; switch (D.getDirectiveKind()) { default: llvm_unreachable("Unexpected standalone target data directive."); break; case OMPD_target_enter_data: - RTLFn = OMPRTL__tgt_target_data_begin; + RTLFn = HasNowait ? OMPRTL__tgt_target_data_begin_nowait + : OMPRTL__tgt_target_data_begin; break; case OMPD_target_exit_data: - RTLFn = OMPRTL__tgt_target_data_end; + RTLFn = HasNowait ? OMPRTL__tgt_target_data_end_nowait + : OMPRTL__tgt_target_data_end; break; case OMPD_target_update: - RTLFn = OMPRTL__tgt_target_data_update; + RTLFn = HasNowait ? OMPRTL__tgt_target_data_update_nowait + : OMPRTL__tgt_target_data_update; break; } CGF.EmitRuntimeCall(RT.createRuntimeFunction(RTLFn), OffloadingArgs); @@ -7777,3 +7947,29 @@ void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF, CGF.EmitRuntimeCall(RTLFn, Args); } +void CGOpenMPRuntime::emitCall(CodeGenFunction &CGF, llvm::Value *Callee, + ArrayRef<llvm::Value *> Args, + SourceLocation Loc) const { + auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc); + + if (auto *Fn = dyn_cast<llvm::Function>(Callee)) { + if (Fn->doesNotThrow()) { + CGF.EmitNounwindRuntimeCall(Fn, Args); + return; + } + } + CGF.EmitRuntimeCall(Callee, Args); +} + +void CGOpenMPRuntime::emitOutlinedFunctionCall( + CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn, + ArrayRef<llvm::Value *> Args) const { + assert(Loc.isValid() && "Outlined function call location must be valid."); + emitCall(CGF, OutlinedFn, Args, Loc); +} + +Address CGOpenMPRuntime::getParameterAddress(CodeGenFunction &CGF, + const VarDecl *NativeParam, + const VarDecl *TargetParam) const { + return CGF.GetAddrOfLocalVar(NativeParam); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h index 185c01d5e5402..94a143841373a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -250,6 +250,11 @@ protected: // virtual StringRef getOutlinedHelperName() const { return ".omp_outlined."; } + /// Emits \p Callee function call with arguments \p Args with location \p Loc. + void emitCall(CodeGenFunction &CGF, llvm::Value *Callee, + ArrayRef<llvm::Value *> Args = llvm::None, + SourceLocation Loc = SourceLocation()) const; + private: /// \brief Default const ident_t object used for initialization of all other /// ident_t objects. @@ -805,6 +810,35 @@ public: unsigned IVSize, bool IVSigned, bool Ordered, const DispatchRTInput &DispatchValues); + /// Struct with the values to be passed to the static runtime function + struct StaticRTInput { + /// Size of the iteration variable in bits. + unsigned IVSize = 0; + /// Sign of the iteration variable. + bool IVSigned = false; + /// true if loop is ordered, false otherwise. + bool Ordered = false; + /// Address of the output variable in which the flag of the last iteration + /// is returned. + Address IL = Address::invalid(); + /// Address of the output variable in which the lower iteration number is + /// returned. + Address LB = Address::invalid(); + /// Address of the output variable in which the upper iteration number is + /// returned. + Address UB = Address::invalid(); + /// Address of the output variable in which the stride value is returned + /// necessary to generated the static_chunked scheduled loop. + Address ST = Address::invalid(); + /// Value of the chunk for the static_chunked scheduled loop. For the + /// default (nullptr) value, the chunk 1 will be used. + llvm::Value *Chunk = nullptr; + StaticRTInput(unsigned IVSize, bool IVSigned, bool Ordered, Address IL, + Address LB, Address UB, Address ST, + llvm::Value *Chunk = nullptr) + : IVSize(IVSize), IVSigned(IVSigned), Ordered(Ordered), IL(IL), LB(LB), + UB(UB), ST(ST), Chunk(Chunk) {} + }; /// \brief Call the appropriate runtime routine to initialize it before start /// of loop. /// @@ -812,55 +846,29 @@ public: /// specify a ordered clause on the loop construct. /// Depending on the loop schedule, it is necessary to call some runtime /// routine before start of the OpenMP loop to get the loop upper / lower - /// bounds \a LB and \a UB and stride \a ST. + /// bounds LB and UB and stride ST. /// /// \param CGF Reference to current CodeGenFunction. /// \param Loc Clang source location. + /// \param DKind Kind of the directive. /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause. - /// \param IVSize Size of the iteration variable in bits. - /// \param IVSigned Sign of the iteration variable. - /// \param Ordered true if loop is ordered, false otherwise. - /// \param IL Address of the output variable in which the flag of the - /// last iteration is returned. - /// \param LB Address of the output variable in which the lower iteration - /// number is returned. - /// \param UB Address of the output variable in which the upper iteration - /// number is returned. - /// \param ST Address of the output variable in which the stride value is - /// returned necessary to generated the static_chunked scheduled loop. - /// \param Chunk Value of the chunk for the static_chunked scheduled loop. - /// For the default (nullptr) value, the chunk 1 will be used. + /// \param Values Input arguments for the construct. /// virtual void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind DKind, const OpenMPScheduleTy &ScheduleKind, - unsigned IVSize, bool IVSigned, bool Ordered, - Address IL, Address LB, Address UB, Address ST, - llvm::Value *Chunk = nullptr); + const StaticRTInput &Values); /// /// \param CGF Reference to current CodeGenFunction. /// \param Loc Clang source location. /// \param SchedKind Schedule kind, specified by the 'dist_schedule' clause. - /// \param IVSize Size of the iteration variable in bits. - /// \param IVSigned Sign of the iteration variable. - /// \param Ordered true if loop is ordered, false otherwise. - /// \param IL Address of the output variable in which the flag of the - /// last iteration is returned. - /// \param LB Address of the output variable in which the lower iteration - /// number is returned. - /// \param UB Address of the output variable in which the upper iteration - /// number is returned. - /// \param ST Address of the output variable in which the stride value is - /// returned necessary to generated the static_chunked scheduled loop. - /// \param Chunk Value of the chunk for the static_chunked scheduled loop. - /// For the default (nullptr) value, the chunk 1 will be used. + /// \param Values Input arguments for the construct. /// - virtual void emitDistributeStaticInit(CodeGenFunction &CGF, SourceLocation Loc, + virtual void emitDistributeStaticInit(CodeGenFunction &CGF, + SourceLocation Loc, OpenMPDistScheduleClauseKind SchedKind, - unsigned IVSize, bool IVSigned, - bool Ordered, Address IL, Address LB, - Address UB, Address ST, - llvm::Value *Chunk = nullptr); + const StaticRTInput &Values); /// \brief Call the appropriate runtime routine to notify that we finished /// iteration of the ordered loop with the dynamic scheduling. @@ -879,8 +887,10 @@ public: /// /// \param CGF Reference to current CodeGenFunction. /// \param Loc Clang source location. + /// \param DKind Kind of the directive for which the static finish is emitted. /// - virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc); + virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc, + OpenMPDirectiveKind DKind); /// Call __kmpc_dispatch_next( /// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter, @@ -1328,6 +1338,30 @@ public: /// \param C 'depend' clause with 'sink|source' dependency kind. virtual void emitDoacrossOrdered(CodeGenFunction &CGF, const OMPDependClause *C); + + /// Translates the native parameter of outlined function if this is required + /// for target. + /// \param FD Field decl from captured record for the paramater. + /// \param NativeParam Parameter itself. + virtual const VarDecl *translateParameter(const FieldDecl *FD, + const VarDecl *NativeParam) const { + return NativeParam; + } + + /// Gets the address of the native argument basing on the address of the + /// target-specific parameter. + /// \param NativeParam Parameter itself. + /// \param TargetParam Corresponding target-specific parameter. + virtual Address getParameterAddress(CodeGenFunction &CGF, + const VarDecl *NativeParam, + const VarDecl *TargetParam) const; + + /// Emits call of the outlined function with the provided arguments, + /// translating these arguments to correct target-specific arguments. + virtual void + emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc, + llvm::Value *OutlinedFn, + ArrayRef<llvm::Value *> Args = llvm::None) const; }; } // namespace CodeGen diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index 3ced05d08a47c..b5fc8d308067e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -22,19 +22,21 @@ using namespace CodeGen; namespace { enum OpenMPRTLFunctionNVPTX { - /// \brief Call to void __kmpc_kernel_init(kmp_int32 thread_limit); + /// \brief Call to void __kmpc_kernel_init(kmp_int32 thread_limit, + /// int16_t RequiresOMPRuntime); OMPRTL_NVPTX__kmpc_kernel_init, - /// \brief Call to void __kmpc_kernel_deinit(); + /// \brief Call to void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized); OMPRTL_NVPTX__kmpc_kernel_deinit, /// \brief Call to void __kmpc_spmd_kernel_init(kmp_int32 thread_limit, - /// short RequiresOMPRuntime, short RequiresDataSharing); + /// int16_t RequiresOMPRuntime, int16_t RequiresDataSharing); OMPRTL_NVPTX__kmpc_spmd_kernel_init, /// \brief Call to void __kmpc_spmd_kernel_deinit(); OMPRTL_NVPTX__kmpc_spmd_kernel_deinit, /// \brief Call to void __kmpc_kernel_prepare_parallel(void - /// *outlined_function); + /// *outlined_function, void ***args, kmp_int32 nArgs); OMPRTL_NVPTX__kmpc_kernel_prepare_parallel, - /// \brief Call to bool __kmpc_kernel_parallel(void **outlined_function); + /// \brief Call to bool __kmpc_kernel_parallel(void **outlined_function, void + /// ***args); OMPRTL_NVPTX__kmpc_kernel_parallel, /// \brief Call to void __kmpc_kernel_end_parallel(); OMPRTL_NVPTX__kmpc_kernel_end_parallel, @@ -150,20 +152,18 @@ enum NamedBarrier : unsigned { /// Get the GPU warp size. static llvm::Value *getNVPTXWarpSize(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - return Bld.CreateCall( + return CGF.EmitRuntimeCall( llvm::Intrinsic::getDeclaration( &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_warpsize), - llvm::None, "nvptx_warp_size"); + "nvptx_warp_size"); } /// Get the id of the current thread on the GPU. static llvm::Value *getNVPTXThreadID(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - return Bld.CreateCall( + return CGF.EmitRuntimeCall( llvm::Intrinsic::getDeclaration( &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x), - llvm::None, "nvptx_tid"); + "nvptx_tid"); } /// Get the id of the warp in the block. @@ -185,17 +185,15 @@ static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) { /// Get the maximum number of threads in a block of the GPU. static llvm::Value *getNVPTXNumThreads(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - return Bld.CreateCall( + return CGF.EmitRuntimeCall( llvm::Intrinsic::getDeclaration( &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x), - llvm::None, "nvptx_num_threads"); + "nvptx_num_threads"); } /// Get barrier to synchronize all threads in a block. static void getNVPTXCTABarrier(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - Bld.CreateCall(llvm::Intrinsic::getDeclaration( + CGF.EmitRuntimeCall(llvm::Intrinsic::getDeclaration( &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_barrier0)); } @@ -205,9 +203,9 @@ static void getNVPTXBarrier(CodeGenFunction &CGF, int ID, llvm::Value *NumThreads) { CGBuilderTy &Bld = CGF.Builder; llvm::Value *Args[] = {Bld.getInt32(ID), NumThreads}; - Bld.CreateCall(llvm::Intrinsic::getDeclaration(&CGF.CGM.getModule(), - llvm::Intrinsic::nvvm_barrier), - Args); + CGF.EmitRuntimeCall(llvm::Intrinsic::getDeclaration( + &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_barrier), + Args); } /// Synchronize all GPU threads in a block. @@ -280,6 +278,8 @@ getExecutionModeForDirective(CodeGenModule &CGM, case OMPD_target_teams: return CGOpenMPRuntimeNVPTX::ExecutionMode::Generic; case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: return CGOpenMPRuntimeNVPTX::ExecutionMode::Spmd; default: llvm_unreachable("Unsupported directive on NVPTX device."); @@ -298,6 +298,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericKernel(const OMPExecutableDirective &D, EntryFunctionState EST; WorkerFunctionState WST(CGM); Work.clear(); + WrapperFunctionsMap.clear(); // Emit target region as a standalone region. class NVPTXPrePostActionTy : public PrePostActionTy { @@ -345,7 +346,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericEntryHeader(CodeGenFunction &CGF, Bld.CreateCondBr(IsWorker, WorkerBB, MasterCheckBB); CGF.EmitBlock(WorkerBB); - CGF.EmitCallOrInvoke(WST.WorkerFn, llvm::None); + emitCall(CGF, WST.WorkerFn); CGF.EmitBranch(EST.ExitBB); CGF.EmitBlock(MasterCheckBB); @@ -356,7 +357,9 @@ void CGOpenMPRuntimeNVPTX::emitGenericEntryHeader(CodeGenFunction &CGF, CGF.EmitBlock(MasterBB); // First action in sequential region: // Initialize the state of the OpenMP runtime library on the GPU. - llvm::Value *Args[] = {getThreadLimit(CGF)}; + // TODO: Optimize runtime initialization and pass in correct value. + llvm::Value *Args[] = {getThreadLimit(CGF), + Bld.getInt16(/*RequiresOMPRuntime=*/1)}; CGF.EmitRuntimeCall( createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_init), Args); } @@ -371,8 +374,10 @@ void CGOpenMPRuntimeNVPTX::emitGenericEntryFooter(CodeGenFunction &CGF, CGF.EmitBlock(TerminateBB); // Signal termination condition. + // TODO: Optimize runtime initialization and pass in correct value. + llvm::Value *Args[] = {CGF.Builder.getInt16(/*IsOMPRuntimeInitialized=*/1)}; CGF.EmitRuntimeCall( - createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_deinit), None); + createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_deinit), Args); // Barrier to terminate worker threads. syncCTAThreads(CGF); // Master thread jumps to exit point. @@ -413,7 +418,6 @@ void CGOpenMPRuntimeNVPTX::emitSpmdKernel(const OMPExecutableDirective &D, CodeGen.setAction(Action); emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry, CodeGen); - return; } void CGOpenMPRuntimeNVPTX::emitSpmdEntryHeader( @@ -471,7 +475,7 @@ static void setPropertyExecutionMode(CodeGenModule &CGM, StringRef Name, } void CGOpenMPRuntimeNVPTX::emitWorkerFunction(WorkerFunctionState &WST) { - auto &Ctx = CGM.getContext(); + ASTContext &Ctx = CGM.getContext(); CodeGenFunction CGF(CGM, /*suppressNewContext=*/true); CGF.disableDebugInfo(); @@ -514,7 +518,10 @@ void CGOpenMPRuntimeNVPTX::emitWorkerLoop(CodeGenFunction &CGF, CGF.InitTempAlloca(ExecStatus, Bld.getInt8(/*C=*/0)); CGF.InitTempAlloca(WorkFn, llvm::Constant::getNullValue(CGF.Int8PtrTy)); - llvm::Value *Args[] = {WorkFn.getPointer()}; + // Set up shared arguments + Address SharedArgs = + CGF.CreateDefaultAlignTempAlloca(CGF.Int8PtrPtrTy, "shared_args"); + llvm::Value *Args[] = {WorkFn.getPointer(), SharedArgs.getPointer()}; llvm::Value *Ret = CGF.EmitRuntimeCall( createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_parallel), Args); Bld.CreateStore(Bld.CreateZExt(Ret, CGF.Int8Ty), ExecStatus); @@ -533,6 +540,9 @@ void CGOpenMPRuntimeNVPTX::emitWorkerLoop(CodeGenFunction &CGF, // Signal start of parallel region. CGF.EmitBlock(ExecuteBB); + // Current context + ASTContext &Ctx = CGF.getContext(); + // Process work items: outlined parallel functions. for (auto *W : Work) { // Try to match this outlined function. @@ -548,14 +558,18 @@ void CGOpenMPRuntimeNVPTX::emitWorkerLoop(CodeGenFunction &CGF, // Execute this outlined function. CGF.EmitBlock(ExecuteFNBB); - // Insert call to work function. - // FIXME: Pass arguments to outlined function from master thread. - auto *Fn = cast<llvm::Function>(W); - Address ZeroAddr = - CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".zero.addr"); - CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C=*/0)); - llvm::Value *FnArgs[] = {ZeroAddr.getPointer(), ZeroAddr.getPointer()}; - CGF.EmitCallOrInvoke(Fn, FnArgs); + // Insert call to work function via shared wrapper. The shared + // wrapper takes exactly three arguments: + // - the parallelism level; + // - the master thread ID; + // - the list of references to shared arguments. + // + // TODO: Assert that the function is a wrapper function.s + Address Capture = CGF.EmitLoadOfPointer(SharedArgs, + Ctx.getPointerType( + Ctx.getPointerType(Ctx.VoidPtrTy)).castAs<PointerType>()); + emitCall(CGF, W, {Bld.getInt16(/*ParallelLevel=*/0), + getMasterThreadID(CGF), Capture.getPointer()}); // Go to end of parallel region. CGF.EmitBranch(TerminateBB); @@ -589,23 +603,25 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) { llvm::Constant *RTLFn = nullptr; switch (static_cast<OpenMPRTLFunctionNVPTX>(Function)) { case OMPRTL_NVPTX__kmpc_kernel_init: { - // Build void __kmpc_kernel_init(kmp_int32 thread_limit); - llvm::Type *TypeParams[] = {CGM.Int32Ty}; + // Build void __kmpc_kernel_init(kmp_int32 thread_limit, int16_t + // RequiresOMPRuntime); + llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_init"); break; } case OMPRTL_NVPTX__kmpc_kernel_deinit: { - // Build void __kmpc_kernel_deinit(); + // Build void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized); + llvm::Type *TypeParams[] = {CGM.Int16Ty}; llvm::FunctionType *FnTy = - llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false); + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_deinit"); break; } case OMPRTL_NVPTX__kmpc_spmd_kernel_init: { // Build void __kmpc_spmd_kernel_init(kmp_int32 thread_limit, - // short RequiresOMPRuntime, short RequiresDataSharing); + // int16_t RequiresOMPRuntime, int16_t RequiresDataSharing); llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty, CGM.Int16Ty}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); @@ -621,16 +637,18 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) { } case OMPRTL_NVPTX__kmpc_kernel_prepare_parallel: { /// Build void __kmpc_kernel_prepare_parallel( - /// void *outlined_function); - llvm::Type *TypeParams[] = {CGM.Int8PtrTy}; + /// void *outlined_function, void ***args, kmp_int32 nArgs); + llvm::Type *TypeParams[] = {CGM.Int8PtrTy, + CGM.Int8PtrPtrTy->getPointerTo(0), CGM.Int32Ty}; llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_prepare_parallel"); break; } case OMPRTL_NVPTX__kmpc_kernel_parallel: { - /// Build bool __kmpc_kernel_parallel(void **outlined_function); - llvm::Type *TypeParams[] = {CGM.Int8PtrPtrTy}; + /// Build bool __kmpc_kernel_parallel(void **outlined_function, void ***args); + llvm::Type *TypeParams[] = {CGM.Int8PtrPtrTy, + CGM.Int8PtrPtrTy->getPointerTo(0)}; llvm::Type *RetTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy); llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, TypeParams, /*isVarArg*/ false); @@ -849,8 +867,17 @@ void CGOpenMPRuntimeNVPTX::emitNumTeamsClause(CodeGenFunction &CGF, llvm::Value *CGOpenMPRuntimeNVPTX::emitParallelOutlinedFunction( const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { - return CGOpenMPRuntime::emitParallelOutlinedFunction(D, ThreadIDVar, - InnermostKind, CodeGen); + + auto *OutlinedFun = cast<llvm::Function>( + CGOpenMPRuntime::emitParallelOutlinedFunction( + D, ThreadIDVar, InnermostKind, CodeGen)); + if (!isInSpmdExecutionMode()) { + llvm::Function *WrapperFun = + createDataSharingWrapper(OutlinedFun, D); + WrapperFunctionsMap[OutlinedFun] = WrapperFun; + } + + return OutlinedFun; } llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction( @@ -883,7 +910,7 @@ void CGOpenMPRuntimeNVPTX::emitTeamsCall(CodeGenFunction &CGF, OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); - CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs); + emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); } void CGOpenMPRuntimeNVPTX::emitParallelCall( @@ -902,15 +929,54 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall( CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn, ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) { llvm::Function *Fn = cast<llvm::Function>(OutlinedFn); + llvm::Function *WFn = WrapperFunctionsMap[Fn]; + assert(WFn && "Wrapper function does not exist!"); + + // Force inline this outlined function at its call site. + Fn->setLinkage(llvm::GlobalValue::InternalLinkage); - auto &&L0ParallelGen = [this, Fn](CodeGenFunction &CGF, PrePostActionTy &) { + auto &&L0ParallelGen = [this, WFn, &CapturedVars](CodeGenFunction &CGF, + PrePostActionTy &) { CGBuilderTy &Bld = CGF.Builder; - // Prepare for parallel region. Indicate the outlined function. - llvm::Value *Args[] = {Bld.CreateBitOrPointerCast(Fn, CGM.Int8PtrTy)}; - CGF.EmitRuntimeCall( - createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_prepare_parallel), - Args); + llvm::Value *ID = Bld.CreateBitOrPointerCast(WFn, CGM.Int8PtrTy); + + if (!CapturedVars.empty()) { + // There's somehting to share, add the attribute + CGF.CurFn->addFnAttr("has-nvptx-shared-depot"); + // Prepare for parallel region. Indicate the outlined function. + Address SharedArgs = + CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, + "shared_args"); + llvm::Value *SharedArgsPtr = SharedArgs.getPointer(); + llvm::Value *Args[] = {ID, SharedArgsPtr, + Bld.getInt32(CapturedVars.size())}; + + CGF.EmitRuntimeCall( + createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_prepare_parallel), + Args); + + unsigned Idx = 0; + ASTContext &Ctx = CGF.getContext(); + for (llvm::Value *V : CapturedVars) { + Address Dst = Bld.CreateConstInBoundsGEP( + CGF.EmitLoadOfPointer(SharedArgs, + Ctx.getPointerType( + Ctx.getPointerType(Ctx.VoidPtrTy)).castAs<PointerType>()), + Idx, CGF.getPointerSize()); + llvm::Value *PtrV = Bld.CreateBitCast(V, CGF.VoidPtrTy); + CGF.EmitStoreOfScalar(PtrV, Dst, /*Volatile=*/false, + Ctx.getPointerType(Ctx.VoidPtrTy)); + Idx++; + } + } else { + llvm::Value *Args[] = {ID, + llvm::ConstantPointerNull::get(CGF.VoidPtrPtrTy->getPointerTo(0)), + /*nArgs=*/Bld.getInt32(0)}; + CGF.EmitRuntimeCall( + createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_kernel_prepare_parallel), + Args); + } // Activate workers. This barrier is used by the master to signal // work for the workers. @@ -925,17 +991,17 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall( syncCTAThreads(CGF); // Remember for post-processing in worker loop. - Work.push_back(Fn); + Work.emplace_back(WFn); }; auto *RTLoc = emitUpdateLocation(CGF, Loc); auto *ThreadID = getThreadID(CGF, Loc); llvm::Value *Args[] = {RTLoc, ThreadID}; - auto &&SeqGen = [this, Fn, &CapturedVars, &Args](CodeGenFunction &CGF, - PrePostActionTy &) { - auto &&CodeGen = [this, Fn, &CapturedVars](CodeGenFunction &CGF, - PrePostActionTy &Action) { + auto &&SeqGen = [this, Fn, &CapturedVars, &Args, Loc](CodeGenFunction &CGF, + PrePostActionTy &) { + auto &&CodeGen = [this, Fn, &CapturedVars, Loc](CodeGenFunction &CGF, + PrePostActionTy &Action) { Action.Enter(CGF); llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs; @@ -944,7 +1010,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall( OutlinedFnArgs.push_back( llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo())); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); - CGF.EmitCallOrInvoke(Fn, OutlinedFnArgs); + emitOutlinedFunctionCall(CGF, Loc, Fn, OutlinedFnArgs); }; RegionCodeGenTy RCG(CodeGen); @@ -980,7 +1046,7 @@ void CGOpenMPRuntimeNVPTX::emitSpmdParallelCall( OutlinedFnArgs.push_back( llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo())); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); - CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs); + emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); } /// This function creates calls to one of two shuffle functions to copy @@ -2238,3 +2304,183 @@ void CGOpenMPRuntimeNVPTX::emitReduction( CGF.EmitBranch(DefaultBB); CGF.EmitBlock(DefaultBB, /*IsFinished=*/true); } + +const VarDecl * +CGOpenMPRuntimeNVPTX::translateParameter(const FieldDecl *FD, + const VarDecl *NativeParam) const { + if (!NativeParam->getType()->isReferenceType()) + return NativeParam; + QualType ArgType = NativeParam->getType(); + QualifierCollector QC; + const Type *NonQualTy = QC.strip(ArgType); + QualType PointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType(); + if (const auto *Attr = FD->getAttr<OMPCaptureKindAttr>()) { + if (Attr->getCaptureKind() == OMPC_map) { + PointeeTy = CGM.getContext().getAddrSpaceQualType(PointeeTy, + LangAS::opencl_global); + } + } + ArgType = CGM.getContext().getPointerType(PointeeTy); + QC.addRestrict(); + enum { NVPTX_local_addr = 5 }; + QC.addAddressSpace(getLangASFromTargetAS(NVPTX_local_addr)); + ArgType = QC.apply(CGM.getContext(), ArgType); + if (isa<ImplicitParamDecl>(NativeParam)) { + return ImplicitParamDecl::Create( + CGM.getContext(), /*DC=*/nullptr, NativeParam->getLocation(), + NativeParam->getIdentifier(), ArgType, ImplicitParamDecl::Other); + } + return ParmVarDecl::Create( + CGM.getContext(), + const_cast<DeclContext *>(NativeParam->getDeclContext()), + NativeParam->getLocStart(), NativeParam->getLocation(), + NativeParam->getIdentifier(), ArgType, + /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr); +} + +Address +CGOpenMPRuntimeNVPTX::getParameterAddress(CodeGenFunction &CGF, + const VarDecl *NativeParam, + const VarDecl *TargetParam) const { + assert(NativeParam != TargetParam && + NativeParam->getType()->isReferenceType() && + "Native arg must not be the same as target arg."); + Address LocalAddr = CGF.GetAddrOfLocalVar(TargetParam); + QualType NativeParamType = NativeParam->getType(); + QualifierCollector QC; + const Type *NonQualTy = QC.strip(NativeParamType); + QualType NativePointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType(); + unsigned NativePointeeAddrSpace = + CGF.getContext().getTargetAddressSpace(NativePointeeTy); + QualType TargetTy = TargetParam->getType(); + llvm::Value *TargetAddr = CGF.EmitLoadOfScalar( + LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation()); + // First cast to generic. + TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo( + /*AddrSpace=*/0)); + // Cast from generic to native address space. + TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo( + NativePointeeAddrSpace)); + Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType); + CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false, + NativeParamType); + return NativeParamAddr; +} + +void CGOpenMPRuntimeNVPTX::emitOutlinedFunctionCall( + CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn, + ArrayRef<llvm::Value *> Args) const { + SmallVector<llvm::Value *, 4> TargetArgs; + TargetArgs.reserve(Args.size()); + auto *FnType = + cast<llvm::FunctionType>(OutlinedFn->getType()->getPointerElementType()); + for (unsigned I = 0, E = Args.size(); I < E; ++I) { + if (FnType->isVarArg() && FnType->getNumParams() <= I) { + TargetArgs.append(std::next(Args.begin(), I), Args.end()); + break; + } + llvm::Type *TargetType = FnType->getParamType(I); + llvm::Value *NativeArg = Args[I]; + if (!TargetType->isPointerTy()) { + TargetArgs.emplace_back(NativeArg); + continue; + } + llvm::Value *TargetArg = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + NativeArg, NativeArg->getType()->getPointerElementType()->getPointerTo( + /*AddrSpace=*/0)); + TargetArgs.emplace_back( + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TargetArg, TargetType)); + } + CGOpenMPRuntime::emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, TargetArgs); +} + +/// Emit function which wraps the outline parallel region +/// and controls the arguments which are passed to this function. +/// The wrapper ensures that the outlined function is called +/// with the correct arguments when data is shared. +llvm::Function *CGOpenMPRuntimeNVPTX::createDataSharingWrapper( + llvm::Function *OutlinedParallelFn, const OMPExecutableDirective &D) { + ASTContext &Ctx = CGM.getContext(); + const auto &CS = *cast<CapturedStmt>(D.getAssociatedStmt()); + + // Create a function that takes as argument the source thread. + FunctionArgList WrapperArgs; + QualType Int16QTy = + Ctx.getIntTypeForBitwidth(/*DestWidth=*/16, /*Signed=*/false); + QualType Int32QTy = + Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false); + QualType Int32PtrQTy = Ctx.getPointerType(Int32QTy); + QualType VoidPtrPtrQTy = Ctx.getPointerType(Ctx.VoidPtrTy); + ImplicitParamDecl ParallelLevelArg(Ctx, Int16QTy, ImplicitParamDecl::Other); + ImplicitParamDecl WrapperArg(Ctx, Int32QTy, ImplicitParamDecl::Other); + ImplicitParamDecl SharedArgsList(Ctx, VoidPtrPtrQTy, + ImplicitParamDecl::Other); + WrapperArgs.emplace_back(&ParallelLevelArg); + WrapperArgs.emplace_back(&WrapperArg); + WrapperArgs.emplace_back(&SharedArgsList); + + auto &CGFI = + CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, WrapperArgs); + + auto *Fn = llvm::Function::Create( + CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, + OutlinedParallelFn->getName() + "_wrapper", &CGM.getModule()); + CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, CGFI); + Fn->setLinkage(llvm::GlobalValue::InternalLinkage); + + CodeGenFunction CGF(CGM, /*suppressNewContext=*/true); + CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, Fn, CGFI, WrapperArgs); + + const auto *RD = CS.getCapturedRecordDecl(); + auto CurField = RD->field_begin(); + + // Get the array of arguments. + SmallVector<llvm::Value *, 8> Args; + + // TODO: suppport SIMD and pass actual values + Args.emplace_back(llvm::ConstantPointerNull::get( + CGM.Int32Ty->getPointerTo())); + Args.emplace_back(llvm::ConstantPointerNull::get( + CGM.Int32Ty->getPointerTo())); + + CGBuilderTy &Bld = CGF.Builder; + auto CI = CS.capture_begin(); + + // Load the start of the array + auto SharedArgs = + CGF.EmitLoadOfPointer(CGF.GetAddrOfLocalVar(&SharedArgsList), + VoidPtrPtrQTy->castAs<PointerType>()); + + // For each captured variable + for (unsigned I = 0; I < CS.capture_size(); ++I, ++CI, ++CurField) { + // Name of captured variable + StringRef Name; + if (CI->capturesThis()) + Name = "this"; + else + Name = CI->getCapturedVar()->getName(); + + // We retrieve the CLANG type of the argument. We use it to create + // an alloca which will give us the LLVM type. + QualType ElemTy = CurField->getType(); + // If this is a capture by copy the element type has to be the pointer to + // the data. + if (CI->capturesVariableByCopy()) + ElemTy = Ctx.getPointerType(ElemTy); + + // Get shared address of the captured variable. + Address ArgAddress = Bld.CreateConstInBoundsGEP( + SharedArgs, I, CGF.getPointerSize()); + Address TypedArgAddress = Bld.CreateBitCast( + ArgAddress, CGF.ConvertTypeForMem(Ctx.getPointerType(ElemTy))); + llvm::Value *Arg = CGF.EmitLoadOfScalar(TypedArgAddress, + /*Volatile=*/false, Int32PtrQTy, SourceLocation()); + Args.emplace_back(Arg); + } + + emitCall(CGF, OutlinedParallelFn, Args); + CGF.FinishFunction(); + return Fn; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h index ae25e94759e6a..5d13408318a55 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h @@ -268,6 +268,26 @@ public: /// \return Specified function. llvm::Constant *createNVPTXRuntimeFunction(unsigned Function); + /// Translates the native parameter of outlined function if this is required + /// for target. + /// \param FD Field decl from captured record for the paramater. + /// \param NativeParam Parameter itself. + const VarDecl *translateParameter(const FieldDecl *FD, + const VarDecl *NativeParam) const override; + + /// Gets the address of the native argument basing on the address of the + /// target-specific parameter. + /// \param NativeParam Parameter itself. + /// \param TargetParam Corresponding target-specific parameter. + Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam, + const VarDecl *TargetParam) const override; + + /// Emits call of the outlined function with the provided arguments, + /// translating these arguments to correct target-specific arguments. + void emitOutlinedFunctionCall( + CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn, + ArrayRef<llvm::Value *> Args = llvm::None) const override; + /// Target codegen is specialized based on two programming models: the /// 'generic' fork-join model of OpenMP, and a more GPU efficient 'spmd' /// model for constructs like 'target parallel' that support it. @@ -285,6 +305,17 @@ private: // target region and used by containing directives such as 'parallel' // to emit optimized code. ExecutionMode CurrentExecutionMode; + + /// Map between an outlined function and its wrapper. + llvm::DenseMap<llvm::Function *, llvm::Function *> WrapperFunctionsMap; + + /// Emit function which wraps the outline parallel region + /// and controls the parameters which are passed to this function. + /// The wrapper ensures that the outlined function is called + /// with the correct arguments when data is shared. + llvm::Function * + createDataSharingWrapper(llvm::Function *OutlinedParallelFn, + const OMPExecutableDirective &D); }; } // CodeGen namespace. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 7d530a278fbf0..1644ab4c07255 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -403,6 +403,27 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, } return; } + + // Check if current Field is better as a single field run. When current field + // has legal integer width, and its bitfield offset is naturally aligned, it + // is better to make the bitfield a separate storage component so as it can be + // accessed directly with lower cost. + auto IsBetterAsSingleFieldRun = [&](RecordDecl::field_iterator Field) { + if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses) + return false; + unsigned Width = Field->getBitWidthValue(Context); + if (!DataLayout.isLegalInteger(Width)) + return false; + // Make sure Field is natually aligned if it is treated as an IType integer. + if (getFieldBitOffset(*Field) % + Context.toBits(getAlignment(getIntNType(Width))) != + 0) + return false; + return true; + }; + + // The start field is better as a single field run. + bool StartFieldAsSingleRun = false; for (;;) { // Check to see if we need to start a new run. if (Run == FieldEnd) { @@ -414,17 +435,28 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, Run = Field; StartBitOffset = getFieldBitOffset(*Field); Tail = StartBitOffset + Field->getBitWidthValue(Context); + StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Run); } ++Field; continue; } - // Add bitfields to the run as long as they qualify. - if (Field != FieldEnd && Field->getBitWidthValue(Context) != 0 && + + // If the start field of a new run is better as a single run, or + // if current field is better as a single run, or + // if current field has zero width bitfield, or + // if the offset of current field is inconsistent with the offset of + // previous field plus its offset, + // skip the block below and go ahead to emit the storage. + // Otherwise, try to add bitfields to the run. + if (!StartFieldAsSingleRun && Field != FieldEnd && + !IsBetterAsSingleFieldRun(Field) && + Field->getBitWidthValue(Context) != 0 && Tail == getFieldBitOffset(*Field)) { Tail += Field->getBitWidthValue(Context); ++Field; continue; } + // We've hit a break-point in the run and need to emit a storage field. llvm::Type *Type = getIntNType(Tail - StartBitOffset); // Add the storage member to the record and set the bitfield info for all of @@ -435,6 +467,7 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), MemberInfo::Field, nullptr, *Run)); Run = FieldEnd; + StartFieldAsSingleRun = false; } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp index a13c386461647..91fa49a46ef1e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp @@ -45,7 +45,7 @@ void CodeGenFunction::EmitStopPoint(const Stmt *S) { } } -void CodeGenFunction::EmitStmt(const Stmt *S) { +void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { assert(S && "Null statement?"); PGO.setCurrentStmt(S); @@ -131,16 +131,16 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::IndirectGotoStmtClass: EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break; - case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break; - case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break; - case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S)); break; - case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break; + case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break; + case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break; + case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S), Attrs); break; + case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S), Attrs); break; - case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break; + case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break; - case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; - case Stmt::GCCAsmStmtClass: // Intentional fall-through. - case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; + case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; + case Stmt::GCCAsmStmtClass: // Intentional fall-through. + case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; case Stmt::CoroutineBodyStmtClass: EmitCoroutineBody(cast<CoroutineBodyStmt>(*S)); break; @@ -178,7 +178,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { EmitCXXTryStmt(cast<CXXTryStmt>(*S)); break; case Stmt::CXXForRangeStmtClass: - EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S)); + EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs); break; case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast<SEHTryStmt>(*S)); @@ -555,23 +555,7 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { } void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { - const Stmt *SubStmt = S.getSubStmt(); - switch (SubStmt->getStmtClass()) { - case Stmt::DoStmtClass: - EmitDoStmt(cast<DoStmt>(*SubStmt), S.getAttrs()); - break; - case Stmt::ForStmtClass: - EmitForStmt(cast<ForStmt>(*SubStmt), S.getAttrs()); - break; - case Stmt::WhileStmtClass: - EmitWhileStmt(cast<WhileStmt>(*SubStmt), S.getAttrs()); - break; - case Stmt::CXXForRangeStmtClass: - EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*SubStmt), S.getAttrs()); - break; - default: - EmitStmt(SubStmt); - } + EmitStmt(S.getSubStmt(), S.getAttrs()); } void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { @@ -2165,10 +2149,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::ConstantAsMetadata::get(Loc))); } - if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { - // Conservatively, mark all inline asm blocks in CUDA as convergent - // (meaning, they may call an intrinsically convergent op, such as bar.sync, - // and so can't have certain optimizations applied around them). + if (getLangOpts().assumeFunctionsAreConvergent()) { + // Conservatively, mark all inline asm blocks in CUDA or OpenCL as + // convergent (meaning, they may call an intrinsically convergent op, such + // as bar.sync, and so can't have certain optimizations applied around + // them). Result->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::Convergent); } @@ -2210,7 +2195,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize)); Tmp = Builder.CreateTrunc(Tmp, TruncTy); } else if (TruncTy->isIntegerTy()) { - Tmp = Builder.CreateTrunc(Tmp, TruncTy); + Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy); } else if (TruncTy->isVectorTy()) { Tmp = Builder.CreateBitCast(Tmp, TruncTy); } @@ -2283,7 +2268,6 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) { Args.append(CD->param_begin(), CD->param_end()); // Create the function declaration. - FunctionType::ExtInfo ExtInfo; const CGFunctionInfo &FuncInfo = CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp index cf430f860fd8a..f04d28ed0d4a9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -65,6 +65,8 @@ public: for (auto &C : CS->captures()) { if (C.capturesVariable() || C.capturesVariableByCopy()) { auto *VD = C.getCapturedVar(); + assert(VD == VD->getCanonicalDecl() && + "Canonical decl must be captured."); DeclRefExpr DRE(const_cast<VarDecl *>(VD), isCapturedVar(CGF, VD) || (CGF.CapturedStmtInfo && @@ -119,6 +121,14 @@ public: /// of used expression from loop statement. class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopDirective &S) { + CodeGenFunction::OMPPrivateScope PreCondScope(CGF); + for (auto *E : S.counters()) { + const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + (void)PreCondScope.addPrivate(VD, [&CGF, VD]() { + return CGF.CreateMemTemp(VD->getType().getNonReferenceType()); + }); + } + (void)PreCondScope.Privatize(); if (auto *LD = dyn_cast<OMPLoopDirective>(&S)) { if (auto *PreInits = cast_or_null<DeclStmt>(LD->getPreInits())) { for (const auto *I : PreInits->decls()) @@ -136,6 +146,26 @@ public: } // namespace +static void emitCommonOMPTargetDirective(CodeGenFunction &CGF, + const OMPExecutableDirective &S, + const RegionCodeGenTy &CodeGen); + +LValue CodeGenFunction::EmitOMPSharedLValue(const Expr *E) { + if (auto *OrigDRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *OrigVD = dyn_cast<VarDecl>(OrigDRE->getDecl())) { + OrigVD = OrigVD->getCanonicalDecl(); + bool IsCaptured = + LambdaCaptureFields.lookup(OrigVD) || + (CapturedStmtInfo && CapturedStmtInfo->lookup(OrigVD)) || + (CurCodeDecl && isa<BlockDecl>(CurCodeDecl)); + DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD), IsCaptured, + OrigDRE->getType(), VK_LValue, OrigDRE->getExprLoc()); + return EmitLValue(&DRE); + } + } + return EmitLValue(E); +} + llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) { auto &C = getContext(); llvm::Value *Size = nullptr; @@ -236,6 +266,12 @@ static QualType getCanonicalParamType(ASTContext &C, QualType T) { } if (T->isPointerType()) return C.getPointerType(getCanonicalParamType(C, T->getPointeeType())); + if (auto *A = T->getAsArrayTypeUnsafe()) { + if (auto *VLA = dyn_cast<VariableArrayType>(A)) + return getCanonicalParamType(C, VLA->getElementType()); + else if (!A->isVariablyModifiedType()) + return C.getCanonicalType(T); + } return C.getCanonicalParamType(T); } @@ -246,12 +282,12 @@ namespace { const CapturedStmt *S = nullptr; /// true if cast to/from UIntPtr is required for variables captured by /// value. - bool UIntPtrCastRequired = true; - /// true if only casted argumefnts must be registered as local args or VLA + const bool UIntPtrCastRequired = true; + /// true if only casted arguments must be registered as local args or VLA /// sizes. - bool RegisterCastedArgsOnly = false; + const bool RegisterCastedArgsOnly = false; /// Name of the generated function. - StringRef FunctionName; + const StringRef FunctionName; explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired, bool RegisterCastedArgsOnly, StringRef FunctionName) @@ -261,9 +297,9 @@ namespace { }; } -static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( +static llvm::Function *emitOutlinedFunctionPrologue( CodeGenFunction &CGF, FunctionArgList &Args, - llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>> + llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> &LocalAddrs, llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> &VLASizes, @@ -276,10 +312,23 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( // Build the argument list. CodeGenModule &CGM = CGF.CGM; ASTContext &Ctx = CGM.getContext(); - bool HasUIntPtrArgs = false; + FunctionArgList TargetArgs; Args.append(CD->param_begin(), std::next(CD->param_begin(), CD->getContextParamPosition())); + TargetArgs.append( + CD->param_begin(), + std::next(CD->param_begin(), CD->getContextParamPosition())); auto I = FO.S->captures().begin(); + FunctionDecl *DebugFunctionDecl = nullptr; + if (!FO.UIntPtrCastRequired) { + FunctionProtoType::ExtProtoInfo EPI; + DebugFunctionDecl = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), FO.S->getLocStart(), + SourceLocation(), DeclarationName(), Ctx.VoidTy, + Ctx.getTrivialTypeSourceInfo( + Ctx.getFunctionType(Ctx.VoidTy, llvm::None, EPI)), + SC_Static, /*isInlineSpecified=*/false, /*hasWrittenPrototype=*/false); + } for (auto *FD : RD->fields()) { QualType ArgType = FD->getType(); IdentifierInfo *II = nullptr; @@ -292,7 +341,6 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( // outlined function. if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) || I->capturesVariableArrayType()) { - HasUIntPtrArgs = true; if (FO.UIntPtrCastRequired) ArgType = Ctx.getUIntPtrType(); } @@ -307,20 +355,36 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( II = &Ctx.Idents.get("vla"); } if (ArgType->isVariablyModifiedType()) - ArgType = getCanonicalParamType(Ctx, ArgType.getNonReferenceType()); - Args.push_back(ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, - FD->getLocation(), II, ArgType, - ImplicitParamDecl::Other)); + ArgType = getCanonicalParamType(Ctx, ArgType); + VarDecl *Arg; + if (DebugFunctionDecl && (CapVar || I->capturesThis())) { + Arg = ParmVarDecl::Create( + Ctx, DebugFunctionDecl, + CapVar ? CapVar->getLocStart() : FD->getLocStart(), + CapVar ? CapVar->getLocation() : FD->getLocation(), II, ArgType, + /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr); + } else { + Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(), + II, ArgType, ImplicitParamDecl::Other); + } + Args.emplace_back(Arg); + // Do not cast arguments if we emit function with non-original types. + TargetArgs.emplace_back( + FO.UIntPtrCastRequired + ? Arg + : CGM.getOpenMPRuntime().translateParameter(FD, Arg)); ++I; } Args.append( std::next(CD->param_begin(), CD->getContextParamPosition() + 1), CD->param_end()); + TargetArgs.append( + std::next(CD->param_begin(), CD->getContextParamPosition() + 1), + CD->param_end()); // Create the function declaration. - FunctionType::ExtInfo ExtInfo; const CGFunctionInfo &FuncInfo = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); + CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, TargetArgs); llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo); llvm::Function *F = @@ -328,19 +392,26 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( FO.FunctionName, &CGM.getModule()); CGM.SetInternalFunctionAttributes(CD, F, FuncInfo); if (CD->isNothrow()) - F->addFnAttr(llvm::Attribute::NoUnwind); + F->setDoesNotThrow(); // Generate the function. - CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), - CD->getBody()->getLocStart()); + CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs, + FO.S->getLocStart(), CD->getBody()->getLocStart()); unsigned Cnt = CD->getContextParamPosition(); I = FO.S->captures().begin(); for (auto *FD : RD->fields()) { + // Do not map arguments if we emit function with non-original types. + Address LocalAddr(Address::invalid()); + if (!FO.UIntPtrCastRequired && Args[Cnt] != TargetArgs[Cnt]) { + LocalAddr = CGM.getOpenMPRuntime().getParameterAddress(CGF, Args[Cnt], + TargetArgs[Cnt]); + } else { + LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]); + } // If we are capturing a pointer by copy we don't need to do anything, just // use the value that we get from the arguments. if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) { const VarDecl *CurVD = I->getCapturedVar(); - Address LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]); // If the variable is a reference we need to materialize it here. if (CurVD->getType()->isReferenceType()) { Address RefAddr = CGF.CreateMemTemp( @@ -356,15 +427,14 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( continue; } - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); - LValue ArgLVal = CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(Args[Cnt]), - Args[Cnt]->getType(), BaseInfo); + LValue ArgLVal = CGF.MakeAddrLValue(LocalAddr, Args[Cnt]->getType(), + AlignmentSource::Decl); if (FD->hasCapturedVLAType()) { if (FO.UIntPtrCastRequired) { ArgLVal = CGF.MakeAddrLValue(castValueFromUintptr(CGF, FD->getType(), Args[Cnt]->getName(), ArgLVal), - FD->getType(), BaseInfo); + FD->getType(), AlignmentSource::Decl); } auto *ExprArg = CGF.EmitLoadOfLValue(ArgLVal, SourceLocation()).getScalarVal(); @@ -376,8 +446,7 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( Address ArgAddr = ArgLVal.getAddress(); if (!VarTy->isReferenceType()) { if (ArgLVal.getType()->isLValueReferenceType()) { - ArgAddr = CGF.EmitLoadOfReference( - ArgAddr, ArgLVal.getType()->castAs<ReferenceType>()); + ArgAddr = CGF.EmitLoadOfReference(ArgLVal); } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) { assert(ArgLVal.getType()->isPointerType()); ArgAddr = CGF.EmitLoadOfPointer( @@ -412,7 +481,7 @@ static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue( ++I; } - return {F, HasUIntPtrArgs}; + return F; } llvm::Function * @@ -426,14 +495,17 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { getDebugInfo() && CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo; FunctionArgList Args; - llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs; + llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs; llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes; + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + Out << CapturedStmtInfo->getHelperName(); + if (NeedWrapperFunction) + Out << "_debug__"; FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false, - CapturedStmtInfo->getHelperName()); - llvm::Function *F; - bool HasUIntPtrArgs; - std::tie(F, HasUIntPtrArgs) = emitOutlinedFunctionPrologue( - *this, Args, LocalAddrs, VLASizes, CXXThisValue, FO); + Out.str()); + llvm::Function *F = emitOutlinedFunctionPrologue(*this, Args, LocalAddrs, + VLASizes, CXXThisValue, FO); for (const auto &LocalAddrPair : LocalAddrs) { if (LocalAddrPair.second.first) { setAddrOfLocalVar(LocalAddrPair.second.first, @@ -445,28 +517,28 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { PGO.assignRegionCounters(GlobalDecl(CD), F); CapturedStmtInfo->EmitBody(*this, CD->getBody()); FinishFunction(CD->getBodyRBrace()); - if (!NeedWrapperFunction || !HasUIntPtrArgs) + if (!NeedWrapperFunction) return F; FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true, /*RegisterCastedArgsOnly=*/true, - ".nondebug_wrapper."); + CapturedStmtInfo->getHelperName()); CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true); - WrapperCGF.disableDebugInfo(); Args.clear(); LocalAddrs.clear(); VLASizes.clear(); llvm::Function *WrapperF = emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes, - WrapperCGF.CXXThisValue, WrapperFO).first; - LValueBaseInfo BaseInfo(AlignmentSource::Decl, false); + WrapperCGF.CXXThisValue, WrapperFO); llvm::SmallVector<llvm::Value *, 4> CallArgs; for (const auto *Arg : Args) { llvm::Value *CallArg; auto I = LocalAddrs.find(Arg); if (I != LocalAddrs.end()) { - LValue LV = - WrapperCGF.MakeAddrLValue(I->second.second, Arg->getType(), BaseInfo); + LValue LV = WrapperCGF.MakeAddrLValue( + I->second.second, + I->second.first ? I->second.first->getType() : Arg->getType(), + AlignmentSource::Decl); CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation()); } else { auto EI = VLASizes.find(Arg); @@ -474,13 +546,15 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { CallArg = EI->second.second; else { LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg), - Arg->getType(), BaseInfo); + Arg->getType(), + AlignmentSource::Decl); CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation()); } } - CallArgs.emplace_back(CallArg); + CallArgs.emplace_back(WrapperCGF.EmitFromMemory(CallArg, Arg->getType())); } - WrapperCGF.Builder.CreateCall(F, CallArgs); + CGM.getOpenMPRuntime().emitOutlinedFunctionCall(WrapperCGF, S.getLocStart(), + F, CallArgs); WrapperCGF.FinishFunction(); return WrapperF; } @@ -956,7 +1030,9 @@ void CodeGenFunction::EmitOMPReductionClauseInit( auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl()); auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl()); - if (isa<OMPArraySectionExpr>(IRef)) { + QualType Type = PrivateVD->getType(); + bool isaOMPArraySectionExpr = isa<OMPArraySectionExpr>(IRef); + if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { @@ -965,7 +1041,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit( PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); - } else if (isa<ArraySubscriptExpr>(IRef)) { + } else if ((isaOMPArraySectionExpr && Type->isScalarType()) || + isa<ArraySubscriptExpr>(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { @@ -1024,7 +1101,8 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( bool WithNowait = D.getSingleClause<OMPNowaitClause>() || isOpenMPParallelDirective(D.getDirectiveKind()) || D.getDirectiveKind() == OMPD_simd; - bool SimpleReduction = D.getDirectiveKind() == OMPD_simd; + bool SimpleReduction = D.getDirectiveKind() == OMPD_simd || + D.getDirectiveKind() == OMPD_distribute_simd; // Emit nowait reduction if nowait clause is present or directive is a // parallel directive (it always has implicit barrier). CGM.getOpenMPRuntime().emitReduction( @@ -1146,9 +1224,13 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, EmitIgnoredExpr(I); } // Update the linear variables. - for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) { - for (auto *U : C->updates()) - EmitIgnoredExpr(U); + // In distribute directives only loop counters may be marked as linear, no + // need to generate the code for them. + if (!isOpenMPDistributeDirective(D.getDirectiveKind())) { + for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) { + for (auto *U : C->updates()) + EmitIgnoredExpr(U); + } } // On a continue in the body, jump to the end. @@ -1488,83 +1570,90 @@ static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF, CGF.EmitStopPoint(&S); } -void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { - auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - // if (PreCond) { - // for (IV in 0..LastIteration) BODY; - // <Final counter/linear vars updates>; - // } - // +static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S, + PrePostActionTy &Action) { + Action.Enter(CGF); + assert(isOpenMPSimdDirective(S.getDirectiveKind()) && + "Expected simd directive"); + OMPLoopScope PreInitScope(CGF, S); + // if (PreCond) { + // for (IV in 0..LastIteration) BODY; + // <Final counter/linear vars updates>; + // } + // - // Emit: if (PreCond) - begin. - // If the condition constant folds and can be elided, avoid emitting the - // whole loop. - bool CondConstant; - llvm::BasicBlock *ContBlock = nullptr; - if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { - if (!CondConstant) - return; - } else { - auto *ThenBlock = CGF.createBasicBlock("simd.if.then"); - ContBlock = CGF.createBasicBlock("simd.if.end"); - emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock, - CGF.getProfileCount(&S)); - CGF.EmitBlock(ThenBlock); - CGF.incrementProfileCounter(&S); - } + // Emit: if (PreCond) - begin. + // If the condition constant folds and can be elided, avoid emitting the + // whole loop. + bool CondConstant; + llvm::BasicBlock *ContBlock = nullptr; + if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { + if (!CondConstant) + return; + } else { + auto *ThenBlock = CGF.createBasicBlock("simd.if.then"); + ContBlock = CGF.createBasicBlock("simd.if.end"); + emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock, + CGF.getProfileCount(&S)); + CGF.EmitBlock(ThenBlock); + CGF.incrementProfileCounter(&S); + } - // Emit the loop iteration variable. - const Expr *IVExpr = S.getIterationVariable(); - const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl()); - CGF.EmitVarDecl(*IVDecl); - CGF.EmitIgnoredExpr(S.getInit()); + // Emit the loop iteration variable. + const Expr *IVExpr = S.getIterationVariable(); + const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl()); + CGF.EmitVarDecl(*IVDecl); + CGF.EmitIgnoredExpr(S.getInit()); - // Emit the iterations count variable. - // If it is not a variable, Sema decided to calculate iterations count on - // each iteration (e.g., it is foldable into a constant). - if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) { - CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl())); - // Emit calculation of the iterations count. - CGF.EmitIgnoredExpr(S.getCalcLastIteration()); - } + // Emit the iterations count variable. + // If it is not a variable, Sema decided to calculate iterations count on + // each iteration (e.g., it is foldable into a constant). + if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) { + CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl())); + // Emit calculation of the iterations count. + CGF.EmitIgnoredExpr(S.getCalcLastIteration()); + } - CGF.EmitOMPSimdInit(S); + CGF.EmitOMPSimdInit(S); - emitAlignedClause(CGF, S); - (void)CGF.EmitOMPLinearClauseInit(S); - { - OMPPrivateScope LoopScope(CGF); - CGF.EmitOMPPrivateLoopCounters(S, LoopScope); - CGF.EmitOMPLinearClause(S, LoopScope); - CGF.EmitOMPPrivateClause(S, LoopScope); - CGF.EmitOMPReductionClauseInit(S, LoopScope); - bool HasLastprivateClause = - CGF.EmitOMPLastprivateClauseInit(S, LoopScope); - (void)LoopScope.Privatize(); - CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), - S.getInc(), - [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S, JumpDest()); - CGF.EmitStopPoint(&S); - }, - [](CodeGenFunction &) {}); - CGF.EmitOMPSimdFinal( - S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); - // Emit final copy of the lastprivate variables at the end of loops. - if (HasLastprivateClause) - CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true); - CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd); - emitPostUpdateForReductionClause( - CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); - } - CGF.EmitOMPLinearClauseFinal( + emitAlignedClause(CGF, S); + (void)CGF.EmitOMPLinearClauseInit(S); + { + CodeGenFunction::OMPPrivateScope LoopScope(CGF); + CGF.EmitOMPPrivateLoopCounters(S, LoopScope); + CGF.EmitOMPLinearClause(S, LoopScope); + CGF.EmitOMPPrivateClause(S, LoopScope); + CGF.EmitOMPReductionClauseInit(S, LoopScope); + bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); + (void)LoopScope.Privatize(); + CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), + S.getInc(), + [&S](CodeGenFunction &CGF) { + CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest()); + CGF.EmitStopPoint(&S); + }, + [](CodeGenFunction &) {}); + CGF.EmitOMPSimdFinal( S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); - // Emit: if (PreCond) - end. - if (ContBlock) { - CGF.EmitBranch(ContBlock); - CGF.EmitBlock(ContBlock, true); - } + // Emit final copy of the lastprivate variables at the end of loops. + if (HasLastprivateClause) + CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd); + emitPostUpdateForReductionClause( + CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); + } + CGF.EmitOMPLinearClauseFinal( + S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); + // Emit: if (PreCond) - end. + if (ContBlock) { + CGF.EmitBranch(ContBlock); + CGF.EmitBlock(ContBlock, true); + } +} + +void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitOMPSimdRegion(CGF, S, Action); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); @@ -1669,7 +1758,8 @@ void CodeGenFunction::EmitOMPOuterLoop( // Tell the runtime we are done. auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) { if (!DynamicOrOrdered) - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(), + S.getDirectiveKind()); }; OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } @@ -1753,9 +1843,11 @@ void CodeGenFunction::EmitOMPForOuterLoop( RT.emitForDispatchInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, DipatchRTInputValues); } else { - RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, - Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB, - LoopArgs.ST, LoopArgs.Chunk); + CGOpenMPRuntime::StaticRTInput StaticInit( + IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB, + LoopArgs.ST, LoopArgs.Chunk); + RT.emitForStaticInit(*this, S.getLocStart(), S.getDirectiveKind(), + ScheduleKind, StaticInit); } auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc, @@ -1797,10 +1889,10 @@ void CodeGenFunction::EmitOMPDistributeOuterLoop( const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); - RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, - IVSigned, /* Ordered = */ false, LoopArgs.IL, - LoopArgs.LB, LoopArgs.UB, LoopArgs.ST, - LoopArgs.Chunk); + CGOpenMPRuntime::StaticRTInput StaticInit( + IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB, + LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk); + RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, StaticInit); // for combined 'distribute' and 'for' the increment expression of distribute // is store in DistInc. For 'distribute' alone, it is in Inc. @@ -1929,13 +2021,27 @@ emitInnerParallelForWhenCombined(CodeGenFunction &CGF, CodeGenFunction::JumpDest LoopExit) { auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + bool HasCancel = false; + if (!isOpenMPSimdDirective(S.getDirectiveKind())) { + if (const auto *D = dyn_cast<OMPTeamsDistributeParallelForDirective>(&S)) + HasCancel = D->hasCancel(); + else if (const auto *D = dyn_cast<OMPDistributeParallelForDirective>(&S)) + HasCancel = D->hasCancel(); + else if (const auto *D = + dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&S)) + HasCancel = D->hasCancel(); + } + CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, S.getDirectiveKind(), + HasCancel); CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(), emitDistributeParallelForInnerBounds, emitDistributeParallelForDispatchBounds); }; emitCommonOMPParallelDirective( - CGF, S, OMPD_for, CGInlinedWorksharingLoop, + CGF, S, + isOpenMPSimdDirective(S.getDirectiveKind()) ? OMPD_for_simd : OMPD_for, + CGInlinedWorksharingLoop, emitDistributeParallelForDistributeInnerBoundParams); } @@ -1946,119 +2052,53 @@ void CodeGenFunction::EmitOMPDistributeParallelForDirective( S.getDistInc()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - OMPCancelStackRAII CancelRegion(*this, OMPD_distribute_parallel_for, - /*HasCancel=*/false); - CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen, - /*HasCancel=*/false); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen); } void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective( const OMPDistributeParallelForSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined, + S.getDistInc()); + }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_distribute_parallel_for_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen); } void CodeGenFunction::EmitOMPDistributeSimdDirective( const OMPDistributeSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_distribute_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); } -void CodeGenFunction::EmitOMPTargetParallelForSimdDirective( - const OMPTargetParallelForSimdDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_target_parallel_for_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); +void CodeGenFunction::EmitOMPTargetSimdDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S) { + // Emit SPMD target parallel for region as a standalone region. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitOMPSimdRegion(CGF, S, Action); + }; + llvm::Function *Fn; + llvm::Constant *Addr; + // Emit target region as a standalone region. + CGM.getOpenMPRuntime().emitTargetOutlinedFunction( + S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen); + assert(Fn && Addr && "Target device function emission failed."); } void CodeGenFunction::EmitOMPTargetSimdDirective( const OMPTargetSimdDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_target_simd, [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - -void CodeGenFunction::EmitOMPTeamsDistributeDirective( - const OMPTeamsDistributeDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_teams_distribute, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - -void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective( - const OMPTeamsDistributeSimdDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_teams_distribute_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - -void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective( - const OMPTeamsDistributeParallelForSimdDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_teams_distribute_parallel_for_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - -void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective( - const OMPTeamsDistributeParallelForDirective &S) { - OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_teams_distribute_parallel_for, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPLoopScope PreInitScope(CGF, S); - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - -void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective( - const OMPTargetTeamsDistributeDirective &S) { - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_target_teams_distribute, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitOMPSimdRegion(CGF, S, Action); + }; + emitCommonOMPTargetDirective(*this, S, CodeGen); } void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective( const OMPTargetTeamsDistributeParallelForDirective &S) { + OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_target_teams_distribute_parallel_for, [&S](CodeGenFunction &CGF, PrePostActionTy &) { @@ -2069,6 +2109,7 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective( void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective( const OMPTargetTeamsDistributeParallelForSimdDirective &S) { + OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_target_teams_distribute_parallel_for_simd, [&S](CodeGenFunction &CGF, PrePostActionTy &) { @@ -2077,16 +2118,6 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective( }); } -void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective( - const OMPTargetTeamsDistributeSimdDirective &S) { - CGM.getOpenMPRuntime().emitInlinedDirective( - *this, OMPD_target_teams_distribute_simd, - [&S](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitStmt( - cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); - }); -} - namespace { struct ScheduleKindModifiersTy { OpenMPScheduleClauseKind Kind; @@ -2209,10 +2240,11 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( // chunks that are approximately equal in size, and at most one chunk is // distributed to each thread. Note that the size of the chunks is // unspecified in this case. - RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, - IVSize, IVSigned, Ordered, - IL.getAddress(), LB.getAddress(), - UB.getAddress(), ST.getAddress()); + CGOpenMPRuntime::StaticRTInput StaticInit( + IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(), + UB.getAddress(), ST.getAddress()); + RT.emitForStaticInit(*this, S.getLocStart(), S.getDirectiveKind(), + ScheduleKind, StaticInit); auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); @@ -2230,7 +2262,8 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. auto &&CodeGen = [&S](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(), + S.getDirectiveKind()); }; OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } else { @@ -2444,10 +2477,11 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { // Emit static non-chunked loop. OpenMPScheduleTy ScheduleKind; ScheduleKind.Schedule = OMPC_SCHEDULE_static; + CGOpenMPRuntime::StaticRTInput StaticInit( + /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), + LB.getAddress(), UB.getAddress(), ST.getAddress()); CGF.CGM.getOpenMPRuntime().emitForStaticInit( - CGF, S.getLocStart(), ScheduleKind, /*IVSize=*/32, - /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), LB.getAddress(), - UB.getAddress(), ST.getAddress()); + CGF, S.getLocStart(), S.getDirectiveKind(), ScheduleKind, StaticInit); // UB = min(UB, GlobalUB); auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart()); auto *MinUBGlobalUB = CGF.Builder.CreateSelect( @@ -2460,7 +2494,8 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { [](CodeGenFunction &) {}); // Tell the runtime we are done. auto &&CodeGen = [&S](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(), + S.getDirectiveKind()); }; CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel); @@ -2731,6 +2766,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, OMPPrivateScope Scope(CGF); if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() || !Data.LastprivateVars.empty()) { + enum { PrivatesParam = 2, CopyFnParam = 3 }; auto *CopyFn = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(3))); auto *PrivatesPtr = CGF.Builder.CreateLoad( @@ -2762,7 +2798,8 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } - CGF.EmitRuntimeCall(CopyFn, CallArgs); + CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getLocStart(), + CopyFn, CallArgs); for (auto &&Pair : LastprivateDstsOrigs) { auto *OrigVD = cast<VarDecl>(Pair.second->getDecl()); DeclRefExpr DRE( @@ -2808,7 +2845,57 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, RedCG, Cnt); } } + // Privatize all private variables except for in_reduction items. (void)Scope.Privatize(); + SmallVector<const Expr *, 4> InRedVars; + SmallVector<const Expr *, 4> InRedPrivs; + SmallVector<const Expr *, 4> InRedOps; + SmallVector<const Expr *, 4> TaskgroupDescriptors; + for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) { + auto IPriv = C->privates().begin(); + auto IRed = C->reduction_ops().begin(); + auto ITD = C->taskgroup_descriptors().begin(); + for (const auto *Ref : C->varlists()) { + InRedVars.emplace_back(Ref); + InRedPrivs.emplace_back(*IPriv); + InRedOps.emplace_back(*IRed); + TaskgroupDescriptors.emplace_back(*ITD); + std::advance(IPriv, 1); + std::advance(IRed, 1); + std::advance(ITD, 1); + } + } + // Privatize in_reduction items here, because taskgroup descriptors must be + // privatized earlier. + OMPPrivateScope InRedScope(CGF); + if (!InRedVars.empty()) { + ReductionCodeGen RedCG(InRedVars, InRedPrivs, InRedOps); + for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) { + RedCG.emitSharedLValue(CGF, Cnt); + RedCG.emitAggregateType(CGF, Cnt); + // The taskgroup descriptor variable is always implicit firstprivate and + // privatized already during procoessing of the firstprivates. + llvm::Value *ReductionsPtr = CGF.EmitLoadOfScalar( + CGF.EmitLValue(TaskgroupDescriptors[Cnt]), SourceLocation()); + Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( + CGF, S.getLocStart(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); + Replacement = Address( + CGF.EmitScalarConversion( + Replacement.getPointer(), CGF.getContext().VoidPtrTy, + CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()), + SourceLocation()), + Replacement.getAlignment()); + Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement); + InRedScope.addPrivate(RedCG.getBaseDecl(Cnt), + [Replacement]() { return Replacement; }); + // FIXME: This must removed once the runtime library is fixed. + // Emit required threadprivate variables for + // initilizer/combiner/finalizer. + CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getLocStart(), + RedCG, Cnt); + } + } + (void)InRedScope.Privatize(); Action.Enter(CGF); BodyGen(CGF); @@ -2867,6 +2954,35 @@ void CodeGenFunction::EmitOMPTaskgroupDirective( const OMPTaskgroupDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); + if (const Expr *E = S.getReductionRef()) { + SmallVector<const Expr *, 4> LHSs; + SmallVector<const Expr *, 4> RHSs; + OMPTaskDataTy Data; + for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) { + auto IPriv = C->privates().begin(); + auto IRed = C->reduction_ops().begin(); + auto ILHS = C->lhs_exprs().begin(); + auto IRHS = C->rhs_exprs().begin(); + for (const auto *Ref : C->varlists()) { + Data.ReductionVars.emplace_back(Ref); + Data.ReductionCopies.emplace_back(*IPriv); + Data.ReductionOps.emplace_back(*IRed); + LHSs.emplace_back(*ILHS); + RHSs.emplace_back(*IRHS); + std::advance(IPriv, 1); + std::advance(IRed, 1); + std::advance(ILHS, 1); + std::advance(IRHS, 1); + } + } + llvm::Value *ReductionDesc = + CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getLocStart(), + LHSs, RHSs, Data); + const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + CGF.EmitVarDecl(*VD); + CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD), + /*Volatile=*/false, E->getType()); + } CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); @@ -2923,6 +3039,7 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, incrementProfileCounter(&S); } + emitAlignedClause(*this, S); // Emit 'then' code. { // Emit helper vars inits. @@ -2944,14 +3061,18 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, OMPPrivateScope LoopScope(*this); if (EmitOMPFirstprivateClause(S, LoopScope)) { - // Emit implicit barrier to synchronize threads and avoid data races on - // initialization of firstprivate variables and post-update of + // Emit implicit barrier to synchronize threads and avoid data races + // on initialization of firstprivate variables and post-update of // lastprivate variables. CGM.getOpenMPRuntime().emitBarrierCall( - *this, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, - /*ForceSimpleCall=*/true); + *this, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, + /*ForceSimpleCall=*/true); } EmitOMPPrivateClause(S, LoopScope); + if (isOpenMPSimdDirective(S.getDirectiveKind()) && + !isOpenMPParallelDirective(S.getDirectiveKind()) && + !isOpenMPTeamsDirective(S.getDirectiveKind())) + EmitOMPReductionClauseInit(S, LoopScope); HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope); EmitOMPPrivateLoopCounters(S, LoopScope); (void)LoopScope.Privatize(); @@ -2964,8 +3085,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, if (const auto *Ch = C->getChunkSize()) { Chunk = EmitScalarExpr(Ch); Chunk = EmitScalarConversion(Chunk, Ch->getType(), - S.getIterationVariable()->getType(), - S.getLocStart()); + S.getIterationVariable()->getType(), + S.getLocStart()); } } const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); @@ -2981,10 +3102,13 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, // league. The size of the chunks is unspecified in this case. if (RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr)) { + if (isOpenMPSimdDirective(S.getDirectiveKind())) + EmitOMPSimdInit(S, /*IsMonotonic=*/true); + CGOpenMPRuntime::StaticRTInput StaticInit( + IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(), + LB.getAddress(), UB.getAddress(), ST.getAddress()); RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, - IVSize, IVSigned, /* Ordered = */ false, - IL.getAddress(), LB.getAddress(), - UB.getAddress(), ST.getAddress()); + StaticInit); auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); @@ -3011,7 +3135,7 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. - RT.emitForStaticFinish(*this, S.getLocStart()); + RT.emitForStaticFinish(*this, S.getLocStart(), S.getDirectiveKind()); } else { // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. @@ -3021,13 +3145,38 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments, CodeGenLoop); } - + if (isOpenMPSimdDirective(S.getDirectiveKind())) { + EmitOMPSimdFinal(S, [&](CodeGenFunction &CGF) -> llvm::Value * { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart())); + }); + } + OpenMPDirectiveKind ReductionKind = OMPD_unknown; + if (isOpenMPParallelDirective(S.getDirectiveKind()) && + isOpenMPSimdDirective(S.getDirectiveKind())) { + ReductionKind = OMPD_parallel_for_simd; + } else if (isOpenMPParallelDirective(S.getDirectiveKind())) { + ReductionKind = OMPD_parallel_for; + } else if (isOpenMPSimdDirective(S.getDirectiveKind())) { + ReductionKind = OMPD_simd; + } else if (!isOpenMPTeamsDirective(S.getDirectiveKind()) && + S.hasClausesOfKind<OMPReductionClause>()) { + llvm_unreachable( + "No reduction clauses is allowed in distribute directive."); + } + EmitOMPReductionClauseFinal(S, ReductionKind); + // Emit post-update of the reduction variables if IsLastIter != 0. + emitPostUpdateForReductionClause( + *this, S, [&](CodeGenFunction &CGF) -> llvm::Value * { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart())); + }); // Emit final copy of the lastprivate variables if IsLastIter != 0. - if (HasLastprivateClause) + if (HasLastprivateClause) { EmitOMPLastprivateClauseFinal( S, /*NoFinals=*/false, - Builder.CreateIsNotNull( - EmitLoadOfScalar(IL, S.getLocStart()))); + Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart()))); + } } // We're now done with the loop, so jump to the continuation block. @@ -3045,8 +3194,7 @@ void CodeGenFunction::EmitOMPDistributeDirective( CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen, - false); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen); } static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM, @@ -3073,7 +3221,8 @@ void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { llvm::SmallVector<llvm::Value *, 16> CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); auto *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS); - CGF.EmitNounwindRuntimeCall(OutlinedFn, CapturedVars); + CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getLocStart(), + OutlinedFn, CapturedVars); } else { Action.Enter(CGF); CGF.EmitStmt( @@ -3259,6 +3408,7 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, case BO_GE: case BO_EQ: case BO_NE: + case BO_Cmp: case BO_AddAssign: case BO_SubAssign: case BO_AndAssign: @@ -3470,6 +3620,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_lastprivate: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: @@ -3552,7 +3703,7 @@ static void emitCommonOMPTargetDirective(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen) { assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind())); CodeGenModule &CGM = CGF.CGM; - const CapturedStmt &CS = *cast<CapturedStmt>(S.getAssociatedStmt()); + const CapturedStmt &CS = *S.getCapturedStmt(OMPD_target); llvm::Function *Fn = nullptr; llvm::Constant *FnID = nullptr; @@ -3675,7 +3826,7 @@ void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) { CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - emitCommonOMPTeamsDirective(*this, S, OMPD_teams, CodeGen); + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen); emitPostUpdateForReductionClause( *this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } @@ -3684,11 +3835,20 @@ static void emitTargetTeamsRegion(CodeGenFunction &CGF, PrePostActionTy &Action, const OMPTargetTeamsDirective &S) { auto *CS = S.getCapturedStmt(OMPD_teams); Action.Enter(CGF); - auto &&CodeGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) { - // TODO: Add support for clauses. + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) { + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); + CGF.EmitOMPPrivateClause(S, PrivateScope); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + Action.Enter(CGF); CGF.EmitStmt(CS->getCapturedStmt()); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen); + emitPostUpdateForReductionClause( + CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } void CodeGenFunction::EmitOMPTargetTeamsDeviceFunction( @@ -3713,6 +3873,183 @@ void CodeGenFunction::EmitOMPTargetTeamsDirective( emitCommonOMPTargetDirective(*this, S, CodeGen); } +static void +emitTargetTeamsDistributeRegion(CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsDistributeDirective &S) { + Action.Enter(CGF); + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute, + CodeGenDistribute); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen); + emitPostUpdateForReductionClause(CGF, S, + [](CodeGenFunction &) { return nullptr; }); +} + +void CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetTeamsDistributeDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetTeamsDistributeRegion(CGF, Action, S); + }; + llvm::Function *Fn; + llvm::Constant *Addr; + // Emit target region as a standalone region. + CGM.getOpenMPRuntime().emitTargetOutlinedFunction( + S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen); + assert(Fn && Addr && "Target device function emission failed."); +} + +void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective( + const OMPTargetTeamsDistributeDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetTeamsDistributeRegion(CGF, Action, S); + }; + emitCommonOMPTargetDirective(*this, S, CodeGen); +} + +static void emitTargetTeamsDistributeSimdRegion( + CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsDistributeSimdDirective &S) { + Action.Enter(CGF); + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute, + CodeGenDistribute); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_simd, CodeGen); + emitPostUpdateForReductionClause(CGF, S, + [](CodeGenFunction &) { return nullptr; }); +} + +void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetTeamsDistributeSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetTeamsDistributeSimdRegion(CGF, Action, S); + }; + llvm::Function *Fn; + llvm::Constant *Addr; + // Emit target region as a standalone region. + CGM.getOpenMPRuntime().emitTargetOutlinedFunction( + S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen); + assert(Fn && Addr && "Target device function emission failed."); +} + +void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective( + const OMPTargetTeamsDistributeSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetTeamsDistributeSimdRegion(CGF, Action, S); + }; + emitCommonOMPTargetDirective(*this, S, CodeGen); +} + +void CodeGenFunction::EmitOMPTeamsDistributeDirective( + const OMPTeamsDistributeDirective &S) { + + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute, + CodeGenDistribute); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen); + emitPostUpdateForReductionClause(*this, S, + [](CodeGenFunction &) { return nullptr; }); +} + +void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective( + const OMPTeamsDistributeSimdDirective &S) { + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd, + CodeGenDistribute); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_simd, CodeGen); + emitPostUpdateForReductionClause(*this, S, + [](CodeGenFunction &) { return nullptr; }); +} + +void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective( + const OMPTeamsDistributeParallelForDirective &S) { + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined, + S.getDistInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute, + CodeGenDistribute); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen); + emitPostUpdateForReductionClause(*this, S, + [](CodeGenFunction &) { return nullptr; }); +} + +void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective( + const OMPTeamsDistributeParallelForSimdDirective &S) { + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined, + S.getDistInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &) { + OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective( + CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen); + emitPostUpdateForReductionClause(*this, S, + [](CodeGenFunction &) { return nullptr; }); +} + void CodeGenFunction::EmitOMPCancellationPointDirective( const OMPCancellationPointDirective &S) { CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getLocStart(), @@ -3740,7 +4077,9 @@ CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) { assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections || Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for || Kind == OMPD_distribute_parallel_for || - Kind == OMPD_target_parallel_for); + Kind == OMPD_target_parallel_for || + Kind == OMPD_teams_distribute_parallel_for || + Kind == OMPD_target_teams_distribute_parallel_for); return OMPCancelStack.getExitBlock(); } @@ -3913,7 +4252,14 @@ void CodeGenFunction::EmitOMPTargetEnterDataDirective( if (auto *C = S.getSingleClause<OMPDeviceClause>()) Device = C->getDevice(); - CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); + auto &&CodeGen = [&S, IfCond, Device](CodeGenFunction &CGF, + PrePostActionTy &) { + CGF.CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(CGF, S, IfCond, + Device); + }; + OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_target_enter_data, + CodeGen); } void CodeGenFunction::EmitOMPTargetExitDataDirective( @@ -3933,7 +4279,14 @@ void CodeGenFunction::EmitOMPTargetExitDataDirective( if (auto *C = S.getSingleClause<OMPDeviceClause>()) Device = C->getDevice(); - CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); + auto &&CodeGen = [&S, IfCond, Device](CodeGenFunction &CGF, + PrePostActionTy &) { + CGF.CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(CGF, S, IfCond, + Device); + }; + OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_target_exit_data, + CodeGen); } static void emitTargetParallelRegion(CodeGenFunction &CGF, @@ -3980,9 +4333,81 @@ void CodeGenFunction::EmitOMPTargetParallelDirective( emitCommonOMPTargetDirective(*this, S, CodeGen); } +static void emitTargetParallelForRegion(CodeGenFunction &CGF, + const OMPTargetParallelForDirective &S, + PrePostActionTy &Action) { + Action.Enter(CGF); + // Emit directive as a combined directive that consists of two implicit + // directives: 'parallel' with 'for' directive. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CodeGenFunction::OMPCancelStackRAII CancelRegion( + CGF, OMPD_target_parallel_for, S.hasCancel()); + CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds, + emitDispatchForLoopBounds); + }; + emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen, + emitEmptyBoundParameters); +} + +void CodeGenFunction::EmitOMPTargetParallelForDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetParallelForDirective &S) { + // Emit SPMD target parallel for region as a standalone region. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetParallelForRegion(CGF, S, Action); + }; + llvm::Function *Fn; + llvm::Constant *Addr; + // Emit target region as a standalone region. + CGM.getOpenMPRuntime().emitTargetOutlinedFunction( + S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen); + assert(Fn && Addr && "Target device function emission failed."); +} + void CodeGenFunction::EmitOMPTargetParallelForDirective( const OMPTargetParallelForDirective &S) { - // TODO: codegen for target parallel for. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetParallelForRegion(CGF, S, Action); + }; + emitCommonOMPTargetDirective(*this, S, CodeGen); +} + +static void +emitTargetParallelForSimdRegion(CodeGenFunction &CGF, + const OMPTargetParallelForSimdDirective &S, + PrePostActionTy &Action) { + Action.Enter(CGF); + // Emit directive as a combined directive that consists of two implicit + // directives: 'parallel' with 'for' directive. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds, + emitDispatchForLoopBounds); + }; + emitCommonOMPParallelDirective(CGF, S, OMPD_simd, CodeGen, + emitEmptyBoundParameters); +} + +void CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetParallelForSimdDirective &S) { + // Emit SPMD target parallel for region as a standalone region. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetParallelForSimdRegion(CGF, S, Action); + }; + llvm::Function *Fn; + llvm::Constant *Addr; + // Emit target region as a standalone region. + CGM.getOpenMPRuntime().emitTargetOutlinedFunction( + S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen); + assert(Fn && Addr && "Target device function emission failed."); +} + +void CodeGenFunction::EmitOMPTargetParallelForSimdDirective( + const OMPTargetParallelForSimdDirective &S) { + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + emitTargetParallelForSimdRegion(CGF, S, Action); + }; + emitCommonOMPTargetDirective(*this, S, CodeGen); } /// Emit a helper variable and return corresponding lvalue. @@ -4160,5 +4585,12 @@ void CodeGenFunction::EmitOMPTargetUpdateDirective( if (auto *C = S.getSingleClause<OMPDeviceClause>()) Device = C->getDevice(); - CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); + auto &&CodeGen = [&S, IfCond, Device](CodeGenFunction &CGF, + PrePostActionTy &) { + CGF.CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(CGF, S, IfCond, + Device); + }; + OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_target_update, + CodeGen); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp index 92fd93b5ca387..78928d04220d3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp @@ -100,7 +100,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, VTT->setComdat(CGM.getModule().getOrInsertComdat(VTT->getName())); // Set the right visibility. - CGM.setGlobalVisibility(VTT, RD); + CGM.setGlobalVisibility(VTT, RD, ForDefinition); } llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp index 64b6d0d3fe9f5..2d9bf3bce926a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp @@ -14,11 +14,12 @@ #include "CGCXXABI.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/Frontend/CodeGenOptions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/Format.h" #include "llvm/Transforms/Utils/Cloning.h" #include <algorithm> @@ -50,7 +51,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, const ThunkInfo &Thunk, llvm::Function *Fn) { - CGM.setGlobalVisibility(Fn, MD); + CGM.setGlobalVisibility(Fn, MD, ForDefinition); } static void setThunkProperties(CodeGenModule &CGM, const ThunkInfo &Thunk, @@ -122,6 +123,33 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF, return RValue::get(ReturnValue); } +/// This function clones a function's DISubprogram node and enters it into +/// a value map with the intent that the map can be utilized by the cloner +/// to short-circuit Metadata node mapping. +/// Furthermore, the function resolves any DILocalVariable nodes referenced +/// by dbg.value intrinsics so they can be properly mapped during cloning. +static void resolveTopLevelMetadata(llvm::Function *Fn, + llvm::ValueToValueMapTy &VMap) { + // Clone the DISubprogram node and put it into the Value map. + auto *DIS = Fn->getSubprogram(); + if (!DIS) + return; + auto *NewDIS = DIS->replaceWithDistinct(DIS->clone()); + VMap.MD()[DIS].reset(NewDIS); + + // Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes + // they are referencing. + for (auto &BB : Fn->getBasicBlockList()) { + for (auto &I : BB) { + if (auto *DII = dyn_cast<llvm::DbgInfoIntrinsic>(&I)) { + auto *DILocal = DII->getVariable(); + if (!DILocal->isResolved()) + DILocal->resolve(); + } + } + } +} + // This function does roughly the same thing as GenerateThunk, but in a // very different way, so that va_start and va_end work correctly. // FIXME: This function assumes "this" is the first non-sret LLVM argument of @@ -154,6 +182,10 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, // Clone to thunk. llvm::ValueToValueMapTy VMap; + + // We are cloning a function while some Metadata nodes are still unresolved. + // Ensure that the value mapper does not encounter any of them. + resolveTopLevelMetadata(BaseFn, VMap); llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap); Fn->replaceAllUsesWith(NewFn); NewFn->takeName(Fn); @@ -698,7 +730,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage); - CGM.setGlobalVisibility(VTable, RD); + CGM.setGlobalVisibility(VTable, RD, ForDefinition); // V-tables are always unnamed_addr. VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h index b768eb86367be..7d07ea4516c92 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h @@ -20,6 +20,7 @@ #include "llvm/IR/Value.h" #include "llvm/IR/Type.h" #include "Address.h" +#include "CodeGenTBAA.h" namespace llvm { class Constant; @@ -148,20 +149,15 @@ static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) { class LValueBaseInfo { AlignmentSource AlignSource; - bool MayAlias; public: - explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type, - bool Alias = false) - : AlignSource(Source), MayAlias(Alias) {} + explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type) + : AlignSource(Source) {} AlignmentSource getAlignmentSource() const { return AlignSource; } void setAlignmentSource(AlignmentSource Source) { AlignSource = Source; } - bool getMayAlias() const { return MayAlias; } - void setMayAlias(bool Alias) { MayAlias = Alias; } void mergeForCast(const LValueBaseInfo &Info) { setAlignmentSource(Info.getAlignmentSource()); - setMayAlias(getMayAlias() || Info.getMayAlias()); } }; @@ -220,6 +216,7 @@ class LValue { bool ImpreciseLifetime : 1; LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; // This flag shows if a nontemporal load/stores should be used when accessing // this lvalue. @@ -227,18 +224,9 @@ class LValue { Expr *BaseIvarExp; - /// Used by struct-path-aware TBAA. - QualType TBAABaseType; - /// Offset relative to the base type. - uint64_t TBAAOffset; - - /// TBAAInfo - TBAA information to attach to dereferences of this LValue. - llvm::MDNode *TBAAInfo; - private: - void Initialize(QualType Type, Qualifiers Quals, - CharUnits Alignment, LValueBaseInfo BaseInfo, - llvm::MDNode *TBAAInfo = nullptr) { + void Initialize(QualType Type, Qualifiers Quals, CharUnits Alignment, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { assert((!Alignment.isZero() || Type->isIncompleteType()) && "initializing l-value with zero alignment!"); this->Type = Type; @@ -247,6 +235,7 @@ private: assert(this->Alignment == Alignment.getQuantity() && "Alignment exceeds allowed max!"); this->BaseInfo = BaseInfo; + this->TBAAInfo = TBAAInfo; // Initialize Objective-C flags. this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; @@ -254,11 +243,6 @@ private: this->Nontemporal = false; this->ThreadLocalRef = false; this->BaseIvarExp = nullptr; - - // Initialize fields for TBAA. - this->TBAABaseType = Type; - this->TBAAOffset = 0; - this->TBAAInfo = TBAAInfo; } public: @@ -318,19 +302,13 @@ public: Expr *getBaseIvarExp() const { return BaseIvarExp; } void setBaseIvarExp(Expr *V) { BaseIvarExp = V; } - QualType getTBAABaseType() const { return TBAABaseType; } - void setTBAABaseType(QualType T) { TBAABaseType = T; } - - uint64_t getTBAAOffset() const { return TBAAOffset; } - void setTBAAOffset(uint64_t O) { TBAAOffset = O; } - - llvm::MDNode *getTBAAInfo() const { return TBAAInfo; } - void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; } + TBAAAccessInfo getTBAAInfo() const { return TBAAInfo; } + void setTBAAInfo(TBAAAccessInfo Info) { TBAAInfo = Info; } const Qualifiers &getQuals() const { return Quals; } Qualifiers &getQuals() { return Quals; } - unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + LangAS getAddressSpace() const { return Quals.getAddressSpace(); } CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); } void setAlignment(CharUnits A) { Alignment = A.getQuantity(); } @@ -383,10 +361,8 @@ public: // global register lvalue llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; } - static LValue MakeAddr(Address address, QualType type, - ASTContext &Context, - LValueBaseInfo BaseInfo, - llvm::MDNode *TBAAInfo = nullptr) { + static LValue MakeAddr(Address address, QualType type, ASTContext &Context, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { Qualifiers qs = type.getQualifiers(); qs.setObjCGCAttr(Context.getObjCGCAttrKind(type)); @@ -399,24 +375,26 @@ public: } static LValue MakeVectorElt(Address vecAddress, llvm::Value *Idx, - QualType type, LValueBaseInfo BaseInfo) { + QualType type, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = VectorElt; R.V = vecAddress.getPointer(); R.VectorIdx = Idx; R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo); + BaseInfo, TBAAInfo); return R; } static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts, - QualType type, LValueBaseInfo BaseInfo) { + QualType type, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = ExtVectorElt; R.V = vecAddress.getPointer(); R.VectorElts = Elts; R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo); + BaseInfo, TBAAInfo); return R; } @@ -426,15 +404,15 @@ public: /// bit-field refers to. /// \param Info - The information describing how to perform the bit-field /// access. - static LValue MakeBitfield(Address Addr, - const CGBitFieldInfo &Info, - QualType type, - LValueBaseInfo BaseInfo) { + static LValue MakeBitfield(Address Addr, const CGBitFieldInfo &Info, + QualType type, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = BitField; R.V = Addr.getPointer(); R.BitFieldInfo = &Info; - R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo); + R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo, + TBAAInfo); return R; } @@ -443,7 +421,7 @@ public: R.LVType = GlobalReg; R.V = Reg.getPointer(); R.Initialize(type, type.getQualifiers(), Reg.getAlignment(), - LValueBaseInfo(AlignmentSource::Decl, false)); + LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo()); return R; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp index 0735a9c3dfbc1..c152291b15b93 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGen/CodeGenABITypes.h" +#include "CGRecordLayout.h" #include "CodeGenModule.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" @@ -80,3 +81,9 @@ llvm::Type * CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) { return CGM.getTypes().ConvertTypeForMem(T); } + +unsigned CodeGen::getLLVMFieldNumber(CodeGenModule &CGM, + const RecordDecl *RD, + const FieldDecl *FD) { + return CGM.getTypes().getCGRecordLayout(RD).getLLVMFieldNo(FD); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp index 4f03de55149b8..6ca69d63cdce7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp @@ -46,6 +46,38 @@ using namespace clang; using namespace llvm; namespace clang { + class BackendConsumer; + class ClangDiagnosticHandler final : public DiagnosticHandler { + public: + ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon) + : CodeGenOpts(CGOpts), BackendCon(BCon) {} + + bool handleDiagnostics(const DiagnosticInfo &DI) override; + + bool isAnalysisRemarkEnabled(StringRef PassName) const override { + return (CodeGenOpts.OptimizationRemarkAnalysisPattern && + CodeGenOpts.OptimizationRemarkAnalysisPattern->match(PassName)); + } + bool isMissedOptRemarkEnabled(StringRef PassName) const override { + return (CodeGenOpts.OptimizationRemarkMissedPattern && + CodeGenOpts.OptimizationRemarkMissedPattern->match(PassName)); + } + bool isPassedOptRemarkEnabled(StringRef PassName) const override { + return (CodeGenOpts.OptimizationRemarkPattern && + CodeGenOpts.OptimizationRemarkPattern->match(PassName)); + } + + bool isAnyRemarkEnabled() const override { + return (CodeGenOpts.OptimizationRemarkAnalysisPattern || + CodeGenOpts.OptimizationRemarkMissedPattern || + CodeGenOpts.OptimizationRemarkPattern); + } + + private: + const CodeGenOptions &CodeGenOpts; + BackendConsumer *BackendCon; + }; + class BackendConsumer : public ASTConsumer { using LinkModule = CodeGenAction::LinkModule; @@ -224,21 +256,20 @@ namespace clang { void *OldContext = Ctx.getInlineAsmDiagnosticContext(); Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this); - LLVMContext::DiagnosticHandlerTy OldDiagnosticHandler = + std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler = Ctx.getDiagnosticHandler(); - void *OldDiagnosticContext = Ctx.getDiagnosticContext(); - Ctx.setDiagnosticHandler(DiagnosticHandler, this); + Ctx.setDiagnosticHandler(llvm::make_unique<ClangDiagnosticHandler>( + CodeGenOpts, this)); Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness); if (CodeGenOpts.DiagnosticsHotnessThreshold != 0) Ctx.setDiagnosticsHotnessThreshold( CodeGenOpts.DiagnosticsHotnessThreshold); - std::unique_ptr<llvm::tool_output_file> OptRecordFile; + std::unique_ptr<llvm::ToolOutputFile> OptRecordFile; if (!CodeGenOpts.OptRecordFile.empty()) { std::error_code EC; - OptRecordFile = - llvm::make_unique<llvm::tool_output_file>(CodeGenOpts.OptRecordFile, - EC, sys::fs::F_None); + OptRecordFile = llvm::make_unique<llvm::ToolOutputFile>( + CodeGenOpts.OptRecordFile, EC, sys::fs::F_None); if (EC) { Diags.Report(diag::err_cannot_open_file) << CodeGenOpts.OptRecordFile << EC.message(); @@ -264,7 +295,7 @@ namespace clang { Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); - Ctx.setDiagnosticHandler(OldDiagnosticHandler, OldDiagnosticContext); + Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); if (OptRecordFile) OptRecordFile->keep(); @@ -299,11 +330,6 @@ namespace clang { ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); } - static void DiagnosticHandler(const llvm::DiagnosticInfo &DI, - void *Context) { - ((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI); - } - /// Get the best possible source location to represent a diagnostic that /// may have associated debug info. const FullSourceLoc @@ -343,6 +369,11 @@ namespace clang { void BackendConsumer::anchor() {} } +bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { + BackendCon->DiagnosticHandlerImpl(DI); + return true; +} + /// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr /// buffer to be a valid FullSourceLoc. static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, @@ -402,6 +433,8 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, case llvm::SourceMgr::DK_Note: DiagID = diag::note_fe_inline_asm; break; + case llvm::SourceMgr::DK_Remark: + llvm_unreachable("remarks unexpected"); } // If this problem has clang-level source location information, report the // issue in the source with a note showing the instantiated @@ -600,6 +633,10 @@ void BackendConsumer::EmitOptimizationMessage( void BackendConsumer::OptimizationRemarkHandler( const llvm::DiagnosticInfoOptimizationBase &D) { + // Without hotness information, don't show noisy remarks. + if (D.isVerbose() && !D.getHotness()) + return; + if (D.isPassed()) { // Optimization remarks are active only if the -Rpass flag has a regular // expression that matches the name of the pass name in \p D. @@ -884,6 +921,8 @@ static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM, case llvm::SourceMgr::DK_Note: DiagID = diag::note_fe_inline_asm; break; + case llvm::SourceMgr::DK_Remark: + llvm_unreachable("remarks unexpected"); } Diags->Report(DiagID).AddString("cannot compile inline asm"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp index c23b25ea461fe..9dbd7cc3fcbfb 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -33,9 +33,11 @@ #include "clang/Frontend/CodeGenOptions.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" +#include "llvm/Transforms/Utils/PromoteMemToReg.h" using namespace clang; using namespace CodeGen; @@ -87,7 +89,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) llvm::FastMathFlags FMF; if (CGM.getLangOpts().FastMath) - FMF.setUnsafeAlgebra(); + FMF.setFast(); if (CGM.getLangOpts().FiniteMathOnly) { FMF.setNoNaNs(); FMF.setNoInfs(); @@ -101,6 +103,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) if (CGM.getCodeGenOpts().ReciprocalMath) { FMF.setAllowReciprocal(); } + if (CGM.getCodeGenOpts().Reassociate) { + FMF.setAllowReassoc(); + } Builder.setFastMathFlags(FMF); } @@ -118,27 +123,32 @@ CodeGenFunction::~CodeGenFunction() { } CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, - LValueBaseInfo *BaseInfo) { - return getNaturalTypeAlignment(T->getPointeeType(), BaseInfo, - /*forPointee*/ true); + LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo) { + return getNaturalTypeAlignment(T->getPointeeType(), BaseInfo, TBAAInfo, + /* forPointeeType= */ true); } CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T, LValueBaseInfo *BaseInfo, + TBAAAccessInfo *TBAAInfo, bool forPointeeType) { + if (TBAAInfo) + *TBAAInfo = CGM.getTBAAAccessInfo(T); + // Honor alignment typedef attributes even on incomplete types. // We also honor them straight for C++ class types, even as pointees; // there's an expressivity gap here. if (auto TT = T->getAs<TypedefType>()) { if (auto Align = TT->getDecl()->getMaxAlignment()) { if (BaseInfo) - *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType, false); + *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType); return getContext().toCharUnitsFromBits(Align); } } if (BaseInfo) - *BaseInfo = LValueBaseInfo(AlignmentSource::Type, false); + *BaseInfo = LValueBaseInfo(AlignmentSource::Type); CharUnits Alignment; if (T->isIncompleteType()) { @@ -169,9 +179,10 @@ CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T, LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { LValueBaseInfo BaseInfo; - CharUnits Alignment = getNaturalTypeAlignment(T, &BaseInfo); + TBAAAccessInfo TBAAInfo; + CharUnits Alignment = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo); return LValue::MakeAddr(Address(V, Alignment), T, getContext(), BaseInfo, - CGM.getTBAAInfo(T)); + TBAAInfo); } /// Given a value of type T* that may not be to a complete object, @@ -179,8 +190,10 @@ LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { LValue CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) { LValueBaseInfo BaseInfo; - CharUnits Align = getNaturalTypeAlignment(T, &BaseInfo, /*pointee*/ true); - return MakeAddrLValue(Address(V, Align), T, BaseInfo); + TBAAAccessInfo TBAAInfo; + CharUnits Align = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, + /* forPointeeType= */ true); + return MakeAddrLValue(Address(V, Align), T, BaseInfo, TBAAInfo); } @@ -344,8 +357,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { // Emit function epilog (to return). llvm::DebugLoc Loc = EmitReturnBlock(); - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_exit"); + if (ShouldInstrumentFunction()) { + if (CGM.getCodeGenOpts().InstrumentFunctions) + CurFn->addFnAttr("instrument-function-exit", "__cyg_profile_func_exit"); + if (CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining) + CurFn->addFnAttr("instrument-function-exit-inlined", + "__cyg_profile_func_exit"); + } // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) @@ -411,12 +429,26 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { I->first->replaceAllUsesWith(I->second); I->first->eraseFromParent(); } + + // Eliminate CleanupDestSlot alloca by replacing it with SSA values and + // PHIs if the current function is a coroutine. We don't do it for all + // functions as it may result in slight increase in numbers of instructions + // if compiled with no optimizations. We do it for coroutine as the lifetime + // of CleanupDestSlot alloca make correct coroutine frame building very + // difficult. + if (NormalCleanupDest && isCoroutine()) { + llvm::DominatorTree DT(*CurFn); + llvm::PromoteMemToReg(NormalCleanupDest, DT); + NormalCleanupDest = nullptr; + } } /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls bool CodeGenFunction::ShouldInstrumentFunction() { - if (!CGM.getCodeGenOpts().InstrumentFunctions) + if (!CGM.getCodeGenOpts().InstrumentFunctions && + !CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining && + !CGM.getCodeGenOpts().InstrumentFunctionEntryBare) return false; if (!CurFuncDecl || CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) return false; @@ -429,29 +461,47 @@ bool CodeGenFunction::ShouldXRayInstrumentFunction() const { return CGM.getCodeGenOpts().XRayInstrumentFunctions; } -/// EmitFunctionInstrumentation - Emit LLVM code to call the specified -/// instrumentation function with the current function and the call site, if -/// function instrumentation is enabled. -void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { - auto NL = ApplyDebugLocation::CreateArtificial(*this); - // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); - llvm::PointerType *PointerTy = Int8PtrTy; - llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; - llvm::FunctionType *FunctionTy = - llvm::FunctionType::get(VoidTy, ProfileFuncArgs, false); +/// AlwaysEmitXRayCustomEvents - Return true if we should emit IR for calls to +/// the __xray_customevent(...) builin calls, when doing XRay instrumentation. +bool CodeGenFunction::AlwaysEmitXRayCustomEvents() const { + return CGM.getCodeGenOpts().XRayAlwaysEmitCustomEvents; +} - llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn); - llvm::CallInst *CallSite = Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::returnaddress), - llvm::ConstantInt::get(Int32Ty, 0), - "callsite"); +llvm::Constant * +CodeGenFunction::EncodeAddrForUseInPrologue(llvm::Function *F, + llvm::Constant *Addr) { + // Addresses stored in prologue data can't require run-time fixups and must + // be PC-relative. Run-time fixups are undesirable because they necessitate + // writable text segments, which are unsafe. And absolute addresses are + // undesirable because they break PIE mode. - llvm::Value *args[] = { - llvm::ConstantExpr::getBitCast(CurFn, PointerTy), - CallSite - }; + // Add a layer of indirection through a private global. Taking its address + // won't result in a run-time fixup, even if Addr has linkonce_odr linkage. + auto *GV = new llvm::GlobalVariable(CGM.getModule(), Addr->getType(), + /*isConstant=*/true, + llvm::GlobalValue::PrivateLinkage, Addr); - EmitNounwindRuntimeCall(F, args); + // Create a PC-relative address. + auto *GOTAsInt = llvm::ConstantExpr::getPtrToInt(GV, IntPtrTy); + auto *FuncAsInt = llvm::ConstantExpr::getPtrToInt(F, IntPtrTy); + auto *PCRelAsInt = llvm::ConstantExpr::getSub(GOTAsInt, FuncAsInt); + return (IntPtrTy == Int32Ty) + ? PCRelAsInt + : llvm::ConstantExpr::getTrunc(PCRelAsInt, Int32Ty); +} + +llvm::Value * +CodeGenFunction::DecodeAddrUsedInPrologue(llvm::Value *F, + llvm::Value *EncodedAddr) { + // Reconstruct the address of the global. + auto *PCRelAsInt = Builder.CreateSExt(EncodedAddr, IntPtrTy); + auto *FuncAsInt = Builder.CreatePtrToInt(F, IntPtrTy, "func_addr.int"); + auto *GOTAsInt = Builder.CreateAdd(PCRelAsInt, FuncAsInt, "global_addr.int"); + auto *GOTAddr = Builder.CreateIntToPtr(GOTAsInt, Int8PtrPtrTy, "global_addr"); + + // Load the original pointer through the global. + return Builder.CreateLoad(Address(GOTAddr, getPointerAlign()), + "decoded_addr"); } static void removeImageAccessQualifier(std::string& TyName) { @@ -480,8 +530,8 @@ static void removeImageAccessQualifier(std::string& TyName) { // for example in clGetKernelArgInfo() implementation between the address // spaces with targets without unique mapping to the OpenCL address spaces // (basically all single AS CPUs). -static unsigned ArgInfoAddressSpace(unsigned LangAS) { - switch (LangAS) { +static unsigned ArgInfoAddressSpace(LangAS AS) { + switch (AS) { case LangAS::opencl_global: return 1; case LangAS::opencl_constant: return 2; case LangAS::opencl_local: return 3; @@ -621,7 +671,10 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, // Get image and pipe access qualifier: if (ty->isImageType()|| ty->isPipeType()) { - const OpenCLAccessAttr *A = parm->getAttr<OpenCLAccessAttr>(); + const Decl *PDecl = parm; + if (auto *TD = dyn_cast<TypedefType>(ty)) + PDecl = TD->getDecl(); + const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>(); if (A && A->isWriteOnly()) accessQuals.push_back(llvm::MDString::get(Context, "write_only")); else if (A && A->isReadWrite()) @@ -721,6 +774,35 @@ static void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) { Fn->removeFnAttr(llvm::Attribute::SanitizeThread); } +static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) { + auto *MD = dyn_cast_or_null<CXXMethodDecl>(D); + if (!MD || !MD->getDeclName().getAsIdentifierInfo() || + !MD->getDeclName().getAsIdentifierInfo()->isStr("allocate") || + (MD->getNumParams() != 1 && MD->getNumParams() != 2)) + return false; + + if (MD->parameters()[0]->getType().getCanonicalType() != Ctx.getSizeType()) + return false; + + if (MD->getNumParams() == 2) { + auto *PT = MD->parameters()[1]->getType()->getAs<PointerType>(); + if (!PT || !PT->isVoidPointerType() || + !PT->getPointeeType().isConstQualified()) + return false; + } + + return true; +} + +/// Return the UBSan prologue signature for \p FD if one is available. +static llvm::Constant *getPrologueSignature(CodeGenModule &CGM, + const FunctionDecl *FD) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) + if (!MD->isStatic()) + return nullptr; + return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); +} + void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, @@ -744,8 +826,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, CurFnInfo = &FnInfo; assert(CurFn->isDeclaration() && "Function already has body?"); - if (CGM.isInSanitizerBlacklist(Fn, Loc)) - SanOpts.clear(); + // If this function has been blacklisted for any of the enabled sanitizers, + // disable the sanitizer for the function. + do { +#define SANITIZER(NAME, ID) \ + if (SanOpts.empty()) \ + break; \ + if (SanOpts.has(SanitizerKind::ID)) \ + if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc)) \ + SanOpts.set(SanitizerKind::ID, false); + +#include "clang/Basic/Sanitizers.def" +#undef SANITIZER + } while (0); if (D) { // Apply the no_sanitize* attributes to SanOpts. @@ -756,6 +849,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, // Apply sanitizer attributes to the function. if (SanOpts.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress)) Fn->addFnAttr(llvm::Attribute::SanitizeAddress); + if (SanOpts.hasOneOf(SanitizerKind::HWAddress)) + Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress); if (SanOpts.has(SanitizerKind::Thread)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); if (SanOpts.has(SanitizerKind::Memory)) @@ -780,6 +875,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, } } + // Ignore unrelated casts in STL allocate() since the allocator must cast + // from void* to T* before object initialization completes. Don't match on the + // namespace because not all allocators are in std:: + if (D && SanOpts.has(SanitizerKind::CFIUnrelatedCast)) { + if (matchesStlAllocatorFn(D, getContext())) + SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast; + } + // Apply xray attributes to the function (as a string, for now) if (D && ShouldXRayInstrumentFunction()) { if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) { @@ -799,14 +902,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, } } - if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) - if (CGM.getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>()) - CGM.getOpenMPRuntime().emitDeclareSimdFunction(FD, Fn); - // Add no-jump-tables value. Fn->addFnAttr("no-jump-tables", llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables)); + // Add profile-sample-accurate value. + if (CGM.getCodeGenOpts().ProfileSampleAccurate) + Fn->addFnAttr("profile-sample-accurate"); + if (getLangOpts().OpenCL) { // Add metadata for a kernel function. if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) @@ -817,11 +920,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, // prologue data. if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function)) { if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { - if (llvm::Constant *PrologueSig = - CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) { + if (llvm::Constant *PrologueSig = getPrologueSignature(CGM, FD)) { llvm::Constant *FTRTTIConst = CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true); - llvm::Constant *PrologueStructElems[] = { PrologueSig, FTRTTIConst }; + llvm::Constant *FTRTTIConstEncoded = + EncodeAddrForUseInPrologue(Fn, FTRTTIConst); + llvm::Constant *PrologueStructElems[] = {PrologueSig, + FTRTTIConstEncoded}; llvm::Constant *PrologueStructConst = llvm::ConstantStruct::getAnon(PrologueStructElems, /*Packed=*/true); Fn->setPrologueData(PrologueStructConst); @@ -885,8 +990,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder); } - if (ShouldInstrumentFunction()) - EmitFunctionInstrumentation("__cyg_profile_func_enter"); + if (ShouldInstrumentFunction()) { + if (CGM.getCodeGenOpts().InstrumentFunctions) + CurFn->addFnAttr("instrument-function-entry", "__cyg_profile_func_enter"); + if (CGM.getCodeGenOpts().InstrumentFunctionsAfterInlining) + CurFn->addFnAttr("instrument-function-entry-inlined", + "__cyg_profile_func_enter"); + if (CGM.getCodeGenOpts().InstrumentFunctionEntryBare) + CurFn->addFnAttr("instrument-function-entry-inlined", + "__cyg_profile_func_enter_bare"); + } // Since emitting the mcount call here impacts optimizations such as function // inlining, we just add an attribute to insert a mcount call in backend. @@ -896,8 +1009,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, if (CGM.getCodeGenOpts().CallFEntry) Fn->addFnAttr("fentry-call", "true"); else { - if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) - Fn->addFnAttr("counting-function", getTarget().getMCountName()); + if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) { + Fn->addFnAttr("instrument-function-entry-inlined", + getTarget().getMCountName()); + } } } @@ -1185,16 +1300,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, !getLangOpts().CUDAIsDevice && FD->hasAttr<CUDAGlobalAttr>()) CGM.getCUDARuntime().emitDeviceStub(*this, Args); - else if (isa<CXXConversionDecl>(FD) && - cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion()) { - // The lambda conversion to block pointer is special; the semantics can't be - // expressed in the AST, so IRGen needs to special-case it. - EmitLambdaToBlockPointerBody(Args); - } else if (isa<CXXMethodDecl>(FD) && - cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) { + else if (isa<CXXMethodDecl>(FD) && + cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) { // The lambda static invoker function is special, because it forwards or // clones the body of the function call operator (but is actually static). - EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD)); + EmitLambdaStaticInvokeBody(cast<CXXMethodDecl>(FD)); } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) && (cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() || cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator())) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index 6a1fa487ed14f..ab5bbc03db955 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -76,6 +76,10 @@ class ObjCAtThrowStmt; class ObjCAtSynchronizedStmt; class ObjCAutoreleasePoolStmt; +namespace analyze_os_log { +class OSLogBufferLayout; +} + namespace CodeGen { class CodeGenTypes; class CGCallee; @@ -111,6 +115,7 @@ enum TypeEvaluationKind { SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0) \ SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0) \ SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0) \ + SANITIZER_CHECK(InvalidBuiltin, invalid_builtin, 0) \ SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0) \ SANITIZER_CHECK(MissingReturn, missing_return, 0) \ SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \ @@ -220,6 +225,10 @@ public: }; CGCoroInfo CurCoro; + bool isCoroutine() const { + return CurCoro.Data != nullptr; + } + /// CurGD - The GlobalDecl for the current function being compiled. GlobalDecl CurGD; @@ -262,9 +271,9 @@ public: if (I->capturesThis()) CXXThisFieldDecl = *Field; else if (I->capturesVariable()) - CaptureFields[I->getCapturedVar()] = *Field; + CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field; else if (I->capturesVariableByCopy()) - CaptureFields[I->getCapturedVar()] = *Field; + CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field; } } @@ -278,7 +287,7 @@ public: /// \brief Lookup the captured field decl for a variable. virtual const FieldDecl *lookup(const VarDecl *VD) const { - return CaptureFields.lookup(VD); + return CaptureFields.lookup(VD->getCanonicalDecl()); } bool isCXXThisExprCaptured() const { return getThisFieldDecl() != nullptr; } @@ -708,6 +717,7 @@ public: llvm::function_ref<Address()> PrivateGen) { assert(PerformCleanup && "adding private to dead scope"); + LocalVD = LocalVD->getCanonicalDecl(); // Only save it once. if (SavedLocals.count(LocalVD)) return false; @@ -758,8 +768,9 @@ public: ForceCleanup(); } - /// Checks if the global variable is captured in current function. + /// Checks if the global variable is captured in current function. bool isGlobalVarCaptured(const VarDecl *VD) const { + VD = VD->getCanonicalDecl(); return !VD->isLocalVarDeclOrParm() && CGF.LocalDeclMap.count(VD) > 0; } @@ -819,7 +830,7 @@ public: /// block through the normal cleanup handling code (if any) and then /// on to \arg Dest. void EmitBranchThroughCleanup(JumpDest Dest); - + /// isObviouslyBranchWithoutCleanups - Return true if a branch to the /// specified destination obviously has no cleanups to run. 'false' is always /// a conservatively correct answer for this method. @@ -1038,7 +1049,7 @@ public: if (Data.isValid()) Data.unbind(CGF); } }; - + private: CGDebugInfo *DebugInfo; bool DisableDebugInfo; @@ -1156,19 +1167,6 @@ private: }; OpenMPCancelExitStack OMPCancelStack; - /// Controls insertion of cancellation exit blocks in worksharing constructs. - class OMPCancelStackRAII { - CodeGenFunction &CGF; - - public: - OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, - bool HasCancel) - : CGF(CGF) { - CGF.OMPCancelStack.enter(CGF, Kind, HasCancel); - } - ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); } - }; - CodeGenPGO PGO; /// Calculate branch weights appropriate for PGO data @@ -1427,7 +1425,7 @@ private: /// Add OpenCL kernel arg metadata and the kernel attribute meatadata to /// the function metadata. - void EmitOpenCLKernelMetadata(const FunctionDecl *FD, + void EmitOpenCLKernelMetadata(const FunctionDecl *FD, llvm::Function *Fn); public: @@ -1436,10 +1434,10 @@ public: CodeGenTypes &getTypes() const { return CGM.getTypes(); } ASTContext &getContext() const { return CGM.getContext(); } - CGDebugInfo *getDebugInfo() { - if (DisableDebugInfo) + CGDebugInfo *getDebugInfo() { + if (DisableDebugInfo) return nullptr; - return DebugInfo; + return DebugInfo; } void disableDebugInfo() { DisableDebugInfo = true; } void enableDebugInfo() { DisableDebugInfo = false; } @@ -1577,13 +1575,21 @@ public: // Block Bits //===--------------------------------------------------------------------===// - llvm::Value *EmitBlockLiteral(const BlockExpr *); + /// Emit block literal. + /// \return an LLVM value which is a pointer to a struct which contains + /// information about the block, including the block invoke function, the + /// captured variables, etc. + /// \param InvokeF will contain the block invoke function if it is not + /// nullptr. + llvm::Value *EmitBlockLiteral(const BlockExpr *, + llvm::Function **InvokeF = nullptr); static void destroyBlockInfos(CGBlockInfo *info); llvm::Function *GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &Info, const DeclMapTy &ldm, - bool IsLambdaConversionToBlock); + bool IsLambdaConversionToBlock, + bool BuildGlobalBlock); llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo); llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo); @@ -1642,10 +1648,9 @@ public: void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator, CallArgList &CallArgs); - void EmitLambdaToBlockPointerBody(FunctionArgList &Args); void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); - void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD); + void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD); void EmitAsanPrologueOrEpilogue(bool Prologue); /// \brief Emit the unified return block, trying to avoid its emission when @@ -1766,13 +1771,18 @@ public: /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; - /// EmitFunctionInstrumentation - Emit LLVM code to call the specified - /// instrumentation function with the current function and the call site, if - /// function instrumentation is enabled. - void EmitFunctionInstrumentation(const char *Fn); + /// AlwaysEmitXRayCustomEvents - Return true if we must unconditionally emit + /// XRay custom event handling calls. + bool AlwaysEmitXRayCustomEvents() const; + + /// Encode an address into a form suitable for use in a function prologue. + llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F, + llvm::Constant *Addr); - /// EmitMCountInstrumentation - Emit call to .mcount. - void EmitMCountInstrumentation(); + /// Decode an address used in a function prologue, encoded by \c + /// EncodeAddrForUseInPrologue. + llvm::Value *DecodeAddrUsedInPrologue(llvm::Value *F, + llvm::Value *EncodedAddr); /// EmitFunctionProlog - Emit the target specific LLVM code to load the /// arguments for the given function. This is also responsible for naming the @@ -1816,8 +1826,7 @@ public: /// TypeOfSelfObject - Return type of object that this self represents. QualType TypeOfSelfObject(); - /// hasAggregateLLVMType - Return true if the specified AST type will map into - /// an aggregate LLVM type or is void. + /// getEvaluationKind - Return the TypeEvaluationKind of QualType \c T. static TypeEvaluationKind getEvaluationKind(QualType T); static bool hasScalarEvaluationKind(QualType T) { @@ -1896,33 +1905,53 @@ public: //===--------------------------------------------------------------------===// LValue MakeAddrLValue(Address Addr, QualType T, - LValueBaseInfo BaseInfo = - LValueBaseInfo(AlignmentSource::Type)) { - return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, - CGM.getTBAAInfo(T)); + AlignmentSource Source = AlignmentSource::Type) { + return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(T)); + } + + LValue MakeAddrLValue(Address Addr, QualType T, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo) { + return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, TBAAInfo); } LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, - LValueBaseInfo BaseInfo = - LValueBaseInfo(AlignmentSource::Type)) { + AlignmentSource Source = AlignmentSource::Type) { return LValue::MakeAddr(Address(V, Alignment), T, getContext(), - BaseInfo, CGM.getTBAAInfo(T)); + LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T)); + } + + LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { + return LValue::MakeAddr(Address(V, Alignment), T, getContext(), + BaseInfo, TBAAInfo); } LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T); LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); CharUnits getNaturalTypeAlignment(QualType T, LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr, bool forPointeeType = false); CharUnits getNaturalPointeeTypeAlignment(QualType T, - LValueBaseInfo *BaseInfo = nullptr); + LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr); - Address EmitLoadOfReference(Address Ref, const ReferenceType *RefTy, - LValueBaseInfo *BaseInfo = nullptr); - LValue EmitLoadOfReferenceLValue(Address Ref, const ReferenceType *RefTy); + Address EmitLoadOfReference(LValue RefLVal, + LValueBaseInfo *PointeeBaseInfo = nullptr, + TBAAAccessInfo *PointeeTBAAInfo = nullptr); + LValue EmitLoadOfReferenceLValue(LValue RefLVal); + LValue EmitLoadOfReferenceLValue(Address RefAddr, QualType RefTy, + AlignmentSource Source = + AlignmentSource::Type) { + LValue RefLVal = MakeAddrLValue(RefAddr, RefTy, LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(RefTy)); + return EmitLoadOfReferenceLValue(RefLVal); + } Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy, - LValueBaseInfo *BaseInfo = nullptr); + LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); /// CreateTempAlloca - This creates an alloca and inserts it into the entry @@ -2345,6 +2374,12 @@ public: TCK_NonnullAssign }; + /// Determine whether the pointer type check \p TCK permits null pointers. + static bool isNullPointerAllowed(TypeCheckKind TCK); + + /// Determine whether the pointer type check \p TCK requires a vptr check. + static bool isVptrCheckRequired(TypeCheckKind TCK, QualType Ty); + /// \brief Whether any type-checking sanitizers are enabled. If \c false, /// calls to EmitTypeCheck can be skipped. bool sanitizePerformTypeCheck() const; @@ -2464,7 +2499,7 @@ public: }; AutoVarEmission EmitAutoVarAlloca(const VarDecl &var); void EmitAutoVarInit(const AutoVarEmission &emission); - void EmitAutoVarCleanups(const AutoVarEmission &emission); + void EmitAutoVarCleanups(const AutoVarEmission &emission); void emitAutoVarTypeCleanup(const AutoVarEmission &emission, QualType::DestructionKind dtorKind); @@ -2486,7 +2521,7 @@ public: bool isIndirect() const { return Alignment != 0; } llvm::Value *getAnyValue() const { return Value; } - + llvm::Value *getDirectValue() const { assert(!isIndirect()); return Value; @@ -2532,7 +2567,7 @@ public: /// This function may clear the current insertion point; callers should use /// EnsureInsertPoint if they wish to subsequently generate code without first /// calling EmitBlock, EmitBranch, or EmitStmt. - void EmitStmt(const Stmt *S); + void EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs = None); /// EmitSimpleStmt - Try to emit a "simple" statement which does not /// necessarily require an insertion point or debug information; typically @@ -2635,6 +2670,19 @@ public: void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef<const Attr *> Attrs = None); + /// Controls insertion of cancellation exit blocks in worksharing constructs. + class OMPCancelStackRAII { + CodeGenFunction &CGF; + + public: + OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, + bool HasCancel) + : CGF(CGF) { + CGF.OMPCancelStack.enter(CGF, Kind, HasCancel); + } + ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); } + }; + /// Returns calculated size of the specified type. llvm::Value *getTypeSize(QualType Ty); LValue InitCapturedStruct(const CapturedStmt &S); @@ -2841,9 +2889,30 @@ public: static void EmitOMPTargetParallelDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetParallelDirective &S); + /// Emit device code for the target parallel for directive. + static void EmitOMPTargetParallelForDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetParallelForDirective &S); + /// Emit device code for the target parallel for simd directive. + static void EmitOMPTargetParallelForSimdDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetParallelForSimdDirective &S); + /// Emit device code for the target teams directive. static void EmitOMPTargetTeamsDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDirective &S); + /// Emit device code for the target teams distribute directive. + static void EmitOMPTargetTeamsDistributeDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetTeamsDistributeDirective &S); + /// Emit device code for the target teams distribute simd directive. + static void EmitOMPTargetTeamsDistributeSimdDeviceFunction( + CodeGenModule &CGM, StringRef ParentName, + const OMPTargetTeamsDistributeSimdDirective &S); + /// Emit device code for the target simd directive. + static void EmitOMPTargetSimdDeviceFunction(CodeGenModule &CGM, + StringRef ParentName, + const OMPTargetSimdDirective &S); /// \brief Emit inner loop of the worksharing/simd construct. /// /// \param S Directive, for which the inner loop must be emitted. @@ -2875,9 +2944,9 @@ public: const CodeGenLoopBoundsTy &CodeGenLoopBounds, const CodeGenDispatchBoundsTy &CGDispatchBounds); -private: - /// Helpers for blocks - llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info); + /// Emit code for the distribute loop-based directive. + void EmitOMPDistributeLoop(const OMPLoopDirective &S, + const CodeGenLoopTy &CodeGenLoop, Expr *IncExpr); /// Helpers for the OpenMP loop directives. void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false); @@ -2885,8 +2954,15 @@ private: const OMPLoopDirective &D, const llvm::function_ref<llvm::Value *(CodeGenFunction &)> &CondGen); - void EmitOMPDistributeLoop(const OMPLoopDirective &S, - const CodeGenLoopTy &CodeGenLoop, Expr *IncExpr); + /// Emits the lvalue for the expression with possibly captured variable. + LValue EmitOMPSharedLValue(const Expr *E); + +private: + /// Helpers for blocks. Returns invoke function by \p InvokeF if it is not + /// nullptr. It should be called without \p InvokeF if the caller does not + /// need invoke function to be returned. + llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info, + llvm::Function **InvokeF = nullptr); /// struct with the values to be passed to the OpenMP loop-related functions struct OMPLoopArguments { @@ -3034,11 +3110,15 @@ public: /// the LLVM value representation. llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, SourceLocation Loc, - LValueBaseInfo BaseInfo = - LValueBaseInfo(AlignmentSource::Type), - llvm::MDNode *TBAAInfo = nullptr, - QualType TBAABaseTy = QualType(), - uint64_t TBAAOffset = 0, + AlignmentSource Source = AlignmentSource::Type, + bool isNontemporal = false) { + return EmitLoadOfScalar(Addr, Volatile, Ty, Loc, LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(Ty), isNontemporal); + } + + llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, + SourceLocation Loc, LValueBaseInfo BaseInfo, + TBAAAccessInfo TBAAInfo, bool isNontemporal = false); /// EmitLoadOfScalar - Load a scalar value from an address, taking @@ -3052,11 +3132,16 @@ public: /// the LLVM value representation. void EmitStoreOfScalar(llvm::Value *Value, Address Addr, bool Volatile, QualType Ty, - LValueBaseInfo BaseInfo = - LValueBaseInfo(AlignmentSource::Type), - llvm::MDNode *TBAAInfo = nullptr, bool isInit = false, - QualType TBAABaseTy = QualType(), - uint64_t TBAAOffset = 0, bool isNontemporal = false); + AlignmentSource Source = AlignmentSource::Type, + bool isInit = false, bool isNontemporal = false) { + EmitStoreOfScalar(Value, Addr, Volatile, Ty, LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(Ty), isInit, isNontemporal); + } + + void EmitStoreOfScalar(llvm::Value *Value, Address Addr, + bool Volatile, QualType Ty, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, + bool isInit = false, bool isNontemporal = false); /// EmitStoreOfScalar - Store a scalar value to an address, taking /// care to appropriately convert from the memory representation to @@ -3120,13 +3205,14 @@ public: LValue EmitCastLValue(const CastExpr *E); LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); - + Address EmitExtVectorElementLValue(LValue V); RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc); Address EmitArrayToPointerDecay(const Expr *Array, - LValueBaseInfo *BaseInfo = nullptr); + LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr); class ConstantEmission { llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference; @@ -3159,6 +3245,7 @@ public: }; ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); + ConstantEmission tryEmitAsConstant(const MemberExpr *ME); RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e, AggValueSlot slot = AggValueSlot::ignored()); @@ -3235,12 +3322,12 @@ public: void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef<llvm::Value*> args); - CGCallee BuildAppleKextVirtualCall(const CXXMethodDecl *MD, + CGCallee BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier *Qual, llvm::Type *Ty); - + CGCallee BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD, - CXXDtorType Type, + CXXDtorType Type, const CXXRecordDecl *RD); RValue @@ -3267,7 +3354,8 @@ public: Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base, llvm::Value *memberPtr, const MemberPointerType *memberPtrType, - LValueBaseInfo *BaseInfo = nullptr); + LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr); RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, ReturnValueSlot ReturnValue); @@ -3286,6 +3374,13 @@ public: unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + /// Emit IR for __builtin_os_log_format. + RValue emitBuiltinOSLogFormat(const CallExpr &E); + + llvm::Function *generateBuiltinOSLogHelperFunction( + const analyze_os_log::OSLogBufferLayout &Layout, + CharUnits BufferAlignment); + RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call @@ -3329,6 +3424,7 @@ public: llvm::Value *EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E); private: enum class MSVCIntrin; @@ -3406,11 +3502,11 @@ public: static Destroyer destroyARCWeak; static Destroyer emitARCIntrinsicUse; - void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); + void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); llvm::Value *EmitObjCAutoreleasePoolPush(); llvm::Value *EmitObjCMRRAutoreleasePoolPush(); void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr); - void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr); + void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr); /// \brief Emits a reference binding to the passed in expression. RValue EmitReferenceBindingToExpr(const Expr *E); @@ -3498,6 +3594,14 @@ public: void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); + enum class GuardKind { VariableGuard, TlsGuard }; + + /// Emit a branch to select whether or not to perform guarded initialization. + void EmitCXXGuardedInitBranch(llvm::Value *NeedsInit, + llvm::BasicBlock *InitBlock, + llvm::BasicBlock *NoInitBlock, + GuardKind Kind, const VarDecl *D); + /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. void GenerateCXXGlobalInitFunc(llvm::Function *Fn, @@ -3517,7 +3621,7 @@ public: bool PerformInit); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); - + void EmitSynthesizedCXXCopyCtor(Address Dest, Address Src, const Expr *Exp); void enterFullExpression(const ExprWithCleanups *E) { @@ -3566,7 +3670,7 @@ public: /// Determine if the given statement might introduce a declaration into the /// current scope, by being a (possibly-labelled) DeclStmt. static bool mightAddDeclToScope(const Stmt *S); - + /// ConstantFoldsToSimpleInteger - If the specified expression does not fold /// to a constant, or if it does but contains a label, return false. If it /// constant folds return true and set the boolean result in Result. @@ -3607,6 +3711,17 @@ public: SourceLocation Loc, const Twine &Name = ""); + /// Specifies which type of sanitizer check to apply when handling a + /// particular builtin. + enum BuiltinCheckKind { + BCK_CTZPassedZero, + BCK_CLZPassedZero, + }; + + /// Emits an argument for a call to a builtin. If the builtin sanitizer is + /// enabled, a runtime check specified by \p Kind is also emitted. + llvm::Value *EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind); + /// \brief Emit a description of a type in a format suitable for passing to /// a runtime sanitizer handler. llvm::Constant *EmitCheckTypeDescriptor(QualType T); @@ -3820,7 +3935,13 @@ public: /// reasonable to just ignore the returned alignment when it isn't from an /// explicit source. Address EmitPointerWithAlignment(const Expr *Addr, - LValueBaseInfo *BaseInfo = nullptr); + LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr); + + /// If \p E references a parameter with pass_object_size info or a constant + /// array size modifier, emit the object size divided by the size of \p EltTy. + /// Otherwise return null. + llvm::Value *LoadPassedObjectSize(const Expr *E, QualType EltTy); void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK); @@ -3835,6 +3956,11 @@ private: void AddObjCARCExceptionMetadata(llvm::Instruction *Inst); llvm::Value *GetValueForARMHint(unsigned BuiltinID); + llvm::Value *EmitX86CpuIs(const CallExpr *E); + llvm::Value *EmitX86CpuIs(StringRef CPUStr); + llvm::Value *EmitX86CpuSupports(const CallExpr *E); + llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs); + llvm::Value *EmitX86CpuInit(); }; /// Helper class with most of the code for saving a value for a diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index 5561d4520cc85..c59dc71da5960 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -23,7 +23,7 @@ #include "CGOpenMPRuntimeNVPTX.h" #include "CodeGenFunction.h" #include "CodeGenPGO.h" -#include "CodeGenTBAA.h" +#include "ConstantEmitter.h" #include "CoverageMappingGen.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -60,6 +60,11 @@ using namespace clang; using namespace CodeGen; +static llvm::cl::opt<bool> LimitedCoverage( + "limited-coverage-experimental", llvm::cl::ZeroOrMore, llvm::cl::Hidden, + llvm::cl::desc("Emit limited coverage mapping information (experimental)"), + llvm::cl::init(false)); + static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI *createCXXABI(CodeGenModule &CGM) { @@ -131,7 +136,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. if (LangOpts.Sanitize.has(SanitizerKind::Thread) || (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)) - TBAA.reset(new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(), + TBAA.reset(new CodeGenTBAA(Context, TheModule, CodeGenOpts, getLangOpts(), getCXXABI().getMangleContext())); // If debug info or coverage generation is enabled, create the CGDebugInfo @@ -436,7 +441,7 @@ void CodeGenModule::Release() { if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters", CodeGenOpts.NumRegisterParameters); - + if (CodeGenOpts.DwarfVersion) { // We actually want the latest version when there are conflicts. // We can change from Warning to Latest if such mode is supported. @@ -470,17 +475,11 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION); - // Width of wchar_t in bytes - uint64_t WCharWidth = - Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity(); - assert((LangOpts.ShortWChar || - llvm::TargetLibraryInfoImpl::getTargetWCharSize(Target.getTriple()) == - Target.getWCharWidth() / 8) && - "LLVM wchar_t size out of sync"); - // We need to record the widths of enums and wchar_t, so that we can generate // the correct build attributes in the ARM backend. wchar_size is also used by // TargetLibraryInfo. + uint64_t WCharWidth = + Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity(); getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth); llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); @@ -573,16 +572,27 @@ void CodeGenModule::RefreshTypeCacheForClass(const CXXRecordDecl *RD) { Types.RefreshTypeCacheForClass(RD); } -llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) { +llvm::MDNode *CodeGenModule::getTBAATypeInfo(QualType QTy) { if (!TBAA) return nullptr; - return TBAA->getTBAAInfo(QTy); + return TBAA->getTypeInfo(QTy); } -llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() { +TBAAAccessInfo CodeGenModule::getTBAAAccessInfo(QualType AccessType) { + // Pointee values may have incomplete types, but they shall never be + // dereferenced. + if (AccessType->isIncompleteType()) + return TBAAAccessInfo::getIncompleteInfo(); + + uint64_t Size = Context.getTypeSizeInChars(AccessType).getQuantity(); + return TBAAAccessInfo(getTBAATypeInfo(AccessType), Size); +} + +TBAAAccessInfo +CodeGenModule::getTBAAVTablePtrAccessInfo(llvm::Type *VTablePtrType) { if (!TBAA) - return nullptr; - return TBAA->getTBAAInfoForVTablePtr(); + return TBAAAccessInfo(); + return TBAA->getVTablePtrAccessInfo(VTablePtrType); } llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { @@ -591,26 +601,37 @@ llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { return TBAA->getTBAAStructInfo(QTy); } -llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy, - llvm::MDNode *AccessN, - uint64_t O) { +llvm::MDNode *CodeGenModule::getTBAABaseTypeInfo(QualType QTy) { + if (!TBAA) + return nullptr; + return TBAA->getBaseTypeInfo(QTy); +} + +llvm::MDNode *CodeGenModule::getTBAAAccessTagInfo(TBAAAccessInfo Info) { if (!TBAA) return nullptr; - return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O); + return TBAA->getAccessTagInfo(Info); +} + +TBAAAccessInfo CodeGenModule::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, + TBAAAccessInfo TargetInfo) { + if (!TBAA) + return TBAAAccessInfo(); + return TBAA->mergeTBAAInfoForCast(SourceInfo, TargetInfo); +} + +TBAAAccessInfo +CodeGenModule::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA, + TBAAAccessInfo InfoB) { + if (!TBAA) + return TBAAAccessInfo(); + return TBAA->mergeTBAAInfoForConditionalOperator(InfoA, InfoB); } -/// Decorate the instruction with a TBAA tag. For both scalar TBAA -/// and struct-path aware TBAA, the tag has the same format: -/// base type, access type and offset. -/// When ConvertTypeToTag is true, we create a tag based on the scalar type. void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo, - bool ConvertTypeToTag) { - if (ConvertTypeToTag && TBAA) - Inst->setMetadata(llvm::LLVMContext::MD_tbaa, - TBAA->getTBAAScalarTagInfo(TBAAInfo)); - else - Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); + TBAAAccessInfo TBAAInfo) { + if (llvm::MDNode *Tag = getTBAAAccessTagInfo(TBAAInfo)) + Inst->setMetadata(llvm::LLVMContext::MD_tbaa, Tag); } void CodeGenModule::DecorateInstructionWithInvariantGroup( @@ -648,7 +669,8 @@ llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { } void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, - const NamedDecl *D) const { + const NamedDecl *D, + ForDefinition_t IsForDefinition) const { // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -657,7 +679,8 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, // Set visibility for definitions. LinkageInfo LV = D->getLinkageAndVisibility(); - if (LV.isVisibilityExplicit() || !GV->hasAvailableExternallyLinkage()) + if (LV.isVisibilityExplicit() || + (IsForDefinition && !GV->hasAvailableExternallyLinkage())) GV->setVisibility(GetLLVMVisibility(LV.getVisibility())); } @@ -712,9 +735,9 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) { } } - StringRef &FoundStr = MangledDeclNames[CanonicalGD]; - if (!FoundStr.empty()) - return FoundStr; + auto FoundName = MangledDeclNames.find(CanonicalGD); + if (FoundName != MangledDeclNames.end()) + return FoundName->second; const auto *ND = cast<NamedDecl>(GD.getDecl()); SmallString<256> Buffer; @@ -745,7 +768,7 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) { // Keep the first result in the case of a mangling collision. auto Result = Manglings.insert(std::make_pair(Str, GD)); - return FoundStr = Result.first->first(); + return MangledDeclNames[CanonicalGD] = Result.first->first(); } StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD, @@ -756,7 +779,7 @@ StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD, SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); if (!D) - MangleCtx.mangleGlobalBlock(BD, + MangleCtx.mangleGlobalBlock(BD, dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()), Out); else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out); @@ -1038,7 +1061,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) - setGlobalVisibility(GV, ND); + setGlobalVisibility(GV, ND, ForDefinition); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -1080,7 +1103,7 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D, GO->setSection(SA->getName()); } - getTargetCodeGenInfo().setTargetAttributes(D, GO, *this); + getTargetCodeGenInfo().setTargetAttributes(D, GO, *this, ForDefinition); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, @@ -1094,8 +1117,8 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, setNonAliasAttributes(D, F); } -static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, - const NamedDecl *ND) { +static void setLinkageForGV(llvm::GlobalValue *GV, + const NamedDecl *ND) { // Set linkage and visibility in case we never see a definition. LinkageInfo LV = ND->getLinkageAndVisibility(); if (!isExternallyVisible(LV.getLinkage())) { @@ -1111,10 +1134,6 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, // separate linkage types for this. GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } - - // Set visibility on a declaration only if it's explicit. - if (LV.isVisibilityExplicit()) - GV->setVisibility(CodeGenModule::GetLLVMVisibility(LV.getVisibility())); } } @@ -1138,6 +1157,7 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType()); F->addTypeMetadata(0, MD); + F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType())); // Emit a hash-based bit set entry for cross-DSO calls. if (CodeGenOpts.SanitizeCfiCrossDso) @@ -1147,7 +1167,9 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD, void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, - bool IsThunk) { + bool IsThunk, + ForDefinition_t IsForDefinition) { + if (llvm::Intrinsic::ID IID = F->getIntrinsicID()) { // If this is an intrinsic function, set the function's attributes // to the intrinsic's attributes. @@ -1157,8 +1179,13 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, const auto *FD = cast<FunctionDecl>(GD.getDecl()); - if (!IsIncompleteFunction) + if (!IsIncompleteFunction) { SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F); + // Setup target-specific attributes. + if (!IsForDefinition) + getTargetCodeGenInfo().setTargetAttributes(FD, F, *this, + NotForDefinition); + } // Add the Returned attribute for "this", except for iOS 5 and earlier // where substantial code, including the libstdc++ dylib, was compiled with @@ -1175,7 +1202,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, // Only a few attributes are set on declarations; these may later be // overridden by a definition. - setLinkageAndVisibilityForGV(F, FD); + setLinkageForGV(F, FD); + setGlobalVisibility(F, FD, NotForDefinition); if (FD->getAttr<PragmaClangTextSectionAttr>()) { F->addFnAttr("implicit-section-name"); @@ -1210,6 +1238,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, // is handled with better precision by the receiving DSO. if (!CodeGenOpts.SanitizeCfiCrossDso) CreateFunctionTypeMetadata(FD, F); + + if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>()) + getOpenMPRuntime().emitDeclareSimdFunction(FD, F); } void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) { @@ -1530,20 +1561,21 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D, Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation())); } -bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn, +bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind, + llvm::Function *Fn, SourceLocation Loc) const { const auto &SanitizerBL = getContext().getSanitizerBlacklist(); // Blacklist by function name. - if (SanitizerBL.isBlacklistedFunction(Fn->getName())) + if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName())) return true; // Blacklist by location. if (Loc.isValid()) - return SanitizerBL.isBlacklistedLocation(Loc); + return SanitizerBL.isBlacklistedLocation(Kind, Loc); // If location is unknown, this may be a compiler-generated function. Assume // it's located in the main file. auto &SM = Context.getSourceManager(); if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - return SanitizerBL.isBlacklistedFile(MainFile->getName()); + return SanitizerBL.isBlacklistedFile(Kind, MainFile->getName()); } return false; } @@ -1552,13 +1584,14 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, StringRef Category) const { // For now globals can be blacklisted only in ASan and KASan. - if (!LangOpts.Sanitize.hasOneOf( - SanitizerKind::Address | SanitizerKind::KernelAddress)) + const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask & + (SanitizerKind::Address | SanitizerKind::KernelAddress | SanitizerKind::HWAddress); + if (!EnabledAsanMask) return false; const auto &SanitizerBL = getContext().getSanitizerBlacklist(); - if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category)) + if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category)) return true; - if (SanitizerBL.isBlacklistedLocation(Loc, Category)) + if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category)) return true; // Check global type. if (!Ty.isNull()) { @@ -1570,7 +1603,7 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV, // We allow to blacklist only record types (classes, structs etc.) if (Ty->isRecordType()) { std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy()); - if (SanitizerBL.isBlacklistedType(TypeStr, Category)) + if (SanitizerBL.isBlacklistedType(EnabledAsanMask, TypeStr, Category)) return true; } } @@ -1986,12 +2019,12 @@ bool CodeGenModule::shouldOpportunisticallyEmitVTables() { void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast<ValueDecl>(GD.getDecl()); - PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(), + PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); - + if (isa<FunctionDecl>(D)) { - // At -O0, don't generate IR for functions with available_externally + // At -O0, don't generate IR for functions with available_externally // linkage. if (!shouldEmitFunction(GD)) return; @@ -2017,7 +2050,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { if (const auto *VD = dyn_cast<VarDecl>(D)) return EmitGlobalVarDefinition(VD, !VD->hasDefinition()); - + llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } @@ -2123,7 +2156,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( assert(F->getName() == MangledName && "name was uniqued!"); if (D) - SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); + SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk, + IsForDefinition); if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) { llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex); F->addAttributes(llvm::AttributeList::FunctionIndex, B); @@ -2259,7 +2293,8 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, F->setCallingConv(getRuntimeCC()); if (!Local && getTriple().isOSBinFormatCOFF() && - !getCodeGenOpts().LTOVisibilityPublicStd) { + !getCodeGenOpts().LTOVisibilityPublicStd && + !getTriple().isWindowsGNUEnvironment()) { const FunctionDecl *FD = GetRuntimeFunctionDecl(Context, Name); if (!FD || FD->hasAttr<DLLImportAttr>()) { F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); @@ -2408,7 +2443,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); - setLinkageAndVisibilityForGV(GV, D); + setLinkageForGV(GV, D); + setGlobalVisibility(GV, D, NotForDefinition); if (D->getTLSKind()) { if (D->getTLSKind() == VarDecl::TLS_Dynamic) @@ -2422,18 +2458,65 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, EmitGlobalVarDefinition(D); } + // Emit section information for extern variables. + if (D->hasExternalStorage()) { + if (const SectionAttr *SA = D->getAttr<SectionAttr>()) + GV->setSection(SA->getName()); + } + // Handle XCore specific ABI requirements. if (getTriple().getArch() == llvm::Triple::xcore && D->getLanguageLinkage() == CLanguageLinkage && D->getType().isConstant(Context) && isExternallyVisible(D->getLinkageAndVisibility().getLinkage())) GV->setSection(".cp.rodata"); + + // Check if we a have a const declaration with an initializer, we may be + // able to emit it as available_externally to expose it's value to the + // optimizer. + if (Context.getLangOpts().CPlusPlus && GV->hasExternalLinkage() && + D->getType().isConstQualified() && !GV->hasInitializer() && + !D->hasDefinition() && D->hasInit() && !D->hasAttr<DLLImportAttr>()) { + const auto *Record = + Context.getBaseElementType(D->getType())->getAsCXXRecordDecl(); + bool HasMutableFields = Record && Record->hasMutableFields(); + if (!HasMutableFields) { + const VarDecl *InitDecl; + const Expr *InitExpr = D->getAnyInitializer(InitDecl); + if (InitExpr) { + ConstantEmitter emitter(*this); + llvm::Constant *Init = emitter.tryEmitForInitializer(*InitDecl); + if (Init) { + auto *InitType = Init->getType(); + if (GV->getType()->getElementType() != InitType) { + // The type of the initializer does not match the definition. + // This happens when an initializer has a different type from + // the type of the global (because of padding at the end of a + // structure for instance). + GV->setName(StringRef()); + // Make a new global with the correct type, this is now guaranteed + // to work. + auto *NewGV = cast<llvm::GlobalVariable>( + GetAddrOfGlobalVar(D, InitType, IsForDefinition)); + + // Erase the old global, since it is no longer used. + cast<llvm::GlobalValue>(GV)->eraseFromParent(); + GV = NewGV; + } else { + GV->setInitializer(Init); + GV->setConstant(true); + GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + } + emitter.finalize(GV); + } + } + } + } } - auto ExpectedAS = + LangAS ExpectedAS = D ? D->getType().getAddressSpace() - : static_cast<unsigned>(LangOpts.OpenCL ? LangAS::opencl_global - : LangAS::Default); + : (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default); assert(getContext().getTargetAddressSpace(ExpectedAS) == Ty->getPointerAddressSpace()); if (AddrSpace != ExpectedAS) @@ -2474,7 +2557,7 @@ CodeGenModule::GetAddrOfGlobal(GlobalDecl GD, } llvm::GlobalVariable * -CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, +CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage) { llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name); @@ -2490,7 +2573,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, assert(GV->isDeclaration() && "Declaration has wrong type!"); OldGV = GV; } - + // Create a new variable. GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name); @@ -2498,13 +2581,13 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, if (OldGV) { // Replace occurrences of the old variable if needed. GV->takeName(OldGV); - + if (!OldGV->use_empty()) { llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); OldGV->replaceAllUsesWith(NewPtrForOldDecl); } - + OldGV->eraseFromParent(); } @@ -2572,11 +2655,10 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { getDataLayout().getTypeStoreSizeInBits(Ty)); } -unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { - unsigned AddrSpace; +LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { + LangAS AddrSpace = LangAS::Default; if (LangOpts.OpenCL) { - AddrSpace = D ? D->getType().getAddressSpace() - : static_cast<unsigned>(LangAS::opencl_global); + AddrSpace = D ? D->getType().getAddressSpace() : LangAS::opencl_global; assert(AddrSpace == LangAS::opencl_global || AddrSpace == LangAS::opencl_constant || AddrSpace == LangAS::opencl_local || @@ -2678,6 +2760,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); + Optional<ConstantEmitter> emitter; + // CUDA E.2.4.1 "__shared__ variables cannot have an initialization // as part of their declaration." Sema has already checked for // error cases, so we just need to set Init to UndefValue. @@ -2698,7 +2782,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, Init = EmitNullConstant(D->getType()); } else { initializedGlobalDecl = GlobalDecl(D); - Init = EmitConstantInit(*InitDecl); + emitter.emplace(*this); + Init = emitter->tryEmitForInitializer(*InitDecl); if (!Init) { QualType T = InitExpr->getType(); @@ -2811,7 +2896,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, Linkage = llvm::GlobalValue::InternalLinkage; } } + GV->setInitializer(Init); + if (emitter) emitter->finalize(GV); // If it is safe to mark the global 'constant', do so now. GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor && @@ -3176,7 +3263,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, setFunctionDLLStorageClass(GD, Fn); // FIXME: this is redundant with part of setFunctionDefinitionAttributes - setGlobalVisibility(Fn, D); + setGlobalVisibility(Fn, D, ForDefinition); MaybeHandleStaticInExternC(D, Fn); @@ -3497,11 +3584,15 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { return ConstantAddress(GV, Alignment); } +bool CodeGenModule::getExpressionLocationsEnabled() const { + return !CodeGenOpts.EmitCodeView || CodeGenOpts.DebugColumnInfo; +} + QualType CodeGenModule::getObjCFastEnumerationStateType() { if (ObjCFastEnumerationStateType.isNull()) { RecordDecl *D = Context.buildImplicitRecord("__objcFastEnumerationState"); D->startDefinition(); - + QualType FieldTypes[] = { Context.UnsignedLongTy, Context.getPointerType(Context.getObjCIdType()), @@ -3509,7 +3600,7 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() { Context.getConstantArrayType(Context.UnsignedLongTy, llvm::APInt(32, 5), ArrayType::Normal, 0) }; - + for (size_t i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(Context, D, @@ -3522,18 +3613,18 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() { Field->setAccess(AS_public); D->addDecl(Field); } - + D->completeDefinition(); ObjCFastEnumerationStateType = Context.getTagDeclType(D); } - + return ObjCFastEnumerationStateType; } llvm::Constant * CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { assert(!E->getType()->isPointerType() && "Strings are always arrays"); - + // Don't emit it as the address of the string, emit the string data itself // as an inline array. if (E->getCharByteWidth() == 1) { @@ -3559,11 +3650,11 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { Elements.resize(NumElements); return llvm::ConstantDataArray::get(VMContext, Elements); } - + assert(ElemTy->getPrimitiveSizeInBits() == 32); SmallVector<uint32_t, 32> Elements; Elements.reserve(NumElements); - + for(unsigned i = 0, e = E->getLength(); i != e; ++i) Elements.push_back(E->getCodeUnit(i)); Elements.resize(NumElements); @@ -3727,12 +3818,18 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( !EvalResult.hasSideEffects()) Value = &EvalResult.Val; + LangAS AddrSpace = + VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace(); + + Optional<ConstantEmitter> emitter; llvm::Constant *InitialValue = nullptr; bool Constant = false; llvm::Type *Type; if (Value) { // The temporary has a constant initializer, use it. - InitialValue = EmitConstantValue(*Value, MaterializedType, nullptr); + emitter.emplace(*this); + InitialValue = emitter->emitForInitializer(*Value, AddrSpace, + MaterializedType); Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value); Type = InitialValue->getType(); } else { @@ -3757,13 +3854,12 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( Linkage = llvm::GlobalVariable::InternalLinkage; } } - unsigned AddrSpace = - VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace(); auto TargetAS = getContext().getTargetAddressSpace(AddrSpace); auto *GV = new llvm::GlobalVariable( getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(), /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); - setGlobalVisibility(GV, VD); + if (emitter) emitter->finalize(GV); + setGlobalVisibility(GV, VD, ForDefinition); GV->setAlignment(Align.getQuantity()); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); @@ -3850,11 +3946,11 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { if (D->getNumIvarInitializers() == 0 || AllTrivialInitializers(*this, D)) return; - + IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. - ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, @@ -3945,6 +4041,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::Namespace: EmitDeclContext(cast<NamespaceDecl>(D)); break; + case Decl::ClassTemplateSpecialization: { + const auto *Spec = cast<ClassTemplateSpecializationDecl>(D); + if (DebugInfo && + Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition && + Spec->hasDefinition()) + DebugInfo->completeTemplateDefinition(*Spec); + } LLVM_FALLTHROUGH; case Decl::CXXRecord: if (DebugInfo) { if (auto *ES = D->getASTContext().getExternalSource()) @@ -3983,7 +4086,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() || cast<FunctionDecl>(D)->isLateTemplateParsed()) return; - + getCXXABI().EmitCXXConstructors(cast<CXXConstructorDecl>(D)); break; case Decl::CXXDestructor: @@ -4009,7 +4112,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { ObjCRuntime->GenerateProtocol(Proto); break; } - + case Decl::ObjCCategoryImpl: // Categories have properties but don't support synthesize so we // can ignore them here. @@ -4131,15 +4234,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D)); break; - case Decl::ClassTemplateSpecialization: { - const auto *Spec = cast<ClassTemplateSpecializationDecl>(D); - if (DebugInfo && - Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition && - Spec->hasDefinition()) - DebugInfo->completeTemplateDefinition(*Spec); - break; - } - case Decl::OMPDeclareReduction: EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D)); break; @@ -4166,6 +4260,9 @@ void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) { case Decl::CXXDestructor: { if (!cast<FunctionDecl>(D)->doesThisDeclarationHaveABody()) return; + SourceManager &SM = getContext().getSourceManager(); + if (LimitedCoverage && SM.getMainFileID() != SM.getFileID(D->getLocStart())) + return; auto I = DeferredEmptyCoverageMappingDecls.find(D); if (I == DeferredEmptyCoverageMappingDecls.end()) DeferredEmptyCoverageMappingDecls[D] = true; @@ -4192,20 +4289,10 @@ void CodeGenModule::ClearUnusedCoverageMapping(const Decl *D) { } void CodeGenModule::EmitDeferredUnusedCoverageMappings() { - std::vector<const Decl *> DeferredDecls; - for (const auto &I : DeferredEmptyCoverageMappingDecls) { - if (!I.second) + for (const auto &Entry : DeferredEmptyCoverageMappingDecls) { + if (!Entry.second) continue; - DeferredDecls.push_back(I.first); - } - // Sort the declarations by their location to make sure that the tests get a - // predictable order for the coverage mapping for the unused declarations. - if (CodeGenOpts.DumpCoverageMapping) - std::sort(DeferredDecls.begin(), DeferredDecls.end(), - [] (const Decl *LHS, const Decl *RHS) { - return LHS->getLocStart() < RHS->getLocStart(); - }); - for (const auto *D : DeferredDecls) { + const Decl *D = Entry.first; switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: @@ -4414,7 +4501,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, // and it's not for EH? if (!ForEH && !getLangOpts().RTTI) return llvm::Constant::getNullValue(Int8PtrTy); - + if (ForEH && Ty->isObjCObjectPointerType() && LangOpts.ObjCRuntime.isGNUFamily()) return ObjCRuntime->GetEHType(Ty); @@ -4456,6 +4543,60 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) { return InternalId; } +// Generalize pointer types to a void pointer with the qualifiers of the +// originally pointed-to type, e.g. 'const char *' and 'char * const *' +// generalize to 'const void *' while 'char *' and 'const char **' generalize to +// 'void *'. +static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) { + if (!Ty->isPointerType()) + return Ty; + + return Ctx.getPointerType( + QualType(Ctx.VoidTy).withCVRQualifiers( + Ty->getPointeeType().getCVRQualifiers())); +} + +// Apply type generalization to a FunctionType's return and argument types +static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) { + if (auto *FnType = Ty->getAs<FunctionProtoType>()) { + SmallVector<QualType, 8> GeneralizedParams; + for (auto &Param : FnType->param_types()) + GeneralizedParams.push_back(GeneralizeType(Ctx, Param)); + + return Ctx.getFunctionType( + GeneralizeType(Ctx, FnType->getReturnType()), + GeneralizedParams, FnType->getExtProtoInfo()); + } + + if (auto *FnType = Ty->getAs<FunctionNoProtoType>()) + return Ctx.getFunctionNoProtoType( + GeneralizeType(Ctx, FnType->getReturnType())); + + llvm_unreachable("Encountered unknown FunctionType"); +} + +llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) { + T = GeneralizeFunctionType(getContext(), T); + + llvm::Metadata *&InternalId = GeneralizedMetadataIdMap[T.getCanonicalType()]; + if (InternalId) + return InternalId; + + if (isExternallyVisible(T->getLinkage())) { + std::string OutName; + llvm::raw_string_ostream Out(OutName); + getCXXABI().getMangleContext().mangleTypeName(T, Out); + Out << ".generalized"; + + InternalId = llvm::MDString::get(getLLVMContext(), Out.str()); + } else { + InternalId = llvm::MDNode::getDistinct(getLLVMContext(), + llvm::ArrayRef<llvm::Metadata *>()); + } + + return InternalId; +} + /// Returns whether this module needs the "all-vtables" type identifier. bool CodeGenModule::NeedAllVtablesTypeId() const { // Returns true if at least one of vtable-based CFI checkers is enabled and @@ -4497,14 +4638,23 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, // If we have a TargetAttr build up the feature map based on that. TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); + ParsedAttr.Features.erase( + llvm::remove_if(ParsedAttr.Features, + [&](const std::string &Feat) { + return !Target.isValidFeatureName( + StringRef{Feat}.substr(1)); + }), + ParsedAttr.Features.end()); + // Make a copy of the features as passed on the command line into the // beginning of the additional features from the function to override. ParsedAttr.Features.insert(ParsedAttr.Features.begin(), Target.getTargetOpts().FeaturesAsWritten.begin(), Target.getTargetOpts().FeaturesAsWritten.end()); - if (ParsedAttr.Architecture != "") - TargetCPU = ParsedAttr.Architecture ; + if (ParsedAttr.Architecture != "" && + Target.isValidCPUName(ParsedAttr.Architecture)) + TargetCPU = ParsedAttr.Architecture; // Now populate the feature map, first with the TargetCPU which is either // the default or a new one from the target attribute string. Then we'll use @@ -4527,8 +4677,8 @@ llvm::SanitizerStatReport &CodeGenModule::getSanStats() { llvm::Value * CodeGenModule::createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF) { - llvm::Constant *C = EmitConstantExpr(E, E->getType(), &CGF); - auto SamplerT = getOpenCLRuntime().getSamplerType(); + llvm::Constant *C = ConstantEmitter(CGF).emitAbstract(E, E->getType()); + auto SamplerT = getOpenCLRuntime().getSamplerType(E->getType().getTypePtr()); auto FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false); return CGF.Builder.CreateCall(CreateRuntimeFunction(FTy, "__translate_sampler_initializer"), diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index b162e72d1992f..22c4463b2c810 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -490,14 +490,16 @@ private: /// @} - llvm::DenseMap<const Decl *, bool> DeferredEmptyCoverageMappingDecls; + llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls; std::unique_ptr<CoverageMappingModuleGen> CoverageMapping; /// Mapping from canonical types to their metadata identifiers. We need to /// maintain this mapping because identifiers may be formed from distinct /// MDNodes. - llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap; + typedef llvm::DenseMap<QualType, llvm::Metadata *> MetadataTypeMap; + MetadataTypeMap MetadataIdMap; + MetadataTypeMap GeneralizedMetadataIdMap; public: CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts, @@ -513,6 +515,9 @@ public: /// Finalize LLVM code generation. void Release(); + /// Return true if we should emit location information for expressions. + bool getExpressionLocationsEnabled() const; + /// Return a reference to the configured Objective-C runtime. CGObjCRuntime &getObjCRuntime() { if (!ObjCRuntime) createObjCRuntime(); @@ -649,25 +654,53 @@ public: CtorList &getGlobalCtors() { return GlobalCtors; } CtorList &getGlobalDtors() { return GlobalDtors; } - llvm::MDNode *getTBAAInfo(QualType QTy); - llvm::MDNode *getTBAAInfoForVTablePtr(); + /// getTBAATypeInfo - Get metadata used to describe accesses to objects of + /// the given type. + llvm::MDNode *getTBAATypeInfo(QualType QTy); + + /// getTBAAAccessInfo - Get TBAA information that describes an access to + /// an object of the given type. + TBAAAccessInfo getTBAAAccessInfo(QualType AccessType); + + /// getTBAAVTablePtrAccessInfo - Get the TBAA information that describes an + /// access to a virtual table pointer. + TBAAAccessInfo getTBAAVTablePtrAccessInfo(llvm::Type *VTablePtrType); + llvm::MDNode *getTBAAStructInfo(QualType QTy); - /// Return the path-aware tag for given base type, access node and offset. - llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN, - uint64_t O); + + /// getTBAABaseTypeInfo - Get metadata that describes the given base access + /// type. Return null if the type is not suitable for use in TBAA access tags. + llvm::MDNode *getTBAABaseTypeInfo(QualType QTy); + + /// getTBAAAccessTagInfo - Get TBAA tag for a given memory access. + llvm::MDNode *getTBAAAccessTagInfo(TBAAAccessInfo Info); + + /// mergeTBAAInfoForCast - Get merged TBAA information for the purposes of + /// type casts. + TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, + TBAAAccessInfo TargetInfo); + + /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the + /// purposes of conditional operator. + TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA, + TBAAAccessInfo InfoB); + + /// getTBAAInfoForSubobject - Get TBAA information for an access with a given + /// base lvalue. + TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType) { + if (Base.getTBAAInfo().isMayAlias()) + return TBAAAccessInfo::getMayAliasInfo(); + return getTBAAAccessInfo(AccessType); + } bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); bool isPaddedAtomicType(QualType type); bool isPaddedAtomicType(const AtomicType *type); - /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag - /// is the same as the type. For struct-path aware TBAA, the tag - /// is different from the type: base type, access type and offset. - /// When ConvertTypeToTag is true, we create a tag based on the scalar type. + /// DecorateInstructionWithTBAA - Decorate the instruction with a TBAA tag. void DecorateInstructionWithTBAA(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo, - bool ConvertTypeToTag = true); + TBAAAccessInfo TBAAInfo); /// Adds !invariant.barrier !tag to instruction void DecorateInstructionWithInvariantGroup(llvm::Instruction *I, @@ -677,7 +710,8 @@ public: llvm::ConstantInt *getSize(CharUnits numChars); /// Set the visibility for the given LLVM GlobalValue. - void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; + void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D, + ForDefinition_t IsForDefinition) const; /// Set the TLS mode for the given LLVM GlobalValue for the thread-local /// variable declaration D. @@ -718,7 +752,7 @@ public: /// /// For languages without explicit address spaces, if D has default address /// space, target-specific global or constant address space may be returned. - unsigned GetGlobalVarAddressSpace(const VarDecl *D); + LangAS GetGlobalVarAddressSpace(const VarDecl *D); /// Return the llvm::Constant for the address of the given global variable. /// If Ty is non-null and if the global doesn't exist, then it will be created @@ -942,27 +976,6 @@ public: llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); - /// Try to emit the initializer for the given declaration as a constant; - /// returns 0 if the expression cannot be emitted as a constant. - llvm::Constant *EmitConstantInit(const VarDecl &D, - CodeGenFunction *CGF = nullptr); - - /// Try to emit the given expression as a constant; returns 0 if the - /// expression cannot be emitted as a constant. - llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, - CodeGenFunction *CGF = nullptr); - - /// Emit the given constant value as a constant, in the type's scalar - /// representation. - llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, - CodeGenFunction *CGF = nullptr); - - /// Emit the given constant value as a constant, in the type's memory - /// representation. - llvm::Constant *EmitConstantValueForMemory(const APValue &Value, - QualType DestType, - CodeGenFunction *CGF = nullptr); - /// \brief Emit type info if type of an expression is a variably modified /// type. Also emit proper debug info for cast types. void EmitExplicitCastExprType(const ExplicitCastExpr *E, @@ -1124,7 +1137,8 @@ public: /// annotations are emitted during finalization of the LLVM code. void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); - bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const; + bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn, + SourceLocation Loc) const; bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, @@ -1148,8 +1162,7 @@ public: /// are emitted lazily. void EmitGlobal(GlobalDecl D); - bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target, - bool InEveryTU); + bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); /// Set attributes for a global definition. @@ -1199,6 +1212,11 @@ public: /// internal identifiers). llvm::Metadata *CreateMetadataIdentifierForType(QualType T); + /// Create a metadata identifier for the generalization of the given type. + /// This may either be an MDString (for external identifiers) or a distinct + /// unnamed MDNode (for internal identifiers). + llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T); + /// Create and attach type metadata to the given function. void CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Function *F); @@ -1239,7 +1257,8 @@ private: /// Set function attributes for a function declaration. void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, - bool IsIncompleteFunction, bool IsThunk); + bool IsIncompleteFunction, bool IsThunk, + ForDefinition_t IsForDefinition); void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr); @@ -1355,6 +1374,7 @@ private: bool AttrOnCallSite, llvm::AttrBuilder &FuncAttrs); }; + } // end namespace CodeGen } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp index c3d66c1dabc5e..295893c64fbc8 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp @@ -22,9 +22,10 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" -static llvm::cl::opt<bool> EnableValueProfiling( - "enable-value-profiling", llvm::cl::ZeroOrMore, - llvm::cl::desc("Enable value profiling"), llvm::cl::init(false)); +static llvm::cl::opt<bool> + EnableValueProfiling("enable-value-profiling", llvm::cl::ZeroOrMore, + llvm::cl::desc("Enable value profiling"), + llvm::cl::Hidden, llvm::cl::init(false)); using namespace clang; using namespace CodeGen; @@ -47,6 +48,15 @@ void CodeGenPGO::setFuncName(llvm::Function *Fn) { llvm::createPGOFuncNameMetadata(*Fn, FuncName); } +/// The version of the PGO hash algorithm. +enum PGOHashVersion : unsigned { + PGO_HASH_V1, + PGO_HASH_V2, + + // Keep this set to the latest hash version. + PGO_HASH_LATEST = PGO_HASH_V2 +}; + namespace { /// \brief Stable hasher for PGO region counters. /// @@ -61,6 +71,7 @@ namespace { class PGOHash { uint64_t Working; unsigned Count; + PGOHashVersion HashVersion; llvm::MD5 MD5; static const int NumBitsPerType = 6; @@ -93,24 +104,53 @@ public: BinaryOperatorLAnd, BinaryOperatorLOr, BinaryConditionalOperator, + // The preceding values are available with PGO_HASH_V1. + + EndOfScope, + IfThenBranch, + IfElseBranch, + GotoStmt, + IndirectGotoStmt, + BreakStmt, + ContinueStmt, + ReturnStmt, + ThrowExpr, + UnaryOperatorLNot, + BinaryOperatorLT, + BinaryOperatorGT, + BinaryOperatorLE, + BinaryOperatorGE, + BinaryOperatorEQ, + BinaryOperatorNE, + // The preceding values are available with PGO_HASH_V2. // Keep this last. It's for the static assert that follows. LastHashType }; static_assert(LastHashType <= TooBig, "Too many types in HashType"); - // TODO: When this format changes, take in a version number here, and use the - // old hash calculation for file formats that used the old hash. - PGOHash() : Working(0), Count(0) {} + PGOHash(PGOHashVersion HashVersion) + : Working(0), Count(0), HashVersion(HashVersion), MD5() {} void combine(HashType Type); uint64_t finalize(); + PGOHashVersion getHashVersion() const { return HashVersion; } }; const int PGOHash::NumBitsPerType; const unsigned PGOHash::NumTypesPerWord; const unsigned PGOHash::TooBig; +/// Get the PGO hash version used in the given indexed profile. +static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader, + CodeGenModule &CGM) { + if (PGOReader->getVersion() <= 4) + return PGO_HASH_V1; + return PGO_HASH_V2; +} + /// A RecursiveASTVisitor that fills a map of statements to PGO counters. struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { + using Base = RecursiveASTVisitor<MapRegionCounters>; + /// The next counter value to assign. unsigned NextCounter; /// The function hash. @@ -118,8 +158,9 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { /// The map of statements to counters. llvm::DenseMap<const Stmt *, unsigned> &CounterMap; - MapRegionCounters(llvm::DenseMap<const Stmt *, unsigned> &CounterMap) - : NextCounter(0), CounterMap(CounterMap) {} + MapRegionCounters(PGOHashVersion HashVersion, + llvm::DenseMap<const Stmt *, unsigned> &CounterMap) + : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap) {} // Blocks and lambdas are handled as separate functions, so we need not // traverse them in the parent context. @@ -145,16 +186,66 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { return true; } - bool VisitStmt(const Stmt *S) { - auto Type = getHashType(S); - if (Type == PGOHash::None) - return true; + /// If \p S gets a fresh counter, update the counter mappings. Return the + /// V1 hash of \p S. + PGOHash::HashType updateCounterMappings(Stmt *S) { + auto Type = getHashType(PGO_HASH_V1, S); + if (Type != PGOHash::None) + CounterMap[S] = NextCounter++; + return Type; + } - CounterMap[S] = NextCounter++; - Hash.combine(Type); + /// Include \p S in the function hash. + bool VisitStmt(Stmt *S) { + auto Type = updateCounterMappings(S); + if (Hash.getHashVersion() != PGO_HASH_V1) + Type = getHashType(Hash.getHashVersion(), S); + if (Type != PGOHash::None) + Hash.combine(Type); return true; } - PGOHash::HashType getHashType(const Stmt *S) { + + bool TraverseIfStmt(IfStmt *If) { + // If we used the V1 hash, use the default traversal. + if (Hash.getHashVersion() == PGO_HASH_V1) + return Base::TraverseIfStmt(If); + + // Otherwise, keep track of which branch we're in while traversing. + VisitStmt(If); + for (Stmt *CS : If->children()) { + if (!CS) + continue; + if (CS == If->getThen()) + Hash.combine(PGOHash::IfThenBranch); + else if (CS == If->getElse()) + Hash.combine(PGOHash::IfElseBranch); + TraverseStmt(CS); + } + Hash.combine(PGOHash::EndOfScope); + return true; + } + +// If the statement type \p N is nestable, and its nesting impacts profile +// stability, define a custom traversal which tracks the end of the statement +// in the hash (provided we're not using the V1 hash). +#define DEFINE_NESTABLE_TRAVERSAL(N) \ + bool Traverse##N(N *S) { \ + Base::Traverse##N(S); \ + if (Hash.getHashVersion() != PGO_HASH_V1) \ + Hash.combine(PGOHash::EndOfScope); \ + return true; \ + } + + DEFINE_NESTABLE_TRAVERSAL(WhileStmt) + DEFINE_NESTABLE_TRAVERSAL(DoStmt) + DEFINE_NESTABLE_TRAVERSAL(ForStmt) + DEFINE_NESTABLE_TRAVERSAL(CXXForRangeStmt) + DEFINE_NESTABLE_TRAVERSAL(ObjCForCollectionStmt) + DEFINE_NESTABLE_TRAVERSAL(CXXTryStmt) + DEFINE_NESTABLE_TRAVERSAL(CXXCatchStmt) + + /// Get version \p HashVersion of the PGO hash for \p S. + PGOHash::HashType getHashType(PGOHashVersion HashVersion, const Stmt *S) { switch (S->getStmtClass()) { default: break; @@ -192,9 +283,53 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { return PGOHash::BinaryOperatorLAnd; if (BO->getOpcode() == BO_LOr) return PGOHash::BinaryOperatorLOr; + if (HashVersion == PGO_HASH_V2) { + switch (BO->getOpcode()) { + default: + break; + case BO_LT: + return PGOHash::BinaryOperatorLT; + case BO_GT: + return PGOHash::BinaryOperatorGT; + case BO_LE: + return PGOHash::BinaryOperatorLE; + case BO_GE: + return PGOHash::BinaryOperatorGE; + case BO_EQ: + return PGOHash::BinaryOperatorEQ; + case BO_NE: + return PGOHash::BinaryOperatorNE; + } + } break; } } + + if (HashVersion == PGO_HASH_V2) { + switch (S->getStmtClass()) { + default: + break; + case Stmt::GotoStmtClass: + return PGOHash::GotoStmt; + case Stmt::IndirectGotoStmtClass: + return PGOHash::IndirectGotoStmt; + case Stmt::BreakStmtClass: + return PGOHash::BreakStmt; + case Stmt::ContinueStmtClass: + return PGOHash::ContinueStmt; + case Stmt::ReturnStmtClass: + return PGOHash::ReturnStmt; + case Stmt::CXXThrowExprClass: + return PGOHash::ThrowExpr; + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(S); + if (UO->getOpcode() == UO_LNot) + return PGOHash::UnaryOperatorLNot; + break; + } + } + } + return PGOHash::None; } }; @@ -653,8 +788,14 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) { } void CodeGenPGO::mapRegionCounters(const Decl *D) { + // Use the latest hash version when inserting instrumentation, but use the + // version in the indexed profile if we're reading PGO data. + PGOHashVersion HashVersion = PGO_HASH_LATEST; + if (auto *PGOReader = CGM.getPGOReader()) + HashVersion = getPGOHashVersion(PGOReader, CGM); + RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>); - MapRegionCounters Walker(*RegionCounterMap); + MapRegionCounters Walker(HashVersion, *RegionCounterMap); if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) Walker.TraverseDecl(const_cast<FunctionDecl *>(FD)); else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp index 8a75a552d9faa..f394ea288d469 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -25,16 +25,18 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Type.h" using namespace clang; using namespace CodeGen; -CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext, +CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::Module &M, const CodeGenOptions &CGO, const LangOptions &Features, MangleContext &MContext) - : Context(Ctx), CodeGenOpts(CGO), Features(Features), MContext(MContext), - MDHelper(VMContext), Root(nullptr), Char(nullptr) { -} + : Context(Ctx), Module(M), CodeGenOpts(CGO), + Features(Features), MContext(MContext), MDHelper(M.getContext()), + Root(nullptr), Char(nullptr) +{} CodeGenTBAA::~CodeGenTBAA() { } @@ -54,10 +56,10 @@ llvm::MDNode *CodeGenTBAA::getRoot() { return Root; } -// For both scalar TBAA and struct-path aware TBAA, the scalar type has the -// same format: name, parent node, and offset. -llvm::MDNode *CodeGenTBAA::createTBAAScalarType(StringRef Name, - llvm::MDNode *Parent) { +llvm::MDNode *CodeGenTBAA::createScalarTypeNode(StringRef Name, + llvm::MDNode *Parent, + uint64_t Size) { + (void)Size; // TODO: Support generation of size-aware type nodes. return MDHelper.createTBAAScalarTypeNode(Name, Parent); } @@ -67,7 +69,7 @@ llvm::MDNode *CodeGenTBAA::getChar() { // these special powers only cover user-accessible memory, and doesn't // include things like vtables. if (!Char) - Char = createTBAAScalarType("omnipotent char", getRoot()); + Char = createScalarTypeNode("omnipotent char", getRoot(), /* Size= */ 1); return Char; } @@ -88,21 +90,27 @@ static bool TypeHasMayAlias(QualType QTy) { return false; } -llvm::MDNode * -CodeGenTBAA::getTBAAInfo(QualType QTy) { - // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. - if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) - return nullptr; - - // If the type has the may_alias attribute (even on a typedef), it is - // effectively in the general char alias class. - if (TypeHasMayAlias(QTy)) - return getChar(); - - const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); +/// Check if the given type is a valid base type to be used in access tags. +static bool isValidBaseType(QualType QTy) { + if (QTy->isReferenceType()) + return false; + if (const RecordType *TTy = QTy->getAs<RecordType>()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + // Incomplete types are not valid base access types. + if (!RD) + return false; + if (RD->hasFlexibleArrayMember()) + return false; + // RD can be struct, union, class, interface or enum. + // For now, we only handle struct and class. + if (RD->isStruct() || RD->isClass()) + return true; + } + return false; +} - if (llvm::MDNode *N = MetadataCache[Ty]) - return N; +llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { + uint64_t Size = Context.getTypeSizeInChars(Ty).getQuantity(); // Handle builtin types. if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) { @@ -120,22 +128,21 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // Unsigned types can alias their corresponding signed types. case BuiltinType::UShort: - return getTBAAInfo(Context.ShortTy); + return getTypeInfo(Context.ShortTy); case BuiltinType::UInt: - return getTBAAInfo(Context.IntTy); + return getTypeInfo(Context.IntTy); case BuiltinType::ULong: - return getTBAAInfo(Context.LongTy); + return getTypeInfo(Context.LongTy); case BuiltinType::ULongLong: - return getTBAAInfo(Context.LongLongTy); + return getTypeInfo(Context.LongLongTy); case BuiltinType::UInt128: - return getTBAAInfo(Context.Int128Ty); + return getTypeInfo(Context.Int128Ty); // Treat all other builtin types as distinct types. This includes // treating wchar_t, char16_t, and char32_t as distinct from their // "underlying types". default: - return MetadataCache[Ty] = - createTBAAScalarType(BTy->getName(Features), getChar()); + return createScalarTypeNode(BTy->getName(Features), getChar(), Size); } } @@ -143,14 +150,13 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // an object through a glvalue of other than one of the following types the // behavior is undefined: [...] a char, unsigned char, or std::byte type." if (Ty->isStdByteType()) - return MetadataCache[Ty] = getChar(); + return getChar(); - // Handle pointers. + // Handle pointers and references. // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. - if (Ty->isPointerType()) - return MetadataCache[Ty] = createTBAAScalarType("any pointer", - getChar()); + if (Ty->isPointerType() || Ty->isReferenceType()) + return createScalarTypeNode("any pointer", getChar(), Size); // Enum types are distinct types. In C++ they have "underlying types", // however they aren't related for TBAA. @@ -160,20 +166,53 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // TODO: Is there a way to get a program-wide unique name for a // decl with local linkage or no linkage? if (!Features.CPlusPlus || !ETy->getDecl()->isExternallyVisible()) - return MetadataCache[Ty] = getChar(); + return getChar(); SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); MContext.mangleTypeName(QualType(ETy, 0), Out); - return MetadataCache[Ty] = createTBAAScalarType(OutName, getChar()); + return createScalarTypeNode(OutName, getChar(), Size); } // For now, handle any other kind of type conservatively. - return MetadataCache[Ty] = getChar(); + return getChar(); +} + +llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { + // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. + if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) + return nullptr; + + // If the type has the may_alias attribute (even on a typedef), it is + // effectively in the general char alias class. + if (TypeHasMayAlias(QTy)) + return getChar(); + + // We need this function to not fall back to returning the "omnipotent char" + // type node for aggregate and union types. Otherwise, any dereference of an + // aggregate will result into the may-alias access descriptor, meaning all + // subsequent accesses to direct and indirect members of that aggregate will + // be considered may-alias too. + // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function. + if (isValidBaseType(QTy)) + return getBaseTypeInfo(QTy); + + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + if (llvm::MDNode *N = MetadataCache[Ty]) + return N; + + // Note that the following helper call is allowed to add new nodes to the + // cache, which invalidates all its previously obtained iterators. So we + // first generate the node for the type and then add that node to the cache. + llvm::MDNode *TypeNode = getTypeInfoHelper(Ty); + return MetadataCache[Ty] = TypeNode; } -llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { - return createTBAAScalarType("vtable pointer", getRoot()); +TBAAAccessInfo CodeGenTBAA::getVTablePtrAccessInfo(llvm::Type *VTablePtrType) { + llvm::DataLayout DL(&Module); + unsigned Size = DL.getPointerTypeSize(VTablePtrType); + return TBAAAccessInfo(createScalarTypeNode("vtable pointer", getRoot(), Size), + Size); } bool @@ -212,8 +251,8 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, /* Otherwise, treat whatever it is as a field. */ uint64_t Offset = BaseOffset; uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); - llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy); - llvm::MDNode *TBAATag = getTBAAScalarTagInfo(TBAAInfo); + llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy); + llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType, Size)); Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); return true; } @@ -233,46 +272,23 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) { return StructMetadataCache[Ty] = nullptr; } -/// Check if the given type can be handled by path-aware TBAA. -static bool isTBAAPathStruct(QualType QTy) { - if (const RecordType *TTy = QTy->getAs<RecordType>()) { - const RecordDecl *RD = TTy->getDecl()->getDefinition(); - if (RD->hasFlexibleArrayMember()) - return false; - // RD can be struct, union, class, interface or enum. - // For now, we only handle struct and class. - if (RD->isStruct() || RD->isClass()) - return true; - } - return false; -} - -llvm::MDNode * -CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { - const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); - assert(isTBAAPathStruct(QTy)); - - if (llvm::MDNode *N = StructTypeMetadataCache[Ty]) - return N; - - if (const RecordType *TTy = QTy->getAs<RecordType>()) { +llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { + if (auto *TTy = dyn_cast<RecordType>(Ty)) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - SmallVector <std::pair<llvm::MDNode*, uint64_t>, 4> Fields; - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i, ++idx) { - QualType FieldQTy = i->getType(); - llvm::MDNode *FieldNode; - if (isTBAAPathStruct(FieldQTy)) - FieldNode = getTBAAStructTypeInfo(FieldQTy); - else - FieldNode = getTBAAInfo(FieldQTy); - if (!FieldNode) - return StructTypeMetadataCache[Ty] = nullptr; - Fields.push_back(std::make_pair( - FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth())); + SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields; + for (FieldDecl *Field : RD->fields()) { + QualType FieldQTy = Field->getType(); + llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ? + getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy); + if (!TypeNode) + return BaseTypeMetadataCache[Ty] = nullptr; + + uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex()); + uint64_t Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); + uint64_t Size = Context.getTypeSizeInChars(FieldQTy).getQuantity(); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, + TypeNode)); } SmallString<256> OutName; @@ -283,47 +299,80 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { } else { OutName = RD->getName(); } + + // TODO: Support size-aware type nodes and create one here for the + // given aggregate type. + // Create the struct type node with a vector of pairs (offset, type). - return StructTypeMetadataCache[Ty] = - MDHelper.createTBAAStructTypeNode(OutName, Fields); + SmallVector<std::pair<llvm::MDNode*, uint64_t>, 4> OffsetsAndTypes; + for (const auto &Field : Fields) + OffsetsAndTypes.push_back(std::make_pair(Field.Type, Field.Offset)); + return MDHelper.createTBAAStructTypeNode(OutName, OffsetsAndTypes); } - return StructMetadataCache[Ty] = nullptr; + return nullptr; } -/// Return a TBAA tag node for both scalar TBAA and struct-path aware TBAA. -llvm::MDNode * -CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode, - uint64_t Offset) { - if (!AccessNode) +llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { + if (!isValidBaseType(QTy)) + return nullptr; + + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + if (llvm::MDNode *N = BaseTypeMetadataCache[Ty]) + return N; + + // Note that the following helper call is allowed to add new nodes to the + // cache, which invalidates all its previously obtained iterators. So we + // first generate the node for the type and then add that node to the cache. + llvm::MDNode *TypeNode = getBaseTypeInfoHelper(Ty); + return BaseTypeMetadataCache[Ty] = TypeNode; +} + +llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) { + assert(!Info.isIncomplete() && "Access to an object of an incomplete type!"); + + if (Info.isMayAlias()) + Info = TBAAAccessInfo(getChar(), Info.Size); + + if (!Info.AccessType) return nullptr; if (!CodeGenOpts.StructPathTBAA) - return getTBAAScalarTagInfo(AccessNode); + Info = TBAAAccessInfo(Info.AccessType, Info.Size); - const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr(); - TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset); - if (llvm::MDNode *N = StructTagMetadataCache[PathTag]) + llvm::MDNode *&N = AccessTagMetadataCache[Info]; + if (N) return N; - llvm::MDNode *BNode = nullptr; - if (isTBAAPathStruct(BaseQTy)) - BNode = getTBAAStructTypeInfo(BaseQTy); - if (!BNode) - return StructTagMetadataCache[PathTag] = - MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); + if (!Info.BaseType) { + Info.BaseType = Info.AccessType; + assert(!Info.Offset && "Nonzero offset for an access with no base type!"); + } + return N = MDHelper.createTBAAStructTagNode(Info.BaseType, Info.AccessType, + Info.Offset); +} - return StructTagMetadataCache[PathTag] = - MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset); +TBAAAccessInfo CodeGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, + TBAAAccessInfo TargetInfo) { + if (SourceInfo.isMayAlias() || TargetInfo.isMayAlias()) + return TBAAAccessInfo::getMayAliasInfo(); + return TargetInfo; } -llvm::MDNode * -CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) { - if (!AccessNode) - return nullptr; - if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode]) - return N; +TBAAAccessInfo +CodeGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA, + TBAAAccessInfo InfoB) { + if (InfoA == InfoB) + return InfoA; + + if (!InfoA || !InfoB) + return TBAAAccessInfo(); + + if (InfoA.isMayAlias() || InfoB.isMayAlias()) + return TBAAAccessInfo::getMayAliasInfo(); - return ScalarTagMetadataCache[AccessNode] = - MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); + // TODO: Implement the rest of the logic here. For example, two accesses + // with same final access types result in an access to an object of that final + // access type regardless of their base types. + return TBAAAccessInfo::getMayAliasInfo(); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h index ddb063d9e88a2..a5b1f66bcd1a1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h @@ -30,20 +30,94 @@ namespace clang { class Type; namespace CodeGen { - class CGRecordLayout; +class CGRecordLayout; - struct TBAAPathTag { - TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O) - : BaseT(B), AccessN(A), Offset(O) {} - const Type *BaseT; - const llvm::MDNode *AccessN; - uint64_t Offset; - }; +// TBAAAccessKind - A kind of TBAA memory access descriptor. +enum class TBAAAccessKind : unsigned { + Ordinary, + MayAlias, + Incomplete, +}; + +// TBAAAccessInfo - Describes a memory access in terms of TBAA. +struct TBAAAccessInfo { + TBAAAccessInfo(TBAAAccessKind Kind, llvm::MDNode *BaseType, + llvm::MDNode *AccessType, uint64_t Offset, uint64_t Size) + : Kind(Kind), BaseType(BaseType), AccessType(AccessType), + Offset(Offset), Size(Size) + {} + + TBAAAccessInfo(llvm::MDNode *BaseType, llvm::MDNode *AccessType, + uint64_t Offset, uint64_t Size) + : TBAAAccessInfo(TBAAAccessKind::Ordinary, BaseType, AccessType, + Offset, Size) + {} + + explicit TBAAAccessInfo(llvm::MDNode *AccessType, uint64_t Size) + : TBAAAccessInfo(/* BaseType= */ nullptr, AccessType, /* Offset= */ 0, Size) + {} + + TBAAAccessInfo() + : TBAAAccessInfo(/* AccessType= */ nullptr, /* Size= */ 0) + {} + + static TBAAAccessInfo getMayAliasInfo() { + return TBAAAccessInfo(TBAAAccessKind::MayAlias, + /* BaseType= */ nullptr, /* AccessType= */ nullptr, + /* Offset= */ 0, /* Size= */ 0); + } + + bool isMayAlias() const { return Kind == TBAAAccessKind::MayAlias; } + + static TBAAAccessInfo getIncompleteInfo() { + return TBAAAccessInfo(TBAAAccessKind::Incomplete, + /* BaseType= */ nullptr, /* AccessType= */ nullptr, + /* Offset= */ 0, /* Size= */ 0); + } + + bool isIncomplete() const { return Kind == TBAAAccessKind::Incomplete; } + + bool operator==(const TBAAAccessInfo &Other) const { + return Kind == Other.Kind && + BaseType == Other.BaseType && + AccessType == Other.AccessType && + Offset == Other.Offset && + Size == Other.Size; + } + + bool operator!=(const TBAAAccessInfo &Other) const { + return !(*this == Other); + } + + explicit operator bool() const { + return *this != TBAAAccessInfo(); + } + + /// Kind - The kind of the access descriptor. + TBAAAccessKind Kind; + + /// BaseType - The base/leading access type. May be null if this access + /// descriptor represents an access that is not considered to be an access + /// to an aggregate or union member. + llvm::MDNode *BaseType; + + /// AccessType - The final access type. May be null if there is no TBAA + /// information available about this access. + llvm::MDNode *AccessType; + + /// Offset - The byte offset of the final access within the base one. Must be + /// zero if the base access type is not specified. + uint64_t Offset; + + /// Size - The size of access, in bytes. + uint64_t Size; +}; /// CodeGenTBAA - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. class CodeGenTBAA { ASTContext &Context; + llvm::Module &Module; const CodeGenOptions &CodeGenOpts; const LangOptions &Features; MangleContext &MContext; @@ -54,12 +128,10 @@ class CodeGenTBAA { /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing /// them. llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache; - /// This maps clang::Types to a struct node in the type DAG. - llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache; - /// This maps TBAAPathTags to a tag node. - llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache; - /// This maps a scalar type to a scalar tag node. - llvm::DenseMap<const llvm::MDNode *, llvm::MDNode *> ScalarTagMetadataCache; + /// This maps clang::Types to a base access type in the type DAG. + llvm::DenseMap<const Type *, llvm::MDNode *> BaseTypeMetadataCache; + /// This maps TBAA access descriptors to tag nodes. + llvm::DenseMap<TBAAAccessInfo, llvm::MDNode *> AccessTagMetadataCache; /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing /// them for struct assignments. @@ -83,39 +155,52 @@ class CodeGenTBAA { SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields, bool MayAlias); - /// A wrapper function to create a scalar type. For struct-path aware TBAA, - /// the scalar type has the same format as the struct type: name, offset, - /// pointer to another node in the type DAG. - llvm::MDNode *createTBAAScalarType(StringRef Name, llvm::MDNode *Parent); + /// createScalarTypeNode - A wrapper function to create a metadata node + /// describing a scalar type. + llvm::MDNode *createScalarTypeNode(StringRef Name, llvm::MDNode *Parent, + uint64_t Size); + + /// getTypeInfoHelper - An internal helper function to generate metadata used + /// to describe accesses to objects of the given type. + llvm::MDNode *getTypeInfoHelper(const Type *Ty); + + /// getBaseTypeInfoHelper - An internal helper function to generate metadata + /// used to describe accesses to objects of the given base type. + llvm::MDNode *getBaseTypeInfoHelper(const Type *Ty); public: - CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, - const CodeGenOptions &CGO, - const LangOptions &Features, - MangleContext &MContext); + CodeGenTBAA(ASTContext &Ctx, llvm::Module &M, const CodeGenOptions &CGO, + const LangOptions &Features, MangleContext &MContext); ~CodeGenTBAA(); - /// getTBAAInfo - Get the TBAA MDNode to be used for a dereference - /// of the given type. - llvm::MDNode *getTBAAInfo(QualType QTy); + /// getTypeInfo - Get metadata used to describe accesses to objects of the + /// given type. + llvm::MDNode *getTypeInfo(QualType QTy); - /// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a - /// dereference of a vtable pointer. - llvm::MDNode *getTBAAInfoForVTablePtr(); + /// getVTablePtrAccessInfo - Get the TBAA information that describes an + /// access to a virtual table pointer. + TBAAAccessInfo getVTablePtrAccessInfo(llvm::Type *VTablePtrType); /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of /// the given type. llvm::MDNode *getTBAAStructInfo(QualType QTy); - /// Get the MDNode in the type DAG for given struct type QType. - llvm::MDNode *getTBAAStructTypeInfo(QualType QType); - /// Get the tag MDNode for a given base type, the actual scalar access MDNode - /// and offset into the base type. - llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType, - llvm::MDNode *AccessNode, uint64_t Offset); + /// getBaseTypeInfo - Get metadata that describes the given base access type. + /// Return null if the type is not suitable for use in TBAA access tags. + llvm::MDNode *getBaseTypeInfo(QualType QTy); + + /// getAccessTagInfo - Get TBAA tag for a given memory access. + llvm::MDNode *getAccessTagInfo(TBAAAccessInfo Info); + + /// mergeTBAAInfoForCast - Get merged TBAA information for the purpose of + /// type casts. + TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, + TBAAAccessInfo TargetInfo); - /// Get the scalar tag MDNode for a given scalar type. - llvm::MDNode *getTBAAScalarTagInfo(llvm::MDNode *AccessNode); + /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the + /// purpose of conditional operator. + TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA, + TBAAAccessInfo InfoB); }; } // end namespace CodeGen @@ -123,32 +208,39 @@ public: namespace llvm { -template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> { - static clang::CodeGen::TBAAPathTag getEmptyKey() { - return clang::CodeGen::TBAAPathTag( - DenseMapInfo<const clang::Type *>::getEmptyKey(), - DenseMapInfo<const MDNode *>::getEmptyKey(), +template<> struct DenseMapInfo<clang::CodeGen::TBAAAccessInfo> { + static clang::CodeGen::TBAAAccessInfo getEmptyKey() { + unsigned UnsignedKey = DenseMapInfo<unsigned>::getEmptyKey(); + return clang::CodeGen::TBAAAccessInfo( + static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey), + DenseMapInfo<MDNode *>::getEmptyKey(), + DenseMapInfo<MDNode *>::getEmptyKey(), + DenseMapInfo<uint64_t>::getEmptyKey(), DenseMapInfo<uint64_t>::getEmptyKey()); } - static clang::CodeGen::TBAAPathTag getTombstoneKey() { - return clang::CodeGen::TBAAPathTag( - DenseMapInfo<const clang::Type *>::getTombstoneKey(), - DenseMapInfo<const MDNode *>::getTombstoneKey(), + static clang::CodeGen::TBAAAccessInfo getTombstoneKey() { + unsigned UnsignedKey = DenseMapInfo<unsigned>::getTombstoneKey(); + return clang::CodeGen::TBAAAccessInfo( + static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey), + DenseMapInfo<MDNode *>::getTombstoneKey(), + DenseMapInfo<MDNode *>::getTombstoneKey(), + DenseMapInfo<uint64_t>::getTombstoneKey(), DenseMapInfo<uint64_t>::getTombstoneKey()); } - static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) { - return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^ - DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^ - DenseMapInfo<uint64_t>::getHashValue(Val.Offset); + static unsigned getHashValue(const clang::CodeGen::TBAAAccessInfo &Val) { + auto KindValue = static_cast<unsigned>(Val.Kind); + return DenseMapInfo<unsigned>::getHashValue(KindValue) ^ + DenseMapInfo<MDNode *>::getHashValue(Val.BaseType) ^ + DenseMapInfo<MDNode *>::getHashValue(Val.AccessType) ^ + DenseMapInfo<uint64_t>::getHashValue(Val.Offset) ^ + DenseMapInfo<uint64_t>::getHashValue(Val.Size); } - static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS, - const clang::CodeGen::TBAAPathTag &RHS) { - return LHS.BaseT == RHS.BaseT && - LHS.AccessN == RHS.AccessN && - LHS.Offset == RHS.Offset; + static bool isEqual(const clang::CodeGen::TBAAAccessInfo &LHS, + const clang::CodeGen::TBAAAccessInfo &RHS) { + return LHS == RHS; } }; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h index 450eab48a3b41..2af7b30eafb4a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H #include "clang/AST/CharUnits.h" +#include "clang/Basic/AddressSpaces.h" #include "llvm/IR/CallingConv.h" namespace llvm { @@ -94,7 +95,7 @@ struct CodeGenTypeCache { unsigned char SizeAlignInBytes; }; - unsigned ASTAllocaAddressSpace; + LangAS ASTAllocaAddressSpace; CharUnits getSizeSize() const { return CharUnits::fromQuantity(SizeSizeInBytes); @@ -114,7 +115,7 @@ struct CodeGenTypeCache { llvm::CallingConv::ID BuiltinCC; llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; } - unsigned getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; } + LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; } }; } // end namespace CodeGen diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp index 9306c4fbaff80..529a13b7adc85 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp @@ -443,12 +443,18 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { static_cast<unsigned>(Context.getTypeSize(T))); break; - case BuiltinType::Half: - // Half FP can either be storage-only (lowered to i16) or native. + case BuiltinType::Float16: ResultType = getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T), - Context.getLangOpts().NativeHalfType || - Context.getLangOpts().HalfArgsAndReturns); + /* UseNativeHalf = */ true); + break; + + case BuiltinType::Half: + // Half FP can either be storage-only (lowered to i16) or native. + ResultType = getTypeForFormat( + getLLVMContext(), Context.getFloatTypeSemantics(T), + Context.getLangOpts().NativeHalfType || + !Context.getTargetInfo().useFP16ConversionIntrinsics()); break; case BuiltinType::Float: case BuiltinType::Double: @@ -639,7 +645,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { break; } case Type::Pipe: { - ResultType = CGM.getOpenCLRuntime().getPipeType(); + ResultType = CGM.getOpenCLRuntime().getPipeType(cast<PipeType>(Ty)); break; } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h index 9d0e3ded23e47..d082342bf5925 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h @@ -164,8 +164,6 @@ class CodeGenTypes { llvm::SmallSet<const Type *, 8> RecordsWithOpaqueMemberPointers; - unsigned ClangCallConvToLLVMCallConv(CallingConv CC); - public: CodeGenTypes(CodeGenModule &cgm); ~CodeGenTypes(); @@ -180,6 +178,9 @@ public: llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } const CodeGenOptions &getCodeGenOpts() const; + /// Convert clang calling convention to LLVM callilng convention. + unsigned ClangCallConvToLLVMCallConv(CallingConv CC); + /// ConvertType - Convert type T into a llvm::Type. llvm::Type *ConvertType(QualType T); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h b/contrib/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h new file mode 100644 index 0000000000000..90c9fcd8cf815 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/ConstantEmitter.h @@ -0,0 +1,178 @@ +//===--- ConstantEmitter.h - IR constant emission ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A helper class for emitting expressions and values as llvm::Constants +// and as initializers for global variables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H +#define LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" + +namespace clang { +namespace CodeGen { + +class ConstantEmitter { +public: + CodeGenModule &CGM; + CodeGenFunction *CGF; + +private: + bool Abstract = false; + + /// Whether non-abstract components of the emitter have been initialized. + bool InitializedNonAbstract = false; + + /// Whether the emitter has been finalized. + bool Finalized = false; + + /// Whether the constant-emission failed. + bool Failed = false; + + /// The AST address space where this (non-abstract) initializer is going. + /// Used for generating appropriate placeholders. + LangAS DestAddressSpace; + + llvm::SmallVector<std::pair<llvm::Constant *, llvm::GlobalVariable*>, 4> + PlaceholderAddresses; + +public: + ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr) + : CGM(CGM), CGF(CGF) {} + + /// Initialize this emission in the context of the given function. + /// Use this if the expression might contain contextaul references like + /// block addresses or PredefinedExprs. + ConstantEmitter(CodeGenFunction &CGF) + : CGM(CGF.CGM), CGF(&CGF) {} + + ConstantEmitter(const ConstantEmitter &other) = delete; + ConstantEmitter &operator=(const ConstantEmitter &other) = delete; + + ~ConstantEmitter(); + + /// Is the current emission context abstract? + bool isAbstract() const { + return Abstract; + } + + /// Try to emit the initiaizer of the given declaration as an abstract + /// constant. If this succeeds, the emission must be finalized. + llvm::Constant *tryEmitForInitializer(const VarDecl &D); + llvm::Constant *tryEmitForInitializer(const Expr *E, LangAS destAddrSpace, + QualType destType); + llvm::Constant *emitForInitializer(const APValue &value, LangAS destAddrSpace, + QualType destType); + + void finalize(llvm::GlobalVariable *global); + + // All of the "abstract" emission methods below permit the emission to + // be immediately discarded without finalizing anything. Therefore, they + // must also promise not to do anything that will, in the future, require + // finalization: + // + // - using the CGF (if present) for anything other than establishing + // semantic context; for example, an expression with ignored + // side-effects must not be emitted as an abstract expression + // + // - doing anything that would not be safe to duplicate within an + // initializer or to propagate to another context; for example, + // side effects, or emitting an initialization that requires a + // reference to its current location. + + /// Try to emit the initializer of the given declaration as an abstract + /// constant. + llvm::Constant *tryEmitAbstractForInitializer(const VarDecl &D); + + /// Emit the result of the given expression as an abstract constant, + /// asserting that it succeeded. This is only safe to do when the + /// expression is known to be a constant expression with either a fairly + /// simple type or a known simple form. + llvm::Constant *emitAbstract(const Expr *E, QualType T); + llvm::Constant *emitAbstract(SourceLocation loc, const APValue &value, + QualType T); + + /// Try to emit the result of the given expression as an abstract constant. + llvm::Constant *tryEmitAbstract(const Expr *E, QualType T); + llvm::Constant *tryEmitAbstractForMemory(const Expr *E, QualType T); + + llvm::Constant *tryEmitAbstract(const APValue &value, QualType T); + llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T); + + llvm::Constant *emitNullForMemory(QualType T) { + return emitNullForMemory(CGM, T); + } + llvm::Constant *emitForMemory(llvm::Constant *C, QualType T) { + return emitForMemory(CGM, C, T); + } + + static llvm::Constant *emitNullForMemory(CodeGenModule &CGM, QualType T); + static llvm::Constant *emitForMemory(CodeGenModule &CGM, llvm::Constant *C, + QualType T); + + // These are private helper routines of the constant emitter that + // can't actually be private because things are split out into helper + // functions and classes. + + llvm::Constant *tryEmitPrivateForVarInit(const VarDecl &D); + + llvm::Constant *tryEmitPrivate(const Expr *E, QualType T); + llvm::Constant *tryEmitPrivateForMemory(const Expr *E, QualType T); + + llvm::Constant *tryEmitPrivate(const APValue &value, QualType T); + llvm::Constant *tryEmitPrivateForMemory(const APValue &value, QualType T); + + /// Get the address of the current location. This is a constant + /// that will resolve, after finalization, to the address of the + /// 'signal' value that is registered with the emitter later. + llvm::GlobalValue *getCurrentAddrPrivate(); + + /// Register a 'signal' value with the emitter to inform it where to + /// resolve a placeholder. The signal value must be unique in the + /// initializer; it might, for example, be the address of a global that + /// refers to the current-address value in its own initializer. + /// + /// Uses of the placeholder must be properly anchored before finalizing + /// the emitter, e.g. by being installed as the initializer of a global + /// variable. That is, it must be possible to replaceAllUsesWith + /// the placeholder with the proper address of the signal. + void registerCurrentAddrPrivate(llvm::Constant *signal, + llvm::GlobalValue *placeholder); + +private: + void initializeNonAbstract(LangAS destAS) { + assert(!InitializedNonAbstract); + InitializedNonAbstract = true; + DestAddressSpace = destAS; + } + llvm::Constant *markIfFailed(llvm::Constant *init) { + if (!init) + Failed = true; + return init; + } + + struct AbstractState { + bool OldValue; + size_t OldPlaceholdersSize; + }; + AbstractState pushAbstract() { + AbstractState saved = { Abstract, PlaceholderAddresses.size() }; + Abstract = true; + return saved; + } + llvm::Constant *validateAndPopAbstract(llvm::Constant *C, AbstractState save); +}; + +} +} + +#endif diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp index a1023473bdd33..89a30dc7040c8 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -29,7 +29,7 @@ using namespace clang; using namespace CodeGen; using namespace llvm::coverage; -void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range) { +void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) { SkippedRanges.push_back(Range); } @@ -45,10 +45,19 @@ class SourceMappingRegion { /// \brief The region's ending location. Optional<SourceLocation> LocEnd; + /// Whether this region should be emitted after its parent is emitted. + bool DeferRegion; + + /// Whether this region is a gap region. The count from a gap region is set + /// as the line execution count if there are no other regions on the line. + bool GapRegion; + public: SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart, - Optional<SourceLocation> LocEnd) - : Count(Count), LocStart(LocStart), LocEnd(LocEnd) {} + Optional<SourceLocation> LocEnd, bool DeferRegion = false, + bool GapRegion = false) + : Count(Count), LocStart(LocStart), LocEnd(LocEnd), + DeferRegion(DeferRegion), GapRegion(GapRegion) {} const Counter &getCounter() const { return Count; } @@ -71,6 +80,47 @@ public: assert(LocEnd && "Region has no end location"); return *LocEnd; } + + bool isDeferred() const { return DeferRegion; } + + void setDeferred(bool Deferred) { DeferRegion = Deferred; } + + bool isGap() const { return GapRegion; } + + void setGap(bool Gap) { GapRegion = Gap; } +}; + +/// Spelling locations for the start and end of a source region. +struct SpellingRegion { + /// The line where the region starts. + unsigned LineStart; + + /// The column where the region starts. + unsigned ColumnStart; + + /// The line where the region ends. + unsigned LineEnd; + + /// The column where the region ends. + unsigned ColumnEnd; + + SpellingRegion(SourceManager &SM, SourceLocation LocStart, + SourceLocation LocEnd) { + LineStart = SM.getSpellingLineNumber(LocStart); + ColumnStart = SM.getSpellingColumnNumber(LocStart); + LineEnd = SM.getSpellingLineNumber(LocEnd); + ColumnEnd = SM.getSpellingColumnNumber(LocEnd); + } + + SpellingRegion(SourceManager &SM, SourceMappingRegion &R) + : SpellingRegion(SM, R.getStartLoc(), R.getEndLoc()) {} + + /// Check if the start and end locations appear in source order, i.e + /// top->bottom, left->right. + bool isInSourceOrder() const { + return (LineStart < LineEnd) || + (LineStart == LineEnd && ColumnStart <= ColumnEnd); + } }; /// \brief Provides the common functionality for the different @@ -241,12 +291,9 @@ public: auto CovFileID = getCoverageFileID(LocStart); if (!CovFileID) continue; - unsigned LineStart = SM.getSpellingLineNumber(LocStart); - unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); - unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); - unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); + SpellingRegion SR{SM, LocStart, LocEnd}; auto Region = CounterMappingRegion::makeSkipped( - *CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd); + *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd); // Make sure that we only collect the regions that are inside // the souce code of this function. if (Region.LineStart >= FileLineRanges[*CovFileID].first && @@ -284,16 +331,19 @@ public: if (Filter.count(std::make_pair(LocStart, LocEnd))) continue; - // Find the spilling locations for the mapping region. - unsigned LineStart = SM.getSpellingLineNumber(LocStart); - unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); - unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); - unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); + // Find the spelling locations for the mapping region. + SpellingRegion SR{SM, LocStart, LocEnd}; + assert(SR.isInSourceOrder() && "region start and end out of order"); - assert(LineStart <= LineEnd && "region start and end out of order"); - MappingRegions.push_back(CounterMappingRegion::makeRegion( - Region.getCounter(), *CovFileID, LineStart, ColumnStart, LineEnd, - ColumnEnd)); + if (Region.isGap()) { + MappingRegions.push_back(CounterMappingRegion::makeGapRegion( + Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, + SR.LineEnd, SR.ColumnEnd)); + } else { + MappingRegions.push_back(CounterMappingRegion::makeRegion( + Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, + SR.LineEnd, SR.ColumnEnd)); + } } } @@ -317,14 +367,11 @@ public: "region spans multiple files"); Filter.insert(std::make_pair(ParentLoc, LocEnd)); - unsigned LineStart = SM.getSpellingLineNumber(ParentLoc); - unsigned ColumnStart = SM.getSpellingColumnNumber(ParentLoc); - unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); - unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); - + SpellingRegion SR{SM, ParentLoc, LocEnd}; + assert(SR.isInSourceOrder() && "region start and end out of order"); MappingRegions.push_back(CounterMappingRegion::makeExpansion( - *ParentFileID, *ExpandedFileID, LineStart, ColumnStart, LineEnd, - ColumnEnd)); + *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart, + SR.LineEnd, SR.ColumnEnd)); } return Filter; } @@ -389,6 +436,10 @@ struct CounterCoverageMappingBuilder /// \brief A stack of currently live regions. std::vector<SourceMappingRegion> RegionStack; + /// The currently deferred region: its end location and count can be set once + /// its parent has been popped from the region stack. + Optional<SourceMappingRegion> DeferredRegion; + CounterExpressionBuilder Builder; /// \brief A location in the most recently visited file or macro. @@ -397,6 +448,9 @@ struct CounterCoverageMappingBuilder /// expressions cross file or macro boundaries. SourceLocation MostRecentLocation; + /// Location of the last terminated region. + Optional<std::pair<SourceLocation, size_t>> LastTerminatedRegion; + /// \brief Return a counter for the subtraction of \c RHS from \c LHS Counter subtractCounters(Counter LHS, Counter RHS) { return Builder.subtract(LHS, RHS); @@ -424,19 +478,84 @@ struct CounterCoverageMappingBuilder /// used with popRegions to exit a "scope", ending the region that was pushed. size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None, Optional<SourceLocation> EndLoc = None) { - if (StartLoc) + if (StartLoc) { MostRecentLocation = *StartLoc; + completeDeferred(Count, MostRecentLocation); + } RegionStack.emplace_back(Count, StartLoc, EndLoc); return RegionStack.size() - 1; } + /// Complete any pending deferred region by setting its end location and + /// count, and then pushing it onto the region stack. + size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) { + size_t Index = RegionStack.size(); + if (!DeferredRegion) + return Index; + + // Consume the pending region. + SourceMappingRegion DR = DeferredRegion.getValue(); + DeferredRegion = None; + + // If the region ends in an expansion, find the expansion site. + FileID StartFile = SM.getFileID(DR.getStartLoc()); + if (SM.getFileID(DeferredEndLoc) != StartFile) { + if (isNestedIn(DeferredEndLoc, StartFile)) { + do { + DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc); + } while (StartFile != SM.getFileID(DeferredEndLoc)); + } else { + return Index; + } + } + + // The parent of this deferred region ends where the containing decl ends, + // so the region isn't useful. + if (DR.getStartLoc() == DeferredEndLoc) + return Index; + + // If we're visiting statements in non-source order (e.g switch cases or + // a loop condition) we can't construct a sensible deferred region. + if (!SpellingRegion(SM, DR.getStartLoc(), DeferredEndLoc).isInSourceOrder()) + return Index; + + DR.setGap(true); + DR.setCounter(Count); + DR.setEndLoc(DeferredEndLoc); + handleFileExit(DeferredEndLoc); + RegionStack.push_back(DR); + return Index; + } + + /// Complete a deferred region created after a terminated region at the + /// top-level. + void completeTopLevelDeferredRegion(Counter Count, + SourceLocation DeferredEndLoc) { + if (DeferredRegion || !LastTerminatedRegion) + return; + + if (LastTerminatedRegion->second != RegionStack.size()) + return; + + SourceLocation Start = LastTerminatedRegion->first; + if (SM.getFileID(Start) != SM.getMainFileID()) + return; + + SourceMappingRegion DR = RegionStack.back(); + DR.setStartLoc(Start); + DR.setDeferred(false); + DeferredRegion = DR; + completeDeferred(Count, DeferredEndLoc); + } + /// \brief Pop regions from the stack into the function's list of regions. /// /// Adds all regions from \c ParentIndex to the top of the stack to the /// function's \c SourceRegions. void popRegions(size_t ParentIndex) { assert(RegionStack.size() >= ParentIndex && "parent not in stack"); + bool ParentOfDeferredRegion = false; while (RegionStack.size() > ParentIndex) { SourceMappingRegion &Region = RegionStack.back(); if (Region.hasStartLoc()) { @@ -467,10 +586,34 @@ struct CounterCoverageMappingBuilder MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); assert(SM.isWrittenInSameFile(Region.getStartLoc(), EndLoc)); + assert(SpellingRegion(SM, Region).isInSourceOrder()); SourceRegions.push_back(Region); + + if (ParentOfDeferredRegion) { + ParentOfDeferredRegion = false; + + // If there's an existing deferred region, keep the old one, because + // it means there are two consecutive returns (or a similar pattern). + if (!DeferredRegion.hasValue() && + // File IDs aren't gathered within macro expansions, so it isn't + // useful to try and create a deferred region inside of one. + !EndLoc.isMacroID()) + DeferredRegion = + SourceMappingRegion(Counter::getZero(), EndLoc, None); + } + } else if (Region.isDeferred()) { + assert(!ParentOfDeferredRegion && "Consecutive deferred regions"); + ParentOfDeferredRegion = true; } RegionStack.pop_back(); + + // If the zero region pushed after the last terminated region no longer + // exists, clear its cached information. + if (LastTerminatedRegion && + RegionStack.size() < LastTerminatedRegion->second) + LastTerminatedRegion = None; } + assert(!ParentOfDeferredRegion && "Deferred region with no parent"); } /// \brief Return the currently active region. @@ -481,15 +624,17 @@ struct CounterCoverageMappingBuilder /// \brief Propagate counts through the children of \c S. Counter propagateCounts(Counter TopCount, const Stmt *S) { - size_t Index = pushRegion(TopCount, getStart(S), getEnd(S)); + SourceLocation StartLoc = getStart(S); + SourceLocation EndLoc = getEnd(S); + size_t Index = pushRegion(TopCount, StartLoc, EndLoc); Visit(S); Counter ExitCount = getRegion().getCounter(); popRegions(Index); // The statement may be spanned by an expansion. Make sure we handle a file // exit out of this expansion before moving to the next statement. - if (SM.isBeforeInTranslationUnit(getStart(S), S->getLocStart())) - MostRecentLocation = getEnd(S); + if (SM.isBeforeInTranslationUnit(StartLoc, S->getLocStart())) + MostRecentLocation = EndLoc; return ExitCount; } @@ -577,9 +722,11 @@ struct CounterCoverageMappingBuilder SourceLocation Loc = MostRecentLocation; while (isNestedIn(Loc, ParentFile)) { SourceLocation FileStart = getStartOfFileOrMacro(Loc); - if (StartLocs.insert(FileStart).second) + if (StartLocs.insert(FileStart).second) { SourceRegions.emplace_back(*ParentCounter, FileStart, getEndOfFileOrMacro(Loc)); + assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder()); + } Loc = getIncludeOrExpansionLoc(Loc); } } @@ -595,15 +742,53 @@ struct CounterCoverageMappingBuilder handleFileExit(StartLoc); if (!Region.hasStartLoc()) Region.setStartLoc(StartLoc); + + completeDeferred(Region.getCounter(), StartLoc); } /// \brief Mark \c S as a terminator, starting a zero region. void terminateRegion(const Stmt *S) { extendRegion(S); SourceMappingRegion &Region = getRegion(); + SourceLocation EndLoc = getEnd(S); if (!Region.hasEndLoc()) - Region.setEndLoc(getEnd(S)); + Region.setEndLoc(EndLoc); pushRegion(Counter::getZero()); + auto &ZeroRegion = getRegion(); + ZeroRegion.setDeferred(true); + LastTerminatedRegion = {EndLoc, RegionStack.size()}; + } + + /// Find a valid gap range between \p AfterLoc and \p BeforeLoc. + Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc, + SourceLocation BeforeLoc) { + // If the start and end locations of the gap are both within the same macro + // file, the range may not be in source order. + if (AfterLoc.isMacroID() || BeforeLoc.isMacroID()) + return None; + if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) + return None; + return {{AfterLoc, BeforeLoc}}; + } + + /// Find the source range after \p AfterStmt and before \p BeforeStmt. + Optional<SourceRange> findGapAreaBetween(const Stmt *AfterStmt, + const Stmt *BeforeStmt) { + return findGapAreaBetween(getPreciseTokenLocEnd(getEnd(AfterStmt)), + getStart(BeforeStmt)); + } + + /// Emit a gap region between \p StartLoc and \p EndLoc with the given count. + void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc, + Counter Count) { + if (StartLoc == EndLoc) + return; + assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder()); + handleFileExit(StartLoc); + size_t Index = pushRegion(Count, StartLoc, EndLoc); + getRegion().setGap(true); + handleFileExit(EndLoc); + popRegions(Index); } /// \brief Keep counts of breaks and continues inside loops. @@ -617,13 +802,15 @@ struct CounterCoverageMappingBuilder CoverageMappingModuleGen &CVM, llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM, const LangOptions &LangOpts) - : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {} + : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), + DeferredRegion(None) {} /// \brief Write the mapping data to the output stream void write(llvm::raw_ostream &OS) { llvm::SmallVector<unsigned, 8> VirtualFileMapping; gatherFileIDs(VirtualFileMapping); SourceRegionFilter Filter = emitExpansionRegions(); + assert(!DeferredRegion && "Deferred region never completed"); emitSourceRegions(Filter); gatherSkippedRegions(); @@ -644,14 +831,42 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + /// Determine whether the final deferred region emitted in \p Body should be + /// discarded. + static bool discardFinalDeferredRegionInDecl(Stmt *Body) { + if (auto *CS = dyn_cast<CompoundStmt>(Body)) { + Stmt *LastStmt = CS->body_back(); + if (auto *IfElse = dyn_cast<IfStmt>(LastStmt)) { + if (auto *Else = dyn_cast_or_null<CompoundStmt>(IfElse->getElse())) + LastStmt = Else->body_back(); + else + LastStmt = IfElse->getElse(); + } + return dyn_cast_or_null<ReturnStmt>(LastStmt); + } + return false; + } + void VisitDecl(const Decl *D) { + assert(!DeferredRegion && "Deferred region never completed"); + Stmt *Body = D->getBody(); // Do not propagate region counts into system headers. if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))) return; - propagateCounts(getRegionCounter(Body), Body); + Counter ExitCount = propagateCounts(getRegionCounter(Body), Body); + assert(RegionStack.empty() && "Regions entered but never exited"); + + if (DeferredRegion) { + // Complete (or discard) any deferred regions introduced by the last + // statement. + if (discardFinalDeferredRegionInDecl(Body)) + DeferredRegion = None; + else + popRegions(completeDeferred(ExitCount, getEnd(Body))); + } } void VisitReturnStmt(const ReturnStmt *S) { @@ -671,10 +886,12 @@ struct CounterCoverageMappingBuilder void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } void VisitLabelStmt(const LabelStmt *S) { + Counter LabelCount = getRegionCounter(S); SourceLocation Start = getStart(S); + completeTopLevelDeferredRegion(LabelCount, Start); // We can't extendRegion here or we risk overlapping with our new region. handleFileExit(Start); - pushRegion(getRegionCounter(S), Start); + pushRegion(LabelCount, Start); Visit(S->getSubStmt()); } @@ -682,6 +899,8 @@ struct CounterCoverageMappingBuilder assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); BreakContinueStack.back().BreakCount = addCounters( BreakContinueStack.back().BreakCount, getRegion().getCounter()); + // FIXME: a break in a switch should terminate regions for all preceding + // case statements, not just the most recent one. terminateRegion(S); } @@ -692,6 +911,16 @@ struct CounterCoverageMappingBuilder terminateRegion(S); } + void VisitCallExpr(const CallExpr *E) { + VisitStmt(E); + + // Terminate the region when we hit a noreturn function. + // (This is helpful dealing with switch statements.) + QualType CalleeType = E->getCallee()->getType(); + if (getFunctionExtInfo(*CalleeType).getNoReturn()) + terminateRegion(E); + } + void VisitWhileStmt(const WhileStmt *S) { extendRegion(S); @@ -710,6 +939,11 @@ struct CounterCoverageMappingBuilder propagateCounts(CondCount, S->getCond()); adjustForOutOfOrderTraversal(getEnd(S)); + // The body count applies to the area immediately after the increment. + auto Gap = findGapAreaBetween(S->getCond(), S->getBody()); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); + Counter OutCount = addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); if (OutCount != ParentCount) @@ -764,6 +998,12 @@ struct CounterCoverageMappingBuilder adjustForOutOfOrderTraversal(getEnd(S)); } + // The body count applies to the area immediately after the increment. + auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), + getStart(S->getBody())); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); + Counter OutCount = addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); if (OutCount != ParentCount) @@ -783,6 +1023,12 @@ struct CounterCoverageMappingBuilder Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); BreakContinue BC = BreakContinueStack.pop_back_val(); + // The body count applies to the area immediately after the range. + auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), + getStart(S->getBody())); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); + Counter LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount); Counter OutCount = @@ -803,6 +1049,12 @@ struct CounterCoverageMappingBuilder Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); BreakContinue BC = BreakContinueStack.pop_back_val(); + // The body count applies to the area immediately after the collection. + auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), + getStart(S->getBody())); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); + Counter LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount); Counter OutCount = @@ -823,15 +1075,20 @@ struct CounterCoverageMappingBuilder extendRegion(Body); if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { if (!CS->body_empty()) { - // The body of the switch needs a zero region so that fallthrough counts - // behave correctly, but it would be misleading to include the braces of - // the compound statement in the zeroed area, so we need to handle this - // specially. + // Make a region for the body of the switch. If the body starts with + // a case, that case will reuse this region; otherwise, this covers + // the unreachable code at the beginning of the switch body. size_t Index = - pushRegion(Counter::getZero(), getStart(CS->body_front()), - getEnd(CS->body_back())); + pushRegion(Counter::getZero(), getStart(CS->body_front())); for (const auto *Child : CS->children()) Visit(Child); + + // Set the end for the body of the switch, if it isn't already set. + for (size_t i = RegionStack.size(); i != Index; --i) { + if (!RegionStack[i - 1].hasEndLoc()) + RegionStack[i - 1].setEndLoc(getEnd(CS->body_back())); + } + popRegions(Index); } } else @@ -889,12 +1146,21 @@ struct CounterCoverageMappingBuilder // counter for the body when looking at the coverage. propagateCounts(ParentCount, S->getCond()); + // The 'then' count applies to the area immediately after the condition. + auto Gap = findGapAreaBetween(S->getCond(), S->getThen()); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); + extendRegion(S->getThen()); Counter OutCount = propagateCounts(ThenCount, S->getThen()); Counter ElseCount = subtractCounters(ParentCount, ThenCount); if (const Stmt *Else = S->getElse()) { - extendRegion(S->getElse()); + // The 'else' count applies to the area immediately after the 'then'. + Gap = findGapAreaBetween(S->getThen(), Else); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); + extendRegion(Else); OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); } else OutCount = addCounters(OutCount, ElseCount); @@ -931,25 +1197,34 @@ struct CounterCoverageMappingBuilder Visit(E->getCond()); if (!isa<BinaryConditionalOperator>(E)) { + // The 'then' count applies to the area immediately after the condition. + auto Gap = + findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr())); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount); + extendRegion(E->getTrueExpr()); propagateCounts(TrueCount, E->getTrueExpr()); } + extendRegion(E->getFalseExpr()); propagateCounts(subtractCounters(ParentCount, TrueCount), E->getFalseExpr()); } void VisitBinLAnd(const BinaryOperator *E) { - extendRegion(E); - Visit(E->getLHS()); + extendRegion(E->getLHS()); + propagateCounts(getRegion().getCounter(), E->getLHS()); + handleFileExit(getEnd(E->getLHS())); extendRegion(E->getRHS()); propagateCounts(getRegionCounter(E), E->getRHS()); } void VisitBinLOr(const BinaryOperator *E) { - extendRegion(E); - Visit(E->getLHS()); + extendRegion(E->getLHS()); + propagateCounts(getRegion().getCounter(), E->getLHS()); + handleFileExit(getEnd(E->getLHS())); extendRegion(E->getRHS()); propagateCounts(getRegionCounter(E), E->getRHS()); @@ -992,6 +1267,9 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName, case CounterMappingRegion::SkippedRegion: OS << "Skipped,"; break; + case CounterMappingRegion::GapRegion: + OS << "Gap,"; + break; } OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h index b6789c2a79f12..d07ed5ebcf2b4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.h @@ -39,7 +39,7 @@ class CoverageSourceInfo : public PPCallbacks { public: ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; } - void SourceRangeSkipped(SourceRange Range) override; + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override; }; namespace CodeGen { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp index bd4cb9a3667b2..c375b82ea9363 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -165,9 +165,17 @@ public: Address Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) override; + /// Itanium says that an _Unwind_Exception has to be "double-word" + /// aligned (and thus the end of it is also so-aligned), meaning 16 + /// bytes. Of course, that was written for the actual Itanium, + /// which is a 64-bit platform. Classically, the ABI doesn't really + /// specify the alignment on other platforms, but in practice + /// libUnwind declares the struct with __attribute__((aligned)), so + /// we assume that alignment here. (It's generally 16 bytes, but + /// some targets overwrite it.) CharUnits getAlignmentOfExnObject() { - unsigned Align = CGM.getContext().getTargetInfo().getExnObjectAlignment(); - return CGM.getContext().toCharUnitsFromBits(Align); + auto align = CGM.getContext().getTargetDefaultAlignForAttributeAligned(); + return CGM.getContext().toCharUnitsFromBits(align); } void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; @@ -292,6 +300,14 @@ public: // linkage together with vtables when needed. if (ForVTable && !Thunk->hasLocalLinkage()) Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + + // Propagate dllexport storage, to enable the linker to generate import + // thunks as necessary (e.g. when a parent class has a key function and a + // child class doesn't, and the construction vtable for the parent in the + // child needs to reference the parent's thunks). + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + if (MD->hasAttr<DLLExportAttr>()) + Thunk->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); } llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This, @@ -373,6 +389,10 @@ public: void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override; + std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) override; + private: bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const { const auto &VtableLayout = @@ -546,9 +566,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( llvm::Value *MemFnPtr, const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; - const FunctionProtoType *FPT = + const FunctionProtoType *FPT = MPT->getPointeeType()->getAs<FunctionProtoType>(); - const CXXRecordDecl *RD = + const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType( @@ -575,10 +595,10 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( Ptr = Builder.CreateInBoundsGEP(Ptr, Adj); This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); ThisPtrForCall = This; - + // Load the function pointer. llvm::Value *FnAsInt = Builder.CreateExtractValue(MemFnPtr, 0, "memptr.ptr"); - + // If the LSB in the function pointer is 1, the function pointer points to // a virtual function. llvm::Value *IsVirtual; @@ -626,7 +646,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( CGF.EmitBlock(FnNonVirtual); llvm::Value *NonVirtualFn = Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn"); - + // We're done. CGF.EmitBlock(FnEnd); llvm::PHINode *CalleePtr = Builder.CreatePHI(FTy->getPointerTo(), 2); @@ -791,7 +811,7 @@ llvm::Constant * ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { // Itanium C++ ABI 2.3: // A NULL pointer is represented as -1. - if (MPT->isMemberDataPointer()) + if (MPT->isMemberDataPointer()) return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true); llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0); @@ -868,7 +888,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, (UseARMMethodPtrABI ? 2 : 1) * ThisAdjustment.getQuantity()); } - + return llvm::ConstantStruct::getAnon(MemPtr); } @@ -927,7 +947,7 @@ ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, // (L.ptr == 0 && ((L.adj|R.adj) & 1) == 0))) // The inequality tautologies have exactly the same structure, except // applying De Morgan's laws. - + llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); @@ -980,7 +1000,7 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Constant::getAllOnesValue(MemPtr->getType()); return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); } - + // In Itanium, a member function pointer is not null if 'ptr' is not null. llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); @@ -1138,9 +1158,9 @@ static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) { // const abi::__class_type_info *src, // const abi::__class_type_info *dst, // std::ptrdiff_t src2dst_offset); - + llvm::Type *Int8PtrTy = CGF.Int8PtrTy; - llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy }; @@ -1427,8 +1447,9 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { if (CGF.CurFuncDecl && CGF.CurFuncDecl->hasAttr<NakedAttr>()) return; - /// Initialize the 'this' slot. - EmitThisParam(CGF); + /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue + /// adjustments are required, becuase they are all handled by thunks. + setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF)); /// Initialize the 'vtt' slot if needed. if (getStructorImplicitParamDecl(CGF)) { @@ -1510,7 +1531,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, VTable->setComdat(CGM.getModule().getOrInsertComdat(VTable->getName())); // Set the right visibility. - CGM.setGlobalVisibility(VTable, RD); + CGM.setGlobalVisibility(VTable, RD, ForDefinition); // Use pointer alignment for the vtable. Otherwise we would align them based // on the size of the initializer which doesn't make sense as only single @@ -1620,6 +1641,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, VTable = CGM.CreateOrReplaceCXXRuntimeVariable( Name, VTableType, llvm::GlobalValue::ExternalLinkage); VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + CGM.setGlobalVisibility(VTable, RD, NotForDefinition); if (RD->hasAttr<DLLImportAttr>()) VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); @@ -2111,30 +2133,31 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, (UseARMGuardVarABI && !useInt8GuardVariable) ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1)) : LI; - llvm::Value *isInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); + llvm::Value *NeedsInit = Builder.CreateIsNull(V, "guard.uninitialized"); llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); // Check if the first byte of the guard variable is zero. - Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock); + CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock, + CodeGenFunction::GuardKind::VariableGuard, &D); CGF.EmitBlock(InitCheckBlock); // Variables used when coping with thread-safe statics and exceptions. - if (threadsafe) { + if (threadsafe) { // Call __cxa_guard_acquire. llvm::Value *V = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard); - + llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); - + Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), InitBlock, EndBlock); - + // Call __cxa_guard_abort along the exceptional edge. CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard); - + CGF.EmitBlock(InitBlock); } @@ -2447,11 +2470,11 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, /// if it's a base constructor or destructor with virtual bases. bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - + // We don't have any virtual bases, just return early. if (!MD->getParent()->getNumVBases()) return false; - + // Check if we have a base constructor. if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) return true; @@ -2459,7 +2482,7 @@ bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) { // Check if we have a base destructor. if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return true; - + return false; } @@ -2648,6 +2671,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: + case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Char16: case BuiltinType::Char32: @@ -2981,15 +3005,13 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, if (RD->hasAttr<DLLImportAttr>() && ShouldUseExternalRTTIDescriptor(CGM, Ty)) return llvm::GlobalValue::ExternalLinkage; - if (RD->isDynamicClass()) { - llvm::GlobalValue::LinkageTypes LT = CGM.getVTableLinkage(RD); - // MinGW won't export the RTTI information when there is a key function. - // Make sure we emit our own copy instead of attempting to dllimport it. - if (RD->hasAttr<DLLImportAttr>() && - llvm::GlobalValue::isAvailableExternallyLinkage(LT)) - LT = llvm::GlobalValue::LinkOnceODRLinkage; - return LT; - } + // MinGW always uses LinkOnceODRLinkage for type info. + if (RD->isDynamicClass() && + !CGM.getContext() + .getTargetInfo() + .getTriple() + .isWindowsGNUEnvironment()) + return CGM.getVTableLinkage(RD); } return llvm::GlobalValue::LinkOnceODRLinkage; @@ -3648,6 +3670,18 @@ void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD, !CGM.TryEmitBaseDestructorAsAlias(DD)) return; + // FIXME: The deleting destructor is equivalent to the selected operator + // delete if: + // * either the delete is a destroying operator delete or the destructor + // would be trivial if it weren't virtual, + // * the conversion from the 'this' parameter to the first parameter of the + // destructor is equivalent to a bitcast, + // * the destructor does not have an implicit "this" return, and + // * the operator delete has the same calling convention and IR function type + // as the destructor. + // In such cases we should try to emit the deleting dtor as an alias to the + // selected 'operator delete'. + llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type); if (CGType == StructorCodegen::COMDAT) { @@ -4011,3 +4045,9 @@ ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF, } return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn()); } + +std::pair<llvm::Value *, const CXXRecordDecl *> +ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) { + return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD}; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 1bd2937e47477..ffb3681c2585a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -244,9 +244,6 @@ public: void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params) override; - llvm::Value *adjustThisParameterInVirtualFunctionPrologue( - CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) override; - void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override; AddedStructorArgs @@ -581,7 +578,7 @@ private: return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr); } - std::pair<Address, llvm::Value *> + std::tuple<Address, llvm::Value *, const CXXRecordDecl *> performBaseAdjustment(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy); @@ -748,6 +745,10 @@ public: llvm::GlobalVariable *getThrowInfo(QualType T) override; + std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) override; + private: typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy; @@ -929,7 +930,7 @@ void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF, /// We need to perform a generic polymorphic operation (like a typeid /// or a cast), which requires an object with a vfptr. Adjust the /// address to point to an object with a vfptr. -std::pair<Address, llvm::Value *> +std::tuple<Address, llvm::Value *, const CXXRecordDecl *> MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy) { Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy); @@ -940,7 +941,8 @@ MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, // covers non-virtual base subobjects: a class with its own virtual // functions would be a candidate to be a primary base. if (Context.getASTRecordLayout(SrcDecl).hasExtendableVFPtr()) - return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0)); + return std::make_tuple(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0), + SrcDecl); // Okay, one of the vbases must have a vfptr, or else this isn't // actually a polymorphic class. @@ -959,7 +961,7 @@ MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP(Value.getPointer(), Offset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Value.getAlignment(), SrcDecl, PolymorphicBase); - return std::make_pair(Address(Ptr, VBaseAlign), Offset); + return std::make_tuple(Address(Ptr, VBaseAlign), Offset, PolymorphicBase); } bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref, @@ -990,7 +992,7 @@ llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy, Address ThisPtr, llvm::Type *StdTypeInfoPtrTy) { - std::tie(ThisPtr, std::ignore) = + std::tie(ThisPtr, std::ignore, std::ignore) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy); auto Typeid = emitRTtypeidCall(CGF, ThisPtr.getPointer()).getInstruction(); return CGF.Builder.CreateBitCast(Typeid, StdTypeInfoPtrTy); @@ -1014,7 +1016,8 @@ llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall( CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType()); llvm::Value *Offset; - std::tie(This, Offset) = performBaseAdjustment(CGF, This, SrcRecordTy); + std::tie(This, Offset, std::ignore) = + performBaseAdjustment(CGF, This, SrcRecordTy); llvm::Value *ThisPtr = This.getPointer(); Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty); @@ -1040,7 +1043,8 @@ llvm::Value * MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy, QualType DestTy) { - std::tie(Value, std::ignore) = performBaseAdjustment(CGF, Value, SrcRecordTy); + std::tie(Value, std::ignore, std::ignore) = + performBaseAdjustment(CGF, Value, SrcRecordTy); // PVOID __RTCastToVoid( // PVOID inptr) @@ -1433,50 +1437,54 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF, } } -llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue( - CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) { - // In this ABI, every virtual function takes a pointer to one of the - // subobjects that first defines it as the 'this' parameter, rather than a - // pointer to the final overrider subobject. Thus, we need to adjust it back - // to the final overrider subobject before use. - // See comments in the MicrosoftVFTableContext implementation for the details. - CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(GD); - if (Adjustment.isZero()) - return This; - - unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace(); - llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS), - *thisTy = This->getType(); - - This = CGF.Builder.CreateBitCast(This, charPtrTy); - assert(Adjustment.isPositive()); - This = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, This, - -Adjustment.getQuantity()); - return CGF.Builder.CreateBitCast(This, thisTy); -} - void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { // Naked functions have no prolog. if (CGF.CurFuncDecl && CGF.CurFuncDecl->hasAttr<NakedAttr>()) return; - EmitThisParam(CGF); + // Overridden virtual methods of non-primary bases need to adjust the incoming + // 'this' pointer in the prologue. In this hierarchy, C::b will subtract + // sizeof(void*) to adjust from B* to C*: + // struct A { virtual void a(); }; + // struct B { virtual void b(); }; + // struct C : A, B { virtual void b(); }; + // + // Leave the value stored in the 'this' alloca unadjusted, so that the + // debugger sees the unadjusted value. Microsoft debuggers require this, and + // will apply the ThisAdjustment in the method type information. + // FIXME: Do something better for DWARF debuggers, which won't expect this, + // without making our codegen depend on debug info settings. + llvm::Value *This = loadIncomingCXXThis(CGF); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); + if (!CGF.CurFuncIsThunk && MD->isVirtual()) { + CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(CGF.CurGD); + if (!Adjustment.isZero()) { + unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace(); + llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS), + *thisTy = This->getType(); + This = CGF.Builder.CreateBitCast(This, charPtrTy); + assert(Adjustment.isPositive()); + This = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, This, + -Adjustment.getQuantity()); + This = CGF.Builder.CreateBitCast(This, thisTy, "this.adjusted"); + } + } + setCXXABIThisValue(CGF, This); - /// If this is a function that the ABI specifies returns 'this', initialize - /// the return slot to 'this' at the start of the function. - /// - /// Unlike the setting of return types, this is done within the ABI - /// implementation instead of by clients of CGCXXABI because: - /// 1) getThisValue is currently protected - /// 2) in theory, an ABI could implement 'this' returns some other way; - /// HasThisReturn only specifies a contract, not the implementation + // If this is a function that the ABI specifies returns 'this', initialize + // the return slot to 'this' at the start of the function. + // + // Unlike the setting of return types, this is done within the ABI + // implementation instead of by clients of CGCXXABI because: + // 1) getThisValue is currently protected + // 2) in theory, an ABI could implement 'this' returns some other way; + // HasThisReturn only specifies a contract, not the implementation if (HasThisReturn(CGF.CurGD)) CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); else if (hasMostDerivedReturn(CGF.CurGD)) CGF.Builder.CreateStore(CGF.EmitCastToVoidPtr(getThisValue(CGF)), CGF.ReturnValue); - const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { assert(getStructorImplicitParamDecl(CGF) && "no implicit parameter for a constructor with virtual bases?"); @@ -1961,7 +1969,7 @@ llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk( // Start defining the function. CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo, FunctionArgs, MD->getLocation(), SourceLocation()); - EmitThisParam(CGF); + setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF)); // Load the vfptr and then callee from the vftable. The callee should have // adjusted 'this' so that the vfptr is at offset zero. @@ -2461,11 +2469,12 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, // Test our bit from the guard variable. llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1ULL << GuardNum); llvm::LoadInst *LI = Builder.CreateLoad(GuardAddr); - llvm::Value *IsInitialized = - Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero); + llvm::Value *NeedsInit = + Builder.CreateICmpEQ(Builder.CreateAnd(LI, Bit), Zero); llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); - Builder.CreateCondBr(IsInitialized, EndBlock, InitBlock); + CGF.EmitCXXGuardedInitBranch(NeedsInit, InitBlock, EndBlock, + CodeGenFunction::GuardKind::VariableGuard, &D); // Set our bit in the guard variable and emit the initializer and add a global // destructor if appropriate. @@ -2500,7 +2509,8 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch); llvm::BasicBlock *AttemptInitBlock = CGF.createBasicBlock("init.attempt"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); - Builder.CreateCondBr(IsUninitialized, AttemptInitBlock, EndBlock); + CGF.EmitCXXGuardedInitBranch(IsUninitialized, AttemptInitBlock, EndBlock, + CodeGenFunction::GuardKind::VariableGuard, &D); // This BasicBlock attempts to determine whether or not this thread is // responsible for doing the initialization. @@ -3803,7 +3813,7 @@ static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor, if (!dtor->getParent()->getNumVBases() && (dtorType == StructorType::Complete || dtorType == StructorType::Base)) { bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias( - GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base), true); + GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base)); if (ProducedAlias) { if (dtorType == StructorType::Complete) return; @@ -3898,7 +3908,7 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, FunctionArgs, CD->getLocation(), SourceLocation()); // Create a scope with an artificial location for the body of this function. auto AL = ApplyDebugLocation::CreateArtificial(CGF); - EmitThisParam(CGF); + setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF)); llvm::Value *This = getThisValue(CGF); llvm::Value *SrcVal = @@ -4241,3 +4251,11 @@ void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { }; CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args); } + +std::pair<llvm::Value *, const CXXRecordDecl *> +MicrosoftCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) { + std::tie(This, std::ignore, RD) = + performBaseAdjustment(CGF, This, QualType(RD->getTypeForDecl(), 0)); + return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD}; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp index fc642850d60ad..8aa9bfb421b4a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp @@ -119,6 +119,14 @@ namespace { return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition)); } + llvm::Module *StartModule(llvm::StringRef ModuleName, + llvm::LLVMContext &C) { + assert(!M && "Replacing existing Module?"); + M.reset(new llvm::Module(ModuleName, C)); + Initialize(*Ctx); + return M.get(); + } + void Initialize(ASTContext &Context) override { Ctx = &Context; @@ -317,6 +325,11 @@ llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global, ->GetAddrOfGlobal(global, isForDefinition); } +llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName, + llvm::LLVMContext &C) { + return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C); +} + CodeGenerator *clang::CreateLLVMCodeGen( DiagnosticsEngine &Diags, llvm::StringRef ModuleName, const HeaderSearchOptions &HeaderSearchOpts, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp b/contrib/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp index 9848e3e452f4b..f891cfbe4bb2b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -26,7 +26,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, QualType Ty, bool IsDynInit, bool IsBlacklisted) { if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address | - SanitizerKind::KernelAddress)) + SanitizerKind::KernelAddress | + SanitizerKind::HWAddress)) return; IsDynInit &= !CGM.isInSanitizerBlacklist(GV, Loc, Ty, "init"); IsBlacklisted |= CGM.isInSanitizerBlacklist(GV, Loc, Ty); @@ -58,7 +59,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D, bool IsDynInit) { if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address | - SanitizerKind::KernelAddress)) + SanitizerKind::KernelAddress | + SanitizerKind::HWAddress)) return; std::string QualName; llvm::raw_string_ostream OS(QualName); @@ -76,7 +78,8 @@ void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { // For now, just make sure the global is not modified by the ASan // instrumentation. if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address | - SanitizerKind::KernelAddress)) + SanitizerKind::KernelAddress | + SanitizerKind::HWAddress)) reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index ece3a407eae3b..4b8006428f8f0 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -14,6 +14,7 @@ #include "TargetInfo.h" #include "ABIInfo.h" +#include "CGBlocks.h" #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" @@ -22,7 +23,9 @@ #include "clang/CodeGen/SwiftCallingConv.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" @@ -420,18 +423,17 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule & return llvm::ConstantPointerNull::get(T); } -unsigned TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, - const VarDecl *D) const { +LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const { assert(!CGM.getLangOpts().OpenCL && !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && "Address space agnostic languages only"); - return D ? D->getType().getAddressSpace() - : static_cast<unsigned>(LangAS::Default); + return D ? D->getType().getAddressSpace() : LangAS::Default; } llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( - CodeGen::CodeGenFunction &CGF, llvm::Value *Src, unsigned SrcAddr, - unsigned DestAddr, llvm::Type *DestTy, bool isNonNull) const { + CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr, + LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. if (auto *C = dyn_cast<llvm::Constant>(Src)) @@ -441,13 +443,18 @@ llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( llvm::Constant * TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, - unsigned SrcAddr, unsigned DestAddr, + LangAS SrcAddr, LangAS DestAddr, llvm::Type *DestTy) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. return llvm::ConstantExpr::getPointerCast(Src, DestTy); } +llvm::SyncScope::ID +TargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S, llvm::LLVMContext &C) const { + return C.getOrInsertSyncScopeID(""); /* default sync scope */ +} + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -869,7 +876,10 @@ bool IsX86_MMXType(llvm::Type *IRType) { static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) { - if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) { + bool IsMMXCons = llvm::StringSwitch<bool>(Constraint) + .Cases("y", "&y", "^Ym", true) + .Default(false); + if (IsMMXCons && Ty->isVectorTy()) { if (cast<llvm::VectorType>(Ty)->getBitWidth() != 64) { // Invalid MMX constraint return nullptr; @@ -886,8 +896,14 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) { if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) + if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { + if (BT->getKind() == BuiltinType::LongDouble) { + if (&Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return false; + } return true; + } } else if (const VectorType *VT = Ty->getAs<VectorType>()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. @@ -1041,7 +1057,8 @@ public: const llvm::Triple &Triple, const CodeGenOptions &Opts); void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override; + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { // Darwin uses different dwarf register numbers for EH. @@ -1070,14 +1087,14 @@ public: getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { unsigned Sig = (0xeb << 0) | // jmp rel8 (0x06 << 8) | // .+0x08 - ('F' << 16) | - ('T' << 24); + ('v' << 16) | + ('2' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "movl\t%ebp, %ebp" - "\t\t## marker for objc_retainAutoreleaseReturnValue"; + "\t\t// marker for objc_retainAutoreleaseReturnValue"; } }; @@ -1900,7 +1917,6 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI( case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: - case llvm::Triple::Bitrig: case llvm::Triple::Win32: return true; default: @@ -1908,9 +1924,11 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI( } } -void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D, - llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const { +void X86_32TargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const { + if (!IsForDefinition) + return; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) { // Get the LLVM function. @@ -2260,23 +2278,28 @@ public: llvm::Constant * getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { - unsigned Sig; - if (getABIInfo().has64BitPointers()) - Sig = (0xeb << 0) | // jmp rel8 - (0x0a << 8) | // .+0x0c - ('F' << 16) | - ('T' << 24); - else - Sig = (0xeb << 0) | // jmp rel8 - (0x06 << 8) | // .+0x08 - ('F' << 16) | - ('T' << 24); + unsigned Sig = (0xeb << 0) | // jmp rel8 + (0x06 << 8) | // .+0x08 + ('v' << 16) | + ('2' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override { + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override { + if (!IsForDefinition) + return; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { + if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) { + // Get the LLVM function. + auto *Fn = cast<llvm::Function>(GV); + + // Now add the 'alignstack' attribute with a value of 16. + llvm::AttrBuilder B; + B.addStackAlignmentAttr(16); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + } if (FD->hasAttr<AnyX86InterruptAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); @@ -2323,7 +2346,8 @@ public: Win32StructABI, NumRegisterParameters, false) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override; + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { @@ -2351,11 +2375,12 @@ static void addStackProbeSizeTargetAttribute(const Decl *D, } } -void WinX86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D, - llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const { - X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); - +void WinX86_32TargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const { + X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition); + if (!IsForDefinition) + return; addStackProbeSizeTargetAttribute(D, GV, CGM); } @@ -2366,7 +2391,8 @@ public: : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override; + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; @@ -2395,12 +2421,22 @@ public: } }; -void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D, - llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const { - TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); - +void WinX86_64TargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const { + TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition); + if (!IsForDefinition) + return; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { + if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) { + // Get the LLVM function. + auto *Fn = cast<llvm::Function>(GV); + + // Now add the 'alignstack' attribute with a value of 16. + llvm::AttrBuilder B; + B.addStackAlignmentAttr(16); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + } if (FD->hasAttr<AnyX86InterruptAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); @@ -3514,18 +3550,27 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt, NeededSSE; - if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && - !FI.getReturnType()->getTypePtr()->isUnionType()) { - FI.getReturnInfo() = - classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); - if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { - FreeIntRegs -= NeededInt; - FreeSSERegs -= NeededSSE; - } else { - FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); - } - } else if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) { + if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && + !FI.getReturnType()->getTypePtr()->isUnionType()) { + FI.getReturnInfo() = + classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); + if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { + FreeIntRegs -= NeededInt; + FreeSSERegs -= NeededSSE; + } else { + FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); + } + } else if (IsRegCall && FI.getReturnType()->getAs<ComplexType>()) { + // Complex Long Double Type is passed in Memory when Regcall + // calling convention is used. + const ComplexType *CT = FI.getReturnType()->getAs<ComplexType>(); + if (getContext().getCanonicalType(CT->getElementType()) == + getContext().LongDoubleTy) + FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); + } else + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + } // If the return value is indirect, then the hidden argument is consuming one // integer register. @@ -3991,7 +4036,10 @@ Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. class PPC32_SVR4_ABIInfo : public DefaultABIInfo { -bool IsSoftFloatABI; + bool IsSoftFloatABI; + + CharUnits getParamTypeAlignment(QualType Ty) const; + public: PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI) : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {} @@ -4013,13 +4061,46 @@ public: bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; +} + +CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const { + // Complex types are passed just like their elements + if (const ComplexType *CTy = Ty->getAs<ComplexType>()) + Ty = CTy->getElementType(); + if (Ty->isVectorType()) + return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 + : 4); + + // For single-element float/vector structs, we consider the whole type + // to have the same alignment requirements as its single element. + const Type *AlignTy = nullptr; + if (const Type *EltType = isSingleElementStruct(Ty, getContext())) { + const BuiltinType *BT = EltType->getAs<BuiltinType>(); + if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) || + (BT && BT->isFloatingPoint())) + AlignTy = EltType; + } + + if (AlignTy) + return CharUnits::fromQuantity(AlignTy->isVectorType() ? 16 : 4); + return CharUnits::fromQuantity(4); } // TODO: this implementation is now likely redundant with // DefaultABIInfo::EmitVAArg. Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, QualType Ty) const { + if (getTarget().getTriple().isOSDarwin()) { + auto TI = getContext().getTypeInfoInChars(Ty); + TI.second = getParamTypeAlignment(Ty); + + CharUnits SlotSize = CharUnits::fromQuantity(4); + return emitVoidPtrVAArg(CGF, VAList, Ty, + classifyArgumentType(Ty).isIndirect(), TI, SlotSize, + /*AllowHigherAlign=*/true); + } + const unsigned OverflowLimit = 8; if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { // TODO: Implement this. For now ignore. @@ -4860,7 +4941,7 @@ public: : TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {} StringRef getARCRetainAutoreleasedReturnValueMarker() const override { - return "mov\tfp, fp\t\t# marker for objc_retainAutoreleaseReturnValue"; + return "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue"; } int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { @@ -4869,6 +4950,22 @@ public: bool doesReturnSlotInterfereWithArgs() const override { return false; } }; + +class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { +public: + WindowsAArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind K) + : AArch64TargetCodeGenInfo(CGT, K) {} + + void getDependentLibraryOption(llvm::StringRef Lib, + llvm::SmallString<24> &Opt) const override { + Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib); + } + + void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, + llvm::SmallString<32> &Opt) const override { + Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; + } +}; } ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { @@ -5450,7 +5547,7 @@ public: } StringRef getARCRetainAutoreleasedReturnValueMarker() const override { - return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue"; + return "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue"; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, @@ -5468,7 +5565,10 @@ public: } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override { + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override { + if (!IsForDefinition) + return; const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; @@ -5510,7 +5610,8 @@ public: : ARMTargetCodeGenInfo(CGT, K) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override; + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { @@ -5524,8 +5625,11 @@ public: }; void WindowsARMTargetCodeGenInfo::setTargetAttributes( - const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { - ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM); + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const { + ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition); + if (!IsForDefinition) + return; addStackProbeSizeTargetAttribute(D, GV, CGM); } } @@ -6051,7 +6155,9 @@ public: : TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; + CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const override; + private: // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. @@ -6105,9 +6211,11 @@ Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, llvm_unreachable("NVPTX does not support varargs"); } -void NVPTXTargetCodeGenInfo:: -setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const{ +void NVPTXTargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const { + if (!IsForDefinition) + return; const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; @@ -6211,7 +6319,7 @@ public: return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { - return true; + return false; } }; @@ -6543,14 +6651,17 @@ public: MSP430TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; + CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const override; }; } -void MSP430TargetCodeGenInfo::setTargetAttributes(const Decl *D, - llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const { +void MSP430TargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const { + if (!IsForDefinition) + return; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) { // Handle 'interrupt' attribute: @@ -6609,10 +6720,21 @@ public: } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override { + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override { const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; llvm::Function *Fn = cast<llvm::Function>(GV); + + if (FD->hasAttr<MipsLongCallAttr>()) + Fn->addFnAttr("long-call"); + else if (FD->hasAttr<MipsShortCallAttr>()) + Fn->addFnAttr("short-call"); + + // Other attributes do not have a meaning for declarations. + if (!IsForDefinition) + return; + if (FD->hasAttr<Mips16Attr>()) { Fn->addFnAttr("mips16"); } @@ -6974,7 +7096,10 @@ public: : TargetCodeGenInfo(new DefaultABIInfo(CGT)) { } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override { + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override { + if (!IsForDefinition) + return; const auto *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; auto *Fn = cast<llvm::Function>(GV); @@ -7002,11 +7127,15 @@ public: : DefaultTargetCodeGenInfo(CGT) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; + CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const override; }; void TCETargetCodeGenInfo::setTargetAttributes( - const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const { + if (!IsForDefinition) + return; const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; @@ -7302,38 +7431,138 @@ public: namespace { class AMDGPUABIInfo final : public DefaultABIInfo { +private: + static const unsigned MaxNumRegsForArgsRet = 16; + + unsigned numRegsForType(QualType Ty) const; + + bool isHomogeneousAggregateBaseType(QualType Ty) const override; + bool isHomogeneousAggregateSmallEnough(const Type *Base, + uint64_t Members) const override; + public: - explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) : + DefaultABIInfo(CGT) {} -private: - ABIArgInfo classifyArgumentType(QualType Ty) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyKernelArgumentType(QualType Ty) const; + ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const; void computeInfo(CGFunctionInfo &FI) const override; }; +bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { + return true; +} + +bool AMDGPUABIInfo::isHomogeneousAggregateSmallEnough( + const Type *Base, uint64_t Members) const { + uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32; + + // Homogeneous Aggregates may occupy at most 16 registers. + return Members * NumRegs <= MaxNumRegsForArgsRet; +} + +/// Estimate number of registers the type will use when passed in registers. +unsigned AMDGPUABIInfo::numRegsForType(QualType Ty) const { + unsigned NumRegs = 0; + + if (const VectorType *VT = Ty->getAs<VectorType>()) { + // Compute from the number of elements. The reported size is based on the + // in-memory size, which includes the padding 4th element for 3-vectors. + QualType EltTy = VT->getElementType(); + unsigned EltSize = getContext().getTypeSize(EltTy); + + // 16-bit element vectors should be passed as packed. + if (EltSize == 16) + return (VT->getNumElements() + 1) / 2; + + unsigned EltNumRegs = (EltSize + 31) / 32; + return EltNumRegs * VT->getNumElements(); + } + + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + assert(!RD->hasFlexibleArrayMember()); + + for (const FieldDecl *Field : RD->fields()) { + QualType FieldTy = Field->getType(); + NumRegs += numRegsForType(FieldTy); + } + + return NumRegs; + } + + return (getContext().getTypeSize(Ty) + 31) / 32; +} + void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const { + llvm::CallingConv::ID CC = FI.getCallingConvention(); + if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - unsigned CC = FI.getCallingConvention(); - for (auto &Arg : FI.arguments()) - if (CC == llvm::CallingConv::AMDGPU_KERNEL) - Arg.info = classifyArgumentType(Arg.type); - else - Arg.info = DefaultABIInfo::classifyArgumentType(Arg.type); + unsigned NumRegsLeft = MaxNumRegsForArgsRet; + for (auto &Arg : FI.arguments()) { + if (CC == llvm::CallingConv::AMDGPU_KERNEL) { + Arg.info = classifyKernelArgumentType(Arg.type); + } else { + Arg.info = classifyArgumentType(Arg.type, NumRegsLeft); + } + } } -/// \brief Classify argument of given type \p Ty. -ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty) const { - llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty)); - if (!StrTy) { - return DefaultABIInfo::classifyArgumentType(Ty); +ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const { + if (isAggregateTypeForABI(RetTy)) { + // Records with non-trivial destructors/copy-constructors should not be + // returned by value. + if (!getRecordArgABI(RetTy, getCXXABI())) { + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), RetTy, true)) + return ABIArgInfo::getIgnore(); + + // Lower single-element structs to just return a regular value. + if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) + return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + + if (const RecordType *RT = RetTy->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyReturnType(RetTy); + } + + // Pack aggregates <= 4 bytes into single VGPR or pair. + uint64_t Size = getContext().getTypeSize(RetTy); + if (Size <= 16) + return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); + + if (Size <= 32) + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); + + if (Size <= 64) { + llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext()); + return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2)); + } + + if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet) + return ABIArgInfo::getDirect(); + } } + // Otherwise just do the default thing. + return DefaultABIInfo::classifyReturnType(RetTy); +} + +/// For kernels all parameters are really passed in a special buffer. It doesn't +/// make sense to pass anything byval, so everything must be direct. +ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const { + Ty = useFirstFieldIfTransparentUnion(Ty); + + // TODO: Can we omit empty structs? + // Coerce single element structs to its element. - if (StrTy->getNumElements() == 1) { - return ABIArgInfo::getDirect(); - } + if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) + return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // If we set CanBeFlattened to true, CodeGen will expand the struct to its // individual elements, which confuses the Clover OpenCL backend; therefore we @@ -7341,30 +7570,102 @@ ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } +ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, + unsigned &NumRegsLeft) const { + assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow"); + + Ty = useFirstFieldIfTransparentUnion(Ty); + + if (isAggregateTypeForABI(Ty)) { + // Records with non-trivial destructors/copy-constructors should not be + // passed by value. + if (auto RAA = getRecordArgABI(Ty, getCXXABI())) + return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + // Lower single-element structs to just pass a regular value. TODO: We + // could do reasonable-size multiple-element structs too, using getExpand(), + // though watch out for things like bitfields. + if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) + return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return DefaultABIInfo::classifyArgumentType(Ty); + } + + // Pack aggregates <= 8 bytes into single VGPR or pair. + uint64_t Size = getContext().getTypeSize(Ty); + if (Size <= 64) { + unsigned NumRegs = (Size + 31) / 32; + NumRegsLeft -= std::min(NumRegsLeft, NumRegs); + + if (Size <= 16) + return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); + + if (Size <= 32) + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); + + // XXX: Should this be i64 instead, and should the limit increase? + llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext()); + return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2)); + } + + if (NumRegsLeft > 0) { + unsigned NumRegs = numRegsForType(Ty); + if (NumRegsLeft >= NumRegs) { + NumRegsLeft -= NumRegs; + return ABIArgInfo::getDirect(); + } + } + } + + // Otherwise just do the default thing. + ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty); + if (!ArgInfo.isIndirect()) { + unsigned NumRegs = numRegsForType(Ty); + NumRegsLeft -= std::min(NumRegs, NumRegsLeft); + } + + return ArgInfo; +} + class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { public: AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new AMDGPUABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; + CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const override; unsigned getOpenCLKernelCallingConv() const override; llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const override; - unsigned getASTAllocaAddressSpace() const override { - return LangAS::FirstTargetAddressSpace + - getABIInfo().getDataLayout().getAllocaAddrSpace(); + LangAS getASTAllocaAddressSpace() const override { + return getLangASFromTargetAS( + getABIInfo().getDataLayout().getAllocaAddrSpace()); } - unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, - const VarDecl *D) const override; + LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const override; + llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S, + llvm::LLVMContext &C) const override; + llvm::Function * + createEnqueuedBlockKernel(CodeGenFunction &CGF, + llvm::Function *BlockInvokeFunc, + llvm::Value *BlockLiteral) const override; }; } void AMDGPUTargetCodeGenInfo::setTargetAttributes( - const Decl *D, - llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const { + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const { + if (!IsForDefinition) + return; const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; @@ -7441,21 +7742,19 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer( llvm::ConstantPointerNull::get(NPT), PT); } -unsigned +LangAS AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const { assert(!CGM.getLangOpts().OpenCL && !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && "Address space agnostic languages only"); - unsigned DefaultGlobalAS = - LangAS::FirstTargetAddressSpace + - CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + LangAS DefaultGlobalAS = getLangASFromTargetAS( + CGM.getContext().getTargetAddressSpace(LangAS::opencl_global)); if (!D) return DefaultGlobalAS; - unsigned AddrSpace = D->getType().getAddressSpace(); - assert(AddrSpace == LangAS::Default || - AddrSpace >= LangAS::FirstTargetAddressSpace); + LangAS AddrSpace = D->getType().getAddressSpace(); + assert(AddrSpace == LangAS::Default || isTargetAddressSpace(AddrSpace)); if (AddrSpace != LangAS::Default) return AddrSpace; @@ -7466,6 +7765,26 @@ AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, return DefaultGlobalAS; } +llvm::SyncScope::ID +AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S, + llvm::LLVMContext &C) const { + StringRef Name; + switch (S) { + case SyncScope::OpenCLWorkGroup: + Name = "workgroup"; + break; + case SyncScope::OpenCLDevice: + Name = "agent"; + break; + case SyncScope::OpenCLAllSVMDevices: + Name = ""; + break; + case SyncScope::OpenCLSubGroup: + Name = "subgroup"; + } + return C.getOrInsertSyncScopeID(Name); +} + //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. @@ -8506,7 +8825,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (getTarget().getABI() == "darwinpcs") Kind = AArch64ABIInfo::DarwinPCS; else if (Triple.isOSWindows()) - Kind = AArch64ABIInfo::Win64; + return SetCGInfo( + new WindowsAArch64TargetCodeGenInfo(Types, AArch64ABIInfo::Win64)); return SetCGInfo(new AArch64TargetCodeGenInfo(Types, Kind)); } @@ -8636,3 +8956,108 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return SetCGInfo(new SPIRTargetCodeGenInfo(Types)); } } + +/// Create an OpenCL kernel for an enqueued block. +/// +/// The kernel has the same function type as the block invoke function. Its +/// name is the name of the block invoke function postfixed with "_kernel". +/// It simply calls the block invoke function then returns. +llvm::Function * +TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF, + llvm::Function *Invoke, + llvm::Value *BlockLiteral) const { + auto *InvokeFT = Invoke->getFunctionType(); + llvm::SmallVector<llvm::Type *, 2> ArgTys; + for (auto &P : InvokeFT->params()) + ArgTys.push_back(P); + auto &C = CGF.getLLVMContext(); + std::string Name = Invoke->getName().str() + "_kernel"; + auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false); + auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name, + &CGF.CGM.getModule()); + auto IP = CGF.Builder.saveIP(); + auto *BB = llvm::BasicBlock::Create(C, "entry", F); + auto &Builder = CGF.Builder; + Builder.SetInsertPoint(BB); + llvm::SmallVector<llvm::Value *, 2> Args; + for (auto &A : F->args()) + Args.push_back(&A); + Builder.CreateCall(Invoke, Args); + Builder.CreateRetVoid(); + Builder.restoreIP(IP); + return F; +} + +/// Create an OpenCL kernel for an enqueued block. +/// +/// The type of the first argument (the block literal) is the struct type +/// of the block literal instead of a pointer type. The first argument +/// (block literal) is passed directly by value to the kernel. The kernel +/// allocates the same type of struct on stack and stores the block literal +/// to it and passes its pointer to the block invoke function. The kernel +/// has "enqueued-block" function attribute and kernel argument metadata. +llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel( + CodeGenFunction &CGF, llvm::Function *Invoke, + llvm::Value *BlockLiteral) const { + auto &Builder = CGF.Builder; + auto &C = CGF.getLLVMContext(); + + auto *BlockTy = BlockLiteral->getType()->getPointerElementType(); + auto *InvokeFT = Invoke->getFunctionType(); + llvm::SmallVector<llvm::Type *, 2> ArgTys; + llvm::SmallVector<llvm::Metadata *, 8> AddressQuals; + llvm::SmallVector<llvm::Metadata *, 8> AccessQuals; + llvm::SmallVector<llvm::Metadata *, 8> ArgTypeNames; + llvm::SmallVector<llvm::Metadata *, 8> ArgBaseTypeNames; + llvm::SmallVector<llvm::Metadata *, 8> ArgTypeQuals; + llvm::SmallVector<llvm::Metadata *, 8> ArgNames; + + ArgTys.push_back(BlockTy); + ArgTypeNames.push_back(llvm::MDString::get(C, "__block_literal")); + AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(0))); + ArgBaseTypeNames.push_back(llvm::MDString::get(C, "__block_literal")); + ArgTypeQuals.push_back(llvm::MDString::get(C, "")); + AccessQuals.push_back(llvm::MDString::get(C, "none")); + ArgNames.push_back(llvm::MDString::get(C, "block_literal")); + for (unsigned I = 1, E = InvokeFT->getNumParams(); I < E; ++I) { + ArgTys.push_back(InvokeFT->getParamType(I)); + ArgTypeNames.push_back(llvm::MDString::get(C, "void*")); + AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(3))); + AccessQuals.push_back(llvm::MDString::get(C, "none")); + ArgBaseTypeNames.push_back(llvm::MDString::get(C, "void*")); + ArgTypeQuals.push_back(llvm::MDString::get(C, "")); + ArgNames.push_back( + llvm::MDString::get(C, (Twine("local_arg") + Twine(I)).str())); + } + std::string Name = Invoke->getName().str() + "_kernel"; + auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false); + auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name, + &CGF.CGM.getModule()); + F->addFnAttr("enqueued-block"); + auto IP = CGF.Builder.saveIP(); + auto *BB = llvm::BasicBlock::Create(C, "entry", F); + Builder.SetInsertPoint(BB); + unsigned BlockAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(BlockTy); + auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr); + BlockPtr->setAlignment(BlockAlign); + Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign); + auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0)); + llvm::SmallVector<llvm::Value *, 2> Args; + Args.push_back(Cast); + for (auto I = F->arg_begin() + 1, E = F->arg_end(); I != E; ++I) + Args.push_back(I); + Builder.CreateCall(Invoke, Args); + Builder.CreateRetVoid(); + Builder.restoreIP(IP); + + F->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(C, AddressQuals)); + F->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(C, AccessQuals)); + F->setMetadata("kernel_arg_type", llvm::MDNode::get(C, ArgTypeNames)); + F->setMetadata("kernel_arg_base_type", + llvm::MDNode::get(C, ArgBaseTypeNames)); + F->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(C, ArgTypeQuals)); + if (CGF.CGM.getCodeGenOpts().EmitOpenCLArgMetadata) + F->setMetadata("kernel_arg_name", llvm::MDNode::get(C, ArgNames)); + + return F; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h index 952ef96c4aef7..d745e420c4a56 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h @@ -15,9 +15,11 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H #define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H +#include "CodeGenModule.h" #include "CGValue.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/SyncScope.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -34,8 +36,8 @@ class Decl; namespace CodeGen { class ABIInfo; class CallArgList; -class CodeGenModule; class CodeGenFunction; +class CGBlockInfo; class CGFunctionInfo; /// TargetCodeGenInfo - This class organizes various target-specific @@ -55,7 +57,8 @@ public: /// setTargetAttributes - Provides a convenient hook to handle extra /// target-specific attributes for the given global. virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const {} + CodeGen::CodeGenModule &M, + ForDefinition_t IsForDefinition) const {} /// emitTargetMD - Provides a convenient hook to handle extra /// target-specific metadata for the given global. @@ -233,11 +236,11 @@ public: /// other than OpenCL and CUDA. /// If \p D is nullptr, returns the default target favored address space /// for global variable. - virtual unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, - const VarDecl *D) const; + virtual LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const; /// Get the AST address space for alloca. - virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; } + virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; } /// Perform address space cast of an expression of pointer type. /// \param V is the LLVM value to be casted to another address space. @@ -246,9 +249,8 @@ public: /// \param DestTy is the destination LLVM pointer type. /// \param IsNonNull is the flag indicating \p V is known to be non null. virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction &CGF, - llvm::Value *V, unsigned SrcAddr, - unsigned DestAddr, - llvm::Type *DestTy, + llvm::Value *V, LangAS SrcAddr, + LangAS DestAddr, llvm::Type *DestTy, bool IsNonNull = false) const; /// Perform address space cast of a constant expression of pointer type. @@ -256,9 +258,45 @@ public: /// \param SrcAddr is the language address space of \p V. /// \param DestAddr is the targeted language address space. /// \param DestTy is the destination LLVM pointer type. - virtual llvm::Constant * - performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *V, unsigned SrcAddr, - unsigned DestAddr, llvm::Type *DestTy) const; + virtual llvm::Constant *performAddrSpaceCast(CodeGenModule &CGM, + llvm::Constant *V, + LangAS SrcAddr, LangAS DestAddr, + llvm::Type *DestTy) const; + + /// Get the syncscope used in LLVM IR. + virtual llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S, + llvm::LLVMContext &C) const; + + /// Inteface class for filling custom fields of a block literal for OpenCL. + class TargetOpenCLBlockHelper { + public: + typedef std::pair<llvm::Value *, StringRef> ValueTy; + TargetOpenCLBlockHelper() {} + virtual ~TargetOpenCLBlockHelper() {} + /// Get the custom field types for OpenCL blocks. + virtual llvm::SmallVector<llvm::Type *, 1> getCustomFieldTypes() = 0; + /// Get the custom field values for OpenCL blocks. + virtual llvm::SmallVector<ValueTy, 1> + getCustomFieldValues(CodeGenFunction &CGF, const CGBlockInfo &Info) = 0; + virtual bool areAllCustomFieldValuesConstant(const CGBlockInfo &Info) = 0; + /// Get the custom field values for OpenCL blocks if all values are LLVM + /// constants. + virtual llvm::SmallVector<llvm::Constant *, 1> + getCustomFieldValues(CodeGenModule &CGM, const CGBlockInfo &Info) = 0; + }; + virtual TargetOpenCLBlockHelper *getTargetOpenCLBlockHelper() const { + return nullptr; + } + + /// Create an OpenCL kernel for an enqueued block. The kernel function is + /// a wrapper for the block invoke function with target-specific calling + /// convention and ABI as an OpenCL kernel. The wrapper function accepts + /// block context and block arguments in target-specific way and calls + /// the original block invoke function. + virtual llvm::Function * + createEnqueuedBlockKernel(CodeGenFunction &CGF, + llvm::Function *BlockInvokeFunc, + llvm::Value *BlockLiteral) const; }; } // namespace CodeGen diff --git a/contrib/llvm/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp b/contrib/llvm/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp new file mode 100644 index 0000000000000..e20ea7702237c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -0,0 +1,269 @@ +//===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CrossTranslationUnit interface. +// +//===----------------------------------------------------------------------===// +#include "clang/CrossTU/CrossTranslationUnit.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CrossTU/CrossTUDiagnostic.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Index/USRGeneration.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <fstream> +#include <sstream> + +namespace clang { +namespace cross_tu { + +namespace { +// FIXME: This class is will be removed after the transition to llvm::Error. +class IndexErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "clang.index"; } + + std::string message(int Condition) const override { + switch (static_cast<index_error_code>(Condition)) { + case index_error_code::unspecified: + return "An unknown error has occurred."; + case index_error_code::missing_index_file: + return "The index file is missing."; + case index_error_code::invalid_index_format: + return "Invalid index file format."; + case index_error_code::multiple_definitions: + return "Multiple definitions in the index file."; + case index_error_code::missing_definition: + return "Missing definition from the index file."; + case index_error_code::failed_import: + return "Failed to import the definition."; + case index_error_code::failed_to_get_external_ast: + return "Failed to load external AST source."; + case index_error_code::failed_to_generate_usr: + return "Failed to generate USR."; + } + llvm_unreachable("Unrecognized index_error_code."); + } +}; + +static llvm::ManagedStatic<IndexErrorCategory> Category; +} // end anonymous namespace + +char IndexError::ID; + +void IndexError::log(raw_ostream &OS) const { + OS << Category->message(static_cast<int>(Code)) << '\n'; +} + +std::error_code IndexError::convertToErrorCode() const { + return std::error_code(static_cast<int>(Code), *Category); +} + +llvm::Expected<llvm::StringMap<std::string>> +parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) { + std::ifstream ExternalFnMapFile(IndexPath); + if (!ExternalFnMapFile) + return llvm::make_error<IndexError>(index_error_code::missing_index_file, + IndexPath.str()); + + llvm::StringMap<std::string> Result; + std::string Line; + unsigned LineNo = 1; + while (std::getline(ExternalFnMapFile, Line)) { + const size_t Pos = Line.find(" "); + if (Pos > 0 && Pos != std::string::npos) { + StringRef LineRef{Line}; + StringRef FunctionLookupName = LineRef.substr(0, Pos); + if (Result.count(FunctionLookupName)) + return llvm::make_error<IndexError>( + index_error_code::multiple_definitions, IndexPath.str(), LineNo); + StringRef FileName = LineRef.substr(Pos + 1); + SmallString<256> FilePath = CrossTUDir; + llvm::sys::path::append(FilePath, FileName); + Result[FunctionLookupName] = FilePath.str().str(); + } else + return llvm::make_error<IndexError>( + index_error_code::invalid_index_format, IndexPath.str(), LineNo); + LineNo++; + } + return Result; +} + +std::string +createCrossTUIndexString(const llvm::StringMap<std::string> &Index) { + std::ostringstream Result; + for (const auto &E : Index) + Result << E.getKey().str() << " " << E.getValue() << '\n'; + return Result.str(); +} + +CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) + : CI(CI), Context(CI.getASTContext()) {} + +CrossTranslationUnitContext::~CrossTranslationUnitContext() {} + +std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { + SmallString<128> DeclUSR; + bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret; + assert(!Ret && "Unable to generate USR"); + return DeclUSR.str(); +} + +/// Recursively visits the function decls of a DeclContext, and looks up a +/// function based on USRs. +const FunctionDecl * +CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC, + StringRef LookupFnName) { + assert(DC && "Declaration Context must not be null"); + for (const Decl *D : DC->decls()) { + const auto *SubDC = dyn_cast<DeclContext>(D); + if (SubDC) + if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName)) + return FD; + + const auto *ND = dyn_cast<FunctionDecl>(D); + const FunctionDecl *ResultDecl; + if (!ND || !ND->hasBody(ResultDecl)) + continue; + if (getLookupName(ResultDecl) != LookupFnName) + continue; + return ResultDecl; + } + return nullptr; +} + +llvm::Expected<const FunctionDecl *> +CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, + StringRef CrossTUDir, + StringRef IndexName) { + assert(!FD->hasBody() && "FD has a definition in current translation unit!"); + const std::string LookupFnName = getLookupName(FD); + if (LookupFnName.empty()) + return llvm::make_error<IndexError>( + index_error_code::failed_to_generate_usr); + llvm::Expected<ASTUnit *> ASTUnitOrError = + loadExternalAST(LookupFnName, CrossTUDir, IndexName); + if (!ASTUnitOrError) + return ASTUnitOrError.takeError(); + ASTUnit *Unit = *ASTUnitOrError; + if (!Unit) + return llvm::make_error<IndexError>( + index_error_code::failed_to_get_external_ast); + assert(&Unit->getFileManager() == + &Unit->getASTContext().getSourceManager().getFileManager()); + + TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); + if (const FunctionDecl *ResultDecl = + findFunctionInDeclContext(TU, LookupFnName)) + return importDefinition(ResultDecl); + return llvm::make_error<IndexError>(index_error_code::failed_import); +} + +void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { + switch (IE.getCode()) { + case index_error_code::missing_index_file: + Context.getDiagnostics().Report(diag::err_fe_error_opening) + << IE.getFileName() << "required by the CrossTU functionality"; + break; + case index_error_code::invalid_index_format: + Context.getDiagnostics().Report(diag::err_fnmap_parsing) + << IE.getFileName() << IE.getLineNum(); + break; + case index_error_code::multiple_definitions: + Context.getDiagnostics().Report(diag::err_multiple_def_index) + << IE.getLineNum(); + break; + default: + break; + } +} + +llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( + StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) { + // FIXME: The current implementation only supports loading functions with + // a lookup name from a single translation unit. If multiple + // translation units contains functions with the same lookup name an + // error will be returned. + ASTUnit *Unit = nullptr; + auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName); + if (FnUnitCacheEntry == FunctionASTUnitMap.end()) { + if (FunctionFileMap.empty()) { + SmallString<256> IndexFile = CrossTUDir; + if (llvm::sys::path::is_absolute(IndexName)) + IndexFile = IndexName; + else + llvm::sys::path::append(IndexFile, IndexName); + llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = + parseCrossTUIndex(IndexFile, CrossTUDir); + if (IndexOrErr) + FunctionFileMap = *IndexOrErr; + else + return IndexOrErr.takeError(); + } + + auto It = FunctionFileMap.find(LookupName); + if (It == FunctionFileMap.end()) + return llvm::make_error<IndexError>(index_error_code::missing_definition); + StringRef ASTFileName = It->second; + auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); + if (ASTCacheEntry == FileASTUnitMap.end()) { + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); + + std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile( + ASTFileName, CI.getPCHContainerOperations()->getRawReader(), + ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); + Unit = LoadedUnit.get(); + FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); + } else { + Unit = ASTCacheEntry->second.get(); + } + FunctionASTUnitMap[LookupName] = Unit; + } else { + Unit = FnUnitCacheEntry->second; + } + return Unit; +} + +llvm::Expected<const FunctionDecl *> +CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { + ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext()); + auto *ToDecl = + cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD))); + assert(ToDecl->hasBody()); + assert(FD->hasBody() && "Functions already imported should have body."); + return ToDecl; +} + +ASTImporter & +CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { + auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); + if (I != ASTUnitImporterMap.end()) + return *I->second; + ASTImporter *NewImporter = + new ASTImporter(Context, Context.getSourceManager().getFileManager(), + From, From.getSourceManager().getFileManager(), false); + ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); + return *NewImporter; +} + +} // namespace cross_tu +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index cf86644fb8cdf..645da50595877 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -26,9 +26,9 @@ Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs, bool ContainsError) : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u), - Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr), - ForDiagnostics(false), ContainsError(ContainsError) { - // The offloading host toolchain is the default tool chain. + Args(_Args), TranslatedArgs(_TranslatedArgs), ForDiagnostics(false), + ContainsError(ContainsError) { + // The offloading host toolchain is the default toolchain. OrderedOffloadingToolchains.insert( std::make_pair(Action::OFK_Host, &DefaultToolChain)); } @@ -41,14 +41,6 @@ Compilation::~Compilation() { for (auto Arg : TCArgs) if (Arg.second != TranslatedArgs) delete Arg.second; - - // Free redirections of stdout/stderr. - if (Redirects) { - delete Redirects[0]; - delete Redirects[1]; - delete Redirects[2]; - delete [] Redirects; - } } const DerivedArgList & @@ -59,9 +51,32 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}]; if (!Entry) { - Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); - if (!Entry) - Entry = TranslatedArgs; + SmallVector<Arg *, 4> AllocatedArgs; + DerivedArgList *OpenMPArgs = nullptr; + // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>(); + bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple()); + OpenMPArgs = TC->TranslateOpenMPTargetArgs( + *TranslatedArgs, SameTripleAsHost, AllocatedArgs); + } + + if (!OpenMPArgs) { + Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); + if (!Entry) + Entry = TranslatedArgs; + } else { + Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind); + if (!Entry) + Entry = OpenMPArgs; + else + delete OpenMPArgs; + } + + // Add allocated arguments to the final DAL. + for (auto ArgPtr : AllocatedArgs) { + Entry->AddSynthesizedArg(ArgPtr); + } } return *Entry; @@ -167,16 +182,51 @@ int Compilation::ExecuteCommand(const Command &C, return ExecutionFailed ? 1 : Res; } -void Compilation::ExecuteJobs( - const JobList &Jobs, - SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const { +using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>; + +static bool ActionFailed(const Action *A, + const FailingCommandList &FailingCommands) { + + if (FailingCommands.empty()) + return false; + + // CUDA can have the same input source code compiled multiple times so do not + // compiled again if there are already failures. It is OK to abort the CUDA + // pipeline on errors. + if (A->isOffloading(Action::OFK_Cuda)) + return true; + + for (const auto &CI : FailingCommands) + if (A == &(CI.second->getSource())) + return true; + + for (const Action *AI : A->inputs()) + if (ActionFailed(AI, FailingCommands)) + return true; + + return false; +} + +static bool InputsOk(const Command &C, + const FailingCommandList &FailingCommands) { + return !ActionFailed(&C.getSource(), FailingCommands); +} + +void Compilation::ExecuteJobs(const JobList &Jobs, + FailingCommandList &FailingCommands) const { + // According to UNIX standard, driver need to continue compiling all the + // inputs on the command line even one of them failed. + // In all but CLMode, execute all the jobs unless the necessary inputs for the + // job is missing due to previous failures. for (const auto &Job : Jobs) { + if (!InputsOk(Job, FailingCommands)) + continue; const Command *FailingCommand = nullptr; if (int Res = ExecuteCommand(Job, FailingCommand)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); - // Bail as soon as one command fails, so we don't output duplicate error - // messages if we die on e.g. the same file. - return; + // Bail as soon as one command fails in cl driver mode. + if (TheDriver.IsCLMode()) + return; } } } @@ -205,16 +255,13 @@ void Compilation::initCompilationForDiagnostics() { TranslatedArgs->ClaimAllArgs(); // Redirect stdout/stderr to /dev/null. - Redirects = new const StringRef*[3](); - Redirects[0] = nullptr; - Redirects[1] = new StringRef(); - Redirects[2] = new StringRef(); + Redirects = {None, {""}, {""}}; } StringRef Compilation::getSysRoot() const { return getDriver().SysRoot; } -void Compilation::Redirect(const StringRef** Redirects) { +void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) { this->Redirects = Redirects; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Distro.cpp b/contrib/llvm/tools/clang/lib/Driver/Distro.cpp index 2df297f3cfc2d..f15c919b9aae1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Distro.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Distro.cpp @@ -48,6 +48,7 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { .Case("yakkety", Distro::UbuntuYakkety) .Case("zesty", Distro::UbuntuZesty) .Case("artful", Distro::UbuntuArtful) + .Case("bionic", Distro::UbuntuBionic) .Default(Distro::UnknownDistro); if (Version != Distro::UnknownDistro) return Version; @@ -88,6 +89,8 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { return Distro::DebianJessie; case 9: return Distro::DebianStretch; + case 10: + return Distro::DebianBuster; default: return Distro::UnknownDistro; } @@ -126,6 +129,9 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { if (VFS.exists("/etc/exherbo-release")) return Distro::Exherbo; + if (VFS.exists("/etc/alpine-release")) + return Distro::AlpineLinux; + if (VFS.exists("/etc/arch-release")) return Distro::ArchLinux; diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index ba4d0e836b44e..9ae33b80f8898 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -12,7 +12,6 @@ #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" -#include "ToolChains/Bitrig.h" #include "ToolChains/Clang.h" #include "ToolChains/CloudABI.h" #include "ToolChains/Contiki.h" @@ -69,6 +68,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include <map> #include <memory> @@ -87,7 +87,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, : Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), - SysRoot(DEFAULT_SYSROOT), UseStdLib(true), + SysRoot(DEFAULT_SYSROOT), DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr), CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false), @@ -119,9 +119,8 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, void Driver::ParseDriverMode(StringRef ProgramName, ArrayRef<const char *> Args) { - auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName); - StringRef DefaultMode(Default.second); - setDriverModeFromOption(DefaultMode); + ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName); + setDriverModeFromOption(ClangNameParts.DriverMode); for (const char *ArgPtr : Args) { // Ingore nullptrs, they are response file's EOL markers @@ -524,7 +523,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()]; if (!CudaTC) { CudaTC = llvm::make_unique<toolchains::CudaToolChain>( - *this, CudaTriple, *HostTC, C.getInputArgs()); + *this, CudaTriple, *HostTC, C.getInputArgs(), Action::OFK_Cuda); } C.addOffloadDeviceToolChain(CudaTC.get(), Action::OFK_Cuda); } @@ -579,10 +578,10 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, C.getSingleOffloadToolChain<Action::OFK_Host>(); assert(HostTC && "Host toolchain should be always defined."); auto &CudaTC = - ToolChains[TT.str() + "/" + HostTC->getTriple().str()]; + ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; if (!CudaTC) CudaTC = llvm::make_unique<toolchains::CudaToolChain>( - *this, TT, *HostTC, C.getInputArgs()); + *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP); TC = CudaTC.get(); } else TC = &getToolChain(C.getInputArgs(), TT); @@ -599,8 +598,6 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // // TODO: Add support for other offloading programming models here. // - - return; } Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { @@ -664,6 +661,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { T.setOS(llvm::Triple::Win32); T.setVendor(llvm::Triple::PC); T.setEnvironment(llvm::Triple::MSVC); + T.setObjectFormat(llvm::Triple::COFF); DefaultTargetTriple = T.str(); } if (const Arg *A = Args.getLastArg(options::OPT_target)) @@ -678,8 +676,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { SysRoot = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) DyldPrefix = A->getValue(); - if (Args.hasArg(options::OPT_nostdlib)) - UseStdLib = false; if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) ResourceDir = A->getValue(); @@ -1126,7 +1122,8 @@ void Driver::PrintHelp(bool ShowHidden) const { ExcludedFlagsBitmask |= HelpHidden; getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), - IncludedFlagsBitmask, ExcludedFlagsBitmask); + IncludedFlagsBitmask, ExcludedFlagsBitmask, + /*ShowAllAliases=*/false); } void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { @@ -1158,6 +1155,58 @@ static void PrintDiagnosticCategories(raw_ostream &OS) { OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n'; } +void Driver::handleAutocompletions(StringRef PassedFlags) const { + // Print out all options that start with a given argument. This is used for + // shell autocompletion. + std::vector<std::string> SuggestedCompletions; + + unsigned short DisableFlags = + options::NoDriverOption | options::Unsupported | options::Ignored; + // We want to show cc1-only options only when clang is invoked as "clang + // -cc1". When clang is invoked as "clang -cc1", we add "#" to the beginning + // of an --autocomplete option so that the clang driver can distinguish + // whether it is requested to show cc1-only options or not. + if (PassedFlags.size() > 0 && PassedFlags[0] == '#') { + DisableFlags &= ~options::NoDriverOption; + PassedFlags = PassedFlags.substr(1); + } + + if (PassedFlags.find(',') == StringRef::npos) { + // If the flag is in the form of "--autocomplete=-foo", + // we were requested to print out all option names that start with "-foo". + // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". + SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); + + // We have to query the -W flags manually as they're not in the OptTable. + // TODO: Find a good way to add them to OptTable instead and them remove + // this code. + for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) + if (S.startswith(PassedFlags)) + SuggestedCompletions.push_back(S); + } else { + // If the flag is in the form of "--autocomplete=foo,bar", we were + // requested to print out all option values for "-foo" that start with + // "bar". For example, + // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++". + StringRef Option, Arg; + std::tie(Option, Arg) = PassedFlags.split(','); + SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg); + } + + // Sort the autocomplete candidates so that shells print them out in a + // deterministic order. We could sort in any way, but we chose + // case-insensitive sorting for consistency with the -help option + // which prints out options in the case-insensitive alphabetical order. + std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), + [](StringRef A, StringRef B) { + if (int X = A.compare_lower(B)) + return X < 0; + return A.compare(B) > 0; + }); + + llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; +} + bool Driver::HandleImmediateArgs(const Compilation &C) { // The order these options are handled in gcc is all over the place, but we // don't expect inconsistencies w.r.t. that to matter in practice. @@ -1251,55 +1300,15 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { - // Print out all options that start with a given argument. This is used for - // shell autocompletion. StringRef PassedFlags = A->getValue(); - std::vector<std::string> SuggestedCompletions; - - unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; - // We want to show cc1-only options only when clang is invoked as "clang -cc1". - // When clang is invoked as "clang -cc1", we add "#" to the beginning of an --autocomplete - // option so that the clang driver can distinguish whether it is requested to show cc1-only options or not. - if (PassedFlags[0] == '#') { - DisableFlags &= ~options::NoDriverOption; - PassedFlags = PassedFlags.substr(1); - } - - if (PassedFlags.find(',') == StringRef::npos) { - // If the flag is in the form of "--autocomplete=-foo", - // we were requested to print out all option names that start with "-foo". - // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". - SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); - - // We have to query the -W flags manually as they're not in the OptTable. - // TODO: Find a good way to add them to OptTable instead and them remove - // this code. - for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) - if (S.startswith(PassedFlags)) - SuggestedCompletions.push_back(S); - } else { - // If the flag is in the form of "--autocomplete=foo,bar", we were - // requested to print out all option values for "-foo" that start with - // "bar". For example, - // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++". - StringRef Option, Arg; - std::tie(Option, Arg) = PassedFlags.split(','); - SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg); - } - - // Sort the autocomplete candidates so that shells print them out in a - // deterministic order. We could sort in any way, but we chose - // case-insensitive sorting for consistency with the -help option - // which prints out options in the case-insensitive alphabetical order. - std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), - [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; }); - - llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; + handleAutocompletions(PassedFlags); return false; } if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs()); + const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(C.getArgs())); + RegisterEffectiveTriple TripleRAII(TC, Triple); switch (RLT) { case ToolChain::RLT_CompilerRT: llvm::outs() << TC.getCompilerRT(C.getArgs(), "builtins") << "\n"; @@ -3225,6 +3234,12 @@ InputInfo Driver::BuildJobsForActionNoCache( InputInfoList OffloadDependencesInputInfo; bool BuildingForOffloadDevice = TargetDeviceOffloadKind != Action::OFK_None; if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) { + // The 'Darwin' toolchain is initialized only when its arguments are + // computed. Get the default arguments for OFK_None to ensure that + // initialization is performed before processing the offload action. + // FIXME: Remove when darwin's toolchain is initialized during construction. + C.getArgsForToolChain(TC, BoundArch, Action::OFK_None); + // The offload action is expected to be used in four different situations. // // a) Set a toolchain/architecture/kind for a host action: @@ -3402,7 +3417,7 @@ InputInfo Driver::BuildJobsForActionNoCache( // Get the unique string identifier for this dependence and cache the // result. CachedResults[{A, GetTriplePlusArchString( - UI.DependentToolChain, UI.DependentBoundArch, + UI.DependentToolChain, BoundArch, UI.DependentOffloadKind)}] = CurI; } @@ -3677,7 +3692,12 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { return P.str(); } - SmallString<128> P(ResourceDir); + SmallString<128> R(ResourceDir); + llvm::sys::path::append(R, Name); + if (llvm::sys::fs::exists(Twine(R))) + return R.str(); + + SmallString<128> P(TC.getCompilerRTPath()); llvm::sys::path::append(P, Name); if (llvm::sys::fs::exists(Twine(P))) return P.str(); @@ -3810,9 +3830,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::OpenBSD: TC = llvm::make_unique<toolchains::OpenBSD>(*this, Target, Args); break; - case llvm::Triple::Bitrig: - TC = llvm::make_unique<toolchains::Bitrig>(*this, Target, Args); - break; case llvm::Triple::NetBSD: TC = llvm::make_unique<toolchains::NetBSD>(*this, Target, Args); break; @@ -3865,7 +3882,13 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, break; case llvm::Triple::MSVC: case llvm::Triple::UnknownEnvironment: - TC = llvm::make_unique<toolchains::MSVCToolChain>(*this, Target, Args); + if (Args.getLastArgValue(options::OPT_fuse_ld_EQ) + .startswith_lower("bfd")) + TC = llvm::make_unique<toolchains::CrossWindowsToolChain>( + *this, Target, Args); + else + TC = + llvm::make_unique<toolchains::MSVCToolChain>(*this, Target, Args); break; } break; diff --git a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp index ac63b96cf96d1..11e7e4c8fe2bd 100644 --- a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" +#include <cassert> using namespace clang::driver; using namespace clang::driver::options; @@ -40,5 +41,13 @@ public: } std::unique_ptr<OptTable> clang::driver::createDriverOptTable() { - return llvm::make_unique<DriverOptTable>(); + auto Result = llvm::make_unique<DriverOptTable>(); + // Options.inc is included in DriverOptions.cpp, and calls OptTable's + // addValues function. + // Opt is a variable used in the code fragment in Options.inc. + OptTable &Opt = *Result; +#define OPTTABLE_ARG_INIT +#include "clang/Driver/Options.inc" +#undef OPTTABLE_ARG_INIT + return std::move(Result); } diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 8b85680f10b14..765c05752d8f3 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -14,6 +14,7 @@ #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -307,8 +308,8 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { Environment.push_back(nullptr); } -int Command::Execute(const StringRef **Redirects, std::string *ErrMsg, - bool *ExecutionFailed) const { +int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const { SmallVector<const char*, 128> Argv; const char **Envp; @@ -378,8 +379,8 @@ static bool ShouldFallback(int ExitCode) { return ExitCode != 0; } -int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg, - bool *ExecutionFailed) const { +int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const { int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); if (!ShouldFallback(PrimaryStatus)) return PrimaryStatus; @@ -410,7 +411,7 @@ void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator, OS << " || (exit 0)" << Terminator; } -int ForceSuccessCommand::Execute(const StringRef **Redirects, +int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const { int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed); diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp index 7a442c83e1588..f617d8b4551e3 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -29,10 +29,12 @@ enum : SanitizerMask { NeedsUbsanRt = Undefined | Integer | Nullability | CFI, NeedsUbsanCxxRt = Vptr | CFI, NotAllowedWithTrap = Vptr, - RequiresPIE = DataFlow, - NeedsUnwindTables = Address | Thread | Memory | DataFlow, - SupportsCoverage = Address | KernelAddress | Memory | Leak | Undefined | - Integer | Nullability | DataFlow | Fuzzer, + NotAllowedWithMinimalRuntime = Vptr, + RequiresPIE = DataFlow | Scudo, + NeedsUnwindTables = Address | HWAddress | Thread | Memory | DataFlow, + SupportsCoverage = Address | HWAddress | KernelAddress | Memory | Leak | + Undefined | Integer | Nullability | DataFlow | Fuzzer | + FuzzerNoLink, RecoverableByDefault = Undefined | Integer | Nullability, Unrecoverable = Unreachable | Return, LegacyFsanitizeRecoverMask = Undefined | Integer, @@ -41,6 +43,7 @@ enum : SanitizerMask { Nullability | LocalBounds | CFI, TrappingDefault = CFI, CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast, + CompatibleWithMinimalRuntime = TrappingSupported, }; enum CoverageFeature { @@ -55,8 +58,10 @@ enum CoverageFeature { Coverage8bitCounters = 1 << 8, // Deprecated. CoverageTracePC = 1 << 9, CoverageTracePCGuard = 1 << 10, - CoverageInline8bitCounters = 1 << 12, CoverageNoPrune = 1 << 11, + CoverageInline8bitCounters = 1 << 12, + CoveragePCTable = 1 << 13, + CoverageStackDepth = 1 << 14, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -92,6 +97,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, const char *BlacklistFile = nullptr; if (Kinds & Address) BlacklistFile = "asan_blacklist.txt"; + else if (Kinds & HWAddress) + BlacklistFile = "hwasan_blacklist.txt"; else if (Kinds & Memory) BlacklistFile = "msan_blacklist.txt"; else if (Kinds & Thread) @@ -100,6 +107,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, BlacklistFile = "dfsan_abilist.txt"; else if (Kinds & CFI) BlacklistFile = "cfi_blacklist.txt"; + else if (Kinds & (Undefined | Integer | Nullability)) + BlacklistFile = "ubsan_blacklist.txt"; if (BlacklistFile) { clang::SmallString<64> Path(D.ResourceDir); @@ -165,19 +174,23 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, } bool SanitizerArgs::needsUbsanRt() const { - return ((Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || - CoverageFeatures) && - !Sanitizers.has(Address) && !Sanitizers.has(Memory) && - !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) && - !Sanitizers.has(Leak) && !CfiCrossDso; + // All of these include ubsan. + if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() || + needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() || needsScudoRt()) + return false; + + return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || + CoverageFeatures; } bool SanitizerArgs::needsCfiRt() const { - return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso; + return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && + !ImplicitCfiRuntime; } bool SanitizerArgs::needsCfiDiagRt() const { - return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso; + return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && + !ImplicitCfiRuntime; } bool SanitizerArgs::requiresPIE() const { @@ -208,6 +221,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; + MinimalRuntime = + Args.hasFlag(options::OPT_fsanitize_minimal_runtime, + options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); + // The object size sanitizer should not be enabled at -O0. Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); bool RemoveObjectSizeAtO0 = @@ -245,6 +262,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, DiagnosedKinds |= KindsToDiagnose; } Add &= ~InvalidTrappingKinds; + + if (MinimalRuntime) { + if (SanitizerMask KindsToDiagnose = + Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) { + std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-minimal-runtime"; + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~NotAllowedWithMinimalRuntime; + } + if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_unsupported_opt_for_target) @@ -281,11 +310,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. Add &= ~InvalidTrappingKinds; + if (MinimalRuntime) { + Add &= ~NotAllowedWithMinimalRuntime; + } Add &= Supported; - // Enable coverage if the fuzzing flag is set. if (Add & Fuzzer) - CoverageFeatures |= CoverageTracePCGuard | CoverageIndirCall | CoverageTraceCmp; + Add |= FuzzerNoLink; + + // Enable coverage if the fuzzing flag is set. + if (Add & FuzzerNoLink) { + CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | + CoverageTraceCmp | CoveragePCTable; + // Due to TLS differences, stack depth tracking is only enabled on Linux + if (TC.getTriple().isOSLinux()) + CoverageFeatures |= CoverageStackDepth; + } Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { @@ -333,17 +373,15 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Warn about incompatible groups of sanitizers. std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { - std::make_pair(Address, Thread), std::make_pair(Address, Memory), - std::make_pair(Thread, Memory), std::make_pair(Leak, Thread), - std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address), - std::make_pair(KernelAddress, Leak), - std::make_pair(KernelAddress, Thread), - std::make_pair(KernelAddress, Memory), - std::make_pair(Efficiency, Address), - std::make_pair(Efficiency, Leak), - std::make_pair(Efficiency, Thread), - std::make_pair(Efficiency, Memory), - std::make_pair(Efficiency, KernelAddress)}; + std::make_pair(Address, Thread | Memory), + std::make_pair(Thread, Memory), + std::make_pair(Leak, Thread | Memory), + std::make_pair(KernelAddress, Address | Leak | Thread | Memory), + std::make_pair(HWAddress, Address | Thread | Memory | KernelAddress), + std::make_pair(Efficiency, Address | HWAddress | Leak | Thread | Memory | + KernelAddress), + std::make_pair(Scudo, Address | HWAddress | Leak | Thread | Memory | + KernelAddress | Efficiency)}; for (auto G : IncompatibleGroups) { SanitizerMask Group = G.first; if (Kinds & Group) { @@ -456,9 +494,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } MsanUseAfterDtor = - Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); + Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, + options::OPT_fno_sanitize_memory_use_after_dtor, + MsanUseAfterDtor); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); + } else { + MsanUseAfterDtor = false; } if (AllAddedKinds & Thread) { @@ -479,11 +521,33 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Without PIE, external function address may resolve to a PLT record, which // can not be verified by the target module. NeedPIE |= CfiCrossDso; + CfiICallGeneralizePointers = + Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); + + if (CfiCrossDso && CfiICallGeneralizePointers) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize-cfi-cross-dso" + << "-fsanitize-cfi-icall-generalize-pointers"; } Stats = Args.hasFlag(options::OPT_fsanitize_stats, options::OPT_fno_sanitize_stats, false); + if (MinimalRuntime) { + SanitizerMask IncompatibleMask = + Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); + if (IncompatibleMask) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-minimal-runtime" + << lastArgumentForMask(D, Args, IncompatibleMask); + + SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds; + if (NonTrappingCfi) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "fsanitize-minimal-runtime" + << "fsanitize-trap=cfi"; + } + // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. for (const auto *Arg : Args) { @@ -504,7 +568,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Disable coverage and not claim the flags if there is at least one // non-supporting sanitizer. - if (!(AllAddedKinds & ~setGroupBits(SupportsCoverage))) { + if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) { Arg->claim(); } else { CoverageFeatures = 0; @@ -539,23 +603,34 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << "-fsanitize-coverage=trace-pc-guard"; int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; + int InstrumentationTypes = + CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; if ((CoverageFeatures & InsertionPointTypes) && - !(CoverageFeatures &(CoverageTracePC | CoverageTracePCGuard))) { + !(CoverageFeatures & InstrumentationTypes)) { D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=[func|bb|edge]" << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; } // trace-pc w/o func/bb/edge implies edge. - if ((CoverageFeatures & - (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) && - !(CoverageFeatures & InsertionPointTypes)) - CoverageFeatures |= CoverageEdge; + if (!(CoverageFeatures & InsertionPointTypes)) { + if (CoverageFeatures & + (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) + CoverageFeatures |= CoverageEdge; + + if (CoverageFeatures & CoverageStackDepth) + CoverageFeatures |= CoverageFunc; + } + + SharedRuntime = + Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, + TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || + TC.getTriple().isOSDarwin()); + + ImplicitCfiRuntime = TC.getTriple().isAndroid(); if (AllAddedKinds & Address) { - AsanSharedRuntime = - Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid(); - NeedPIE |= TC.getTriple().isAndroid(); + NeedPIE |= TC.getTriple().isOSFuchsia(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); @@ -589,12 +664,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // globals in ASan is disabled by default on ELF targets. // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 AsanGlobalsDeadStripping = - !TC.getTriple().isOSBinFormatELF() || + !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); } else { AsanUseAfterScope = false; } + if (AllAddedKinds & SafeStack) { + // SafeStack runtime is built into the system on Fuchsia. + SafeStackRuntime = !TC.getTriple().isOSFuchsia(); + } + // Parse -link-cxx-sanitizer flag. LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); @@ -656,7 +736,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"), - std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune")}; + std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), + std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), + std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(F.second); @@ -733,9 +815,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (CfiCrossDso) CmdArgs.push_back("-fsanitize-cfi-cross-dso"); + if (CfiICallGeneralizePointers) + CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers"); + if (Stats) CmdArgs.push_back("-fsanitize-stats"); + if (MinimalRuntime) + CmdArgs.push_back("-fsanitize-minimal-runtime"); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); @@ -748,7 +836,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as - // https://code.google.com/p/address-sanitizer/issues/detail?id=373 + // https://github.com/google/sanitizers/issues/373 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't // affect compilation. if (Sanitizers.has(Memory) || Sanitizers.has(Address)) @@ -818,6 +906,8 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { .Case("trace-pc-guard", CoverageTracePCGuard) .Case("no-prune", CoverageNoPrune) .Case("inline-8bit-counters", CoverageInline8bitCounters) + .Case("pc-table", CoveragePCTable) + .Case("stack-depth", CoverageStackDepth) .Default(0); if (F == 0) D.Diag(clang::diag::err_drv_unsupported_option_argument) diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index 12afb18c23a88..f96a1182e3cab 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -27,6 +27,8 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/TargetRegistry.h" @@ -79,6 +81,12 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, getFilePaths().push_back(CandidateLibPath); } +void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { + Triple.setEnvironment(Env); + if (EffectiveTriple != llvm::Triple()) + EffectiveTriple.setEnvironment(Env); +} + ToolChain::~ToolChain() { } @@ -90,6 +98,10 @@ bool ToolChain::useIntegratedAs() const { IsIntegratedAssemblerDefault()); } +bool ToolChain::useRelaxRelocations() const { + return ENABLE_X86_RELAX_RELOCATIONS; +} + const SanitizerArgs& ToolChain::getSanitizerArgs() const { if (!SanitizerArguments.get()) SanitizerArguments.reset(new SanitizerArgs(*this, Args)); @@ -108,7 +120,7 @@ struct DriverSuffix { const char *ModeFlag; }; -const DriverSuffix *FindDriverSuffix(StringRef ProgName) { +const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { // A list of known driver suffixes. Suffixes are compared against the // program name in order. If there is a match, the frontend type is updated as // necessary by applying the ModeFlag. @@ -127,9 +139,13 @@ const DriverSuffix *FindDriverSuffix(StringRef ProgName) { {"++", "--driver-mode=g++"}, }; - for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) - if (ProgName.endswith(DriverSuffixes[i].Suffix)) + for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { + StringRef Suffix(DriverSuffixes[i].Suffix); + if (ProgName.endswith(Suffix)) { + Pos = ProgName.size() - Suffix.size(); return &DriverSuffixes[i]; + } + } return nullptr; } @@ -144,7 +160,7 @@ std::string normalizeProgramName(llvm::StringRef Argv0) { return ProgName; } -const DriverSuffix *parseDriverSuffix(StringRef ProgName) { +const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) { // Try to infer frontend type and default target from the program name by // comparing it against DriverSuffixes in order. @@ -152,47 +168,46 @@ const DriverSuffix *parseDriverSuffix(StringRef ProgName) { // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target // prefix "x86_64-linux". If such a target prefix is found, it may be // added via -target as implicit first argument. - const DriverSuffix *DS = FindDriverSuffix(ProgName); + const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos); if (!DS) { // Try again after stripping any trailing version number: // clang++3.5 -> clang++ ProgName = ProgName.rtrim("0123456789."); - DS = FindDriverSuffix(ProgName); + DS = FindDriverSuffix(ProgName, Pos); } if (!DS) { // Try again after stripping trailing -component. // clang++-tot -> clang++ ProgName = ProgName.slice(0, ProgName.rfind('-')); - DS = FindDriverSuffix(ProgName); + DS = FindDriverSuffix(ProgName, Pos); } return DS; } } // anonymous namespace -std::pair<std::string, std::string> +ParsedClangName ToolChain::getTargetAndModeFromProgramName(StringRef PN) { std::string ProgName = normalizeProgramName(PN); - const DriverSuffix *DS = parseDriverSuffix(ProgName); + size_t SuffixPos; + const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos); if (!DS) - return std::make_pair("", ""); - std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag; + return ParsedClangName(); + size_t SuffixEnd = SuffixPos + strlen(DS->Suffix); - std::string::size_type LastComponent = - ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix)); + size_t LastComponent = ProgName.rfind('-', SuffixPos); if (LastComponent == std::string::npos) - return std::make_pair("", ModeFlag); + return ParsedClangName(ProgName.substr(0, SuffixEnd), DS->ModeFlag); + std::string ModeSuffix = ProgName.substr(LastComponent + 1, + SuffixEnd - LastComponent - 1); // Infer target from the prefix. StringRef Prefix(ProgName); Prefix = Prefix.slice(0, LastComponent); std::string IgnoredError; - std::string Target; - if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { - Target = Prefix; - } - return std::make_pair(Target, ModeFlag); + bool IsRegistered = llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError); + return ParsedClangName{Prefix, ModeSuffix, DS->ModeFlag, IsRegistered}; } StringRef ToolChain::getDefaultUniversalArchName() const { @@ -212,6 +227,10 @@ StringRef ToolChain::getDefaultUniversalArchName() const { } } +std::string ToolChain::getInputFilename(const InputInfo &Input) const { + return Input.getFilename(); +} + bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const { return false; } @@ -292,15 +311,27 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, const llvm::Triple &Triple = TC.getTriple(); bool IsWindows = Triple.isOSWindows(); - if (Triple.isWindowsMSVCEnvironment() && TC.getArch() == llvm::Triple::x86) - return "i386"; - if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) ? "armhf" : "arm"; - return TC.getArchName(); + // For historic reasons, Android library is using i686 instead of i386. + if (TC.getArch() == llvm::Triple::x86 && Triple.isAndroid()) + return "i686"; + + return llvm::Triple::getArchTypeName(TC.getArch()); +} + +std::string ToolChain::getCompilerRTPath() const { + SmallString<128> Path(getDriver().ResourceDir); + if (Triple.isOSUnknown()) { + llvm::sys::path::append(Path, "lib"); + } else { + StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS(); + llvm::sys::path::append(Path, "lib", OSLibName); + } + return Path.str(); } std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, @@ -315,9 +346,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, const char *Suffix = Shared ? (Triple.isOSWindows() ? ".dll" : ".so") : (IsITANMSVCWindows ? ".lib" : ".a"); - SmallString<128> Path(getDriver().ResourceDir); - StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS(); - llvm::sys::path::append(Path, "lib", OSLibName); + SmallString<128> Path(getCompilerRTPath()); llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + Arch + Env + Suffix); return Path.str(); @@ -381,7 +410,11 @@ std::string ToolChain::GetLinkerPath() const { // then use whatever the default system linker is. return GetProgramPath(getDefaultLinker()); } else { - llvm::SmallString<8> LinkerName("ld."); + llvm::SmallString<8> LinkerName; + if (Triple.isOSDarwin()) + LinkerName.append("ld64."); + else + LinkerName.append("ld."); LinkerName.append(UseLinker); std::string LinkerPath(GetProgramPath(LinkerName.c_str())); @@ -424,6 +457,13 @@ ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const { VersionTuple()); } +llvm::ExceptionHandling +ToolChain::GetExceptionModel(const llvm::opt::ArgList &Args) const { + if (Triple.isOSWindows() && Triple.getArch() != llvm::Triple::x86) + return llvm::ExceptionHandling::WinEH; + return llvm::ExceptionHandling::None; +} + bool ToolChain::isThreadModelSupported(const StringRef Model) const { if (Model == "single") { // FIXME: 'single' is only supported on ARM and WebAssembly so far. @@ -500,7 +540,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, : tools::arm::getARMTargetCPU(MCPU, MArch, Triple); StringRef Suffix = tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); - bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::PK_M; + bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::ProfileKind::M; bool ThumbDefault = IsMProfile || (ARM::parseArchVersion(Suffix) == 7 && getTriple().isOSBinFormatMachO()); // FIXME: this is invalid for WindowsCE @@ -512,11 +552,42 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, else ArchName = "arm"; - // Assembly files should start in ARM mode, unless arch is M-profile. - // Windows is always thumb. - if ((InputType != types::TY_PP_Asm && Args.hasFlag(options::OPT_mthumb, - options::OPT_mno_thumb, ThumbDefault)) || IsMProfile || - getTriple().isOSWindows()) { + // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for + // M-Class CPUs/architecture variants, which is not supported. + bool ARMModeRequested = !Args.hasFlag(options::OPT_mthumb, + options::OPT_mno_thumb, ThumbDefault); + if (IsMProfile && ARMModeRequested) { + if (!MCPU.empty()) + getDriver().Diag(diag::err_cpu_unsupported_isa) << CPU << "ARM"; + else + getDriver().Diag(diag::err_arch_unsupported_isa) + << tools::arm::getARMArch(MArch, getTriple()) << "ARM"; + } + + // Check to see if an explicit choice to use thumb has been made via + // -mthumb. For assembler files we must check for -mthumb in the options + // passed to the assember via -Wa or -Xassembler. + bool IsThumb = false; + if (InputType != types::TY_PP_Asm) + IsThumb = Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, + ThumbDefault); + else { + // Ideally we would check for these flags in + // CollectArgsForIntegratedAssembler but we can't change the ArchName at + // that point. There is no assembler equivalent of -mno-thumb, -marm, or + // -mno-arm. + for (const Arg *A : + Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { + for (StringRef Value : A->getValues()) { + if (Value == "-mthumb") + IsThumb = true; + } + } + } + // Assembly files should start in ARM mode, unless arch is M-profile, or + // -mthumb has been passed explicitly to the assembler. Windows is always + // thumb. + if (IsThumb || IsMProfile || getTriple().isOSWindows()) { if (IsBigEndian) ArchName = "thumbeb"; else @@ -643,8 +714,16 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, DriverArgs.AddAllArgs(CC1Args, options::OPT_stdlib_EQ); } +bool ToolChain::ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const { + return getDriver().CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_nostdlibxx); +} + void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + assert(!Args.hasArg(options::OPT_nostdlibxx) && + "should not have called this"); CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { @@ -770,3 +849,70 @@ ToolChain::computeMSVCVersion(const Driver *D, return VersionTuple(); } + +llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( + const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, + SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + bool Modified = false; + + // Handle -Xopenmp-target flags + for (Arg *A : Args) { + // Exclude flags which may only apply to the host toolchain. + // Do not exclude flags when the host triple (AuxTriple) + // matches the current toolchain triple. If it is not present + // at all, target and host share a toolchain. + if (A->getOption().matches(options::OPT_m_Group)) { + if (SameTripleAsHost) + DAL->append(A); + else + Modified = true; + continue; + } + + unsigned Index; + unsigned Prev; + bool XOpenMPTargetNoTriple = + A->getOption().matches(options::OPT_Xopenmp_target); + + if (A->getOption().matches(options::OPT_Xopenmp_target_EQ)) { + // Passing device args: -Xopenmp-target=<triple> -opt=val. + if (A->getValue(0) == getTripleString()) + Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + else + continue; + } else if (XOpenMPTargetNoTriple) { + // Passing device args: -Xopenmp-target -opt=val. + Index = Args.getBaseArgs().MakeIndex(A->getValue(0)); + } else { + DAL->append(A); + continue; + } + + // Parse the argument to -Xopenmp-target. + Prev = Index; + std::unique_ptr<Arg> XOpenMPTargetArg(Opts.ParseOneArg(Args, Index)); + if (!XOpenMPTargetArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args) + << A->getAsString(Args); + continue; + } + if (XOpenMPTargetNoTriple && XOpenMPTargetArg && + Args.getAllArgValues(options::OPT_fopenmp_targets_EQ).size() != 1) { + getDriver().Diag(diag::err_drv_Xopenmp_target_missing_triple); + continue; + } + XOpenMPTargetArg->setBaseArg(A); + A = XOpenMPTargetArg.release(); + AllocatedArgs.push_back(A); + DAL->append(A); + Modified = true; + } + + if (Modified) + return DAL; + + delete DAL; + return nullptr; +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp index 63e1749e00883..a313bc5c35de1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -8,9 +8,10 @@ //===----------------------------------------------------------------------===// #include "AMDGPU.h" -#include "InputInfo.h" #include "CommonArgs.h" +#include "InputInfo.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -35,11 +36,66 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs, Inputs)); } +void amdgpu::getAMDGPUTargetFeatures(const Driver &D, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features) { + if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { + StringRef value = dAbi->getValue(); + if (value == "1.0") { + Features.push_back("+amdgpu-debugger-insert-nops"); + Features.push_back("+amdgpu-debugger-reserve-regs"); + Features.push_back("+amdgpu-debugger-emit-prologue"); + } else { + D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); + } + } + + handleTargetFeaturesGroup( + Args, Features, options::OPT_m_amdgpu_Features_Group); +} + /// AMDGPU Toolchain AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { } + : Generic_ELF(D, Triple, Args), + OptionsDefault({{options::OPT_O, "3"}, + {options::OPT_cl_std_EQ, "CL1.2"}}) {} Tool *AMDGPUToolChain::buildLinker() const { return new tools::amdgpu::Linker(*this); } + +DerivedArgList * +AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + + DerivedArgList *DAL = + Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + + // Do nothing if not OpenCL (-x cl) + if (!Args.getLastArgValue(options::OPT_x).equals("cl")) + return DAL; + + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + for (auto *A : Args) + DAL->append(A); + + const OptTable &Opts = getDriver().getOpts(); + + // Phase 1 (.cl -> .bc) + if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) { + DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit() + ? options::OPT_m64 + : options::OPT_m32)); + + // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately + // as they defined that way in Options.td + if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4, + options::OPT_Ofast)) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), + getOptionDefault(options::OPT_O)); + } + + return DAL; +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h index 9af1e96489ebd..36114d0dabc43 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h @@ -11,13 +11,14 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H #include "Gnu.h" +#include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include <map> namespace clang { namespace driver { namespace tools { - namespace amdgpu { class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { @@ -31,20 +32,35 @@ public: const char *LinkingOutput) const override; }; +void getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace amdgpu } // end namespace tools namespace toolchains { class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { + +private: + const std::map<options::ID, const StringRef> OptionsDefault; + protected: Tool *buildLinker() const override; + const StringRef getOptionDefault(options::ID OptID) const { + auto opt = OptionsDefault.find(OptID); + assert(opt != OptionsDefault.end() && "No Default for Option"); + return opt->second; + } public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + const llvm::opt::ArgList &Args); unsigned GetDefaultDwarfVersion() const override { return 2; } bool IsIntegratedAssemblerDefault() const override { return true; } + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; }; } // end namespace toolchains diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp index a67e1d2378f5d..ee072cc03e7ca 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp @@ -91,11 +91,10 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) CmdArgs.push_back("-lc"); - } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 554d051fb155c..ad04aedd098eb 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -20,14 +20,12 @@ using namespace clang; using namespace llvm::opt; /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are -/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune -/// arguments if they are provided, or to nullptr otherwise. +/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is +/// provided, or to nullptr otherwise. std::string aarch64::getAArch64TargetCPU(const ArgList &Args, Arg *&A) { std::string CPU; - // If we have -mtune or -mcpu, use that. - if ((A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) { - CPU = StringRef(A->getValue()).lower(); - } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { + // If we have -mcpu, use that. + if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); CPU = Mcpu.split("+").first.lower(); } @@ -74,7 +72,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, if (CPU == "generic") { Features.push_back("+neon"); } else { - unsigned ArchKind = llvm::AArch64::parseCPUArch(CPU); + llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU); if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) return false; @@ -96,8 +94,8 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, std::string MarchLowerCase = March.lower(); std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); - unsigned ArchKind = llvm::AArch64::parseArch(Split.first); - if (ArchKind == static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID) || + llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); + if (ArchKind == llvm::AArch64::ArchKind::INVALID || !llvm::AArch64::getArchFeatures(ArchKind, Features) || (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))) return false; @@ -122,6 +120,12 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector<StringRef> &Features) { std::string MtuneLowerCase = Mtune.lower(); + // Check CPU name is valid + std::vector<StringRef> MtuneFeatures; + StringRef Tune; + if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) + return false; + // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = llvm::sys::getHostCPUName(); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 95b86f784f914..44c8871d0e1fc 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -29,8 +29,7 @@ int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) { // True if M-profile. bool arm::isARMMProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); - unsigned Profile = llvm::ARM::parseArchProfile(Arch); - return Profile == llvm::ARM::PK_M; + return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; } // Get Arch/CPU from args. @@ -88,6 +87,15 @@ static bool DecodeARMFeatures(const Driver &D, StringRef text, return true; } +static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, + std::vector<StringRef> &Features) { + if (CPU != "generic") { + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); + unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); + llvm::ARM::getExtensionFeatures(Extension, Features); + } +} + // Check if -march is valid by checking if it can be canonicalised and parsed. // getARMArch is used here instead of just checking the -march value in order // to handle -march=native correctly. @@ -98,7 +106,7 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); - if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID || + if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID || (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -123,6 +131,26 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); } +// Select mode for reading thread pointer (-mtp=soft/cp15). +arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { + const Driver &D = TC.getDriver(); + arm::ReadTPMode ThreadPointer = + llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) + .Case("cp15", ReadTPMode::Cp15) + .Case("soft", ReadTPMode::Soft) + .Default(ReadTPMode::Invalid); + if (ThreadPointer != ReadTPMode::Invalid) + return ThreadPointer; + if (StringRef(A->getValue()).empty()) + D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args); + else + D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); + return ReadTPMode::Invalid; + } + return ReadTPMode::Soft; +} + // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { @@ -254,6 +282,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); + arm::ReadTPMode ThreadPointer = arm::getReadTPMode(TC, Args); const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; @@ -295,6 +324,9 @@ void arm::getARMTargetFeatures(const ToolChain &TC, } } + if (ThreadPointer == arm::ReadTPMode::Cp15) + Features.push_back("+read-tp-hard"); + // Check -march. ClangAs gives preference to -Wa,-march=. const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); StringRef ArchName; @@ -332,6 +364,8 @@ void arm::getARMTargetFeatures(const ToolChain &TC, for (auto &F : HostFeatures) Features.push_back( Args.MakeArgString((F.second ? "+" : "-") + F.first())); + } else if (!CPUName.empty()) { + DecodeARMFeaturesFromCPU(D, CPUName, Features); } // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. @@ -393,7 +427,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { if (getARMSubArchVersionNumber(Triple) < 7 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::AK_ARMV6T2) + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); @@ -525,11 +559,11 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, // FIXME: This is redundant with -mcpu, why does LLVM use this. StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, const llvm::Triple &Triple) { - unsigned ArchKind; + llvm::ARM::ArchKind ArchKind; if (CPU == "generic") { std::string ARMArch = tools::arm::getARMArch(Arch, Triple); ArchKind = llvm::ARM::parseArch(ARMArch); - if (ArchKind == llvm::ARM::AK_INVALID) + if (ArchKind == llvm::ARM::ArchKind::INVALID) // In case of generic Arch, i.e. "arm", // extract arch from default cpu of the Triple ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); @@ -537,10 +571,10 @@ StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, // FIXME: horrible hack to get around the fact that Cortex-A7 is only an // armv7k triple if it's actually been specified via "-arch armv7k". ArchKind = (Arch == "armv7k" || Arch == "thumbv7k") - ? (unsigned)llvm::ARM::AK_ARMV7K + ? llvm::ARM::ArchKind::ARMV7K : llvm::ARM::parseCPUArch(CPU); } - if (ArchKind == llvm::ARM::AK_INVALID) + if (ArchKind == llvm::ARM::ArchKind::INVALID) return ""; return llvm::ARM::getSubArch(ArchKind); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h index 52afaab762d0a..c1dc168840330 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -32,6 +32,12 @@ StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch, void appendEBLinkFlags(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const llvm::Triple &Triple); +enum class ReadTPMode { + Invalid, + Soft, + Cp15, +}; + enum class FloatABI { Invalid, Soft, @@ -40,6 +46,7 @@ enum class FloatABI { }; FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); +ReadTPMode getReadTPMode(const ToolChain &TC, const llvm::opt::ArgList &Args); bool useAAPCSForMachO(const llvm::Triple &T); void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp index b45dcd6db6780..61481a92d0b73 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -35,7 +35,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the // default for mips64(el)?-img-linux-gnu. if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && - Triple.getEnvironment() == llvm::Triple::GNU) { + Triple.isGNUEnvironment()) { DefMips32CPU = "mips32r6"; DefMips64CPU = "mips64r6"; } @@ -227,11 +227,32 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); } - if (IsN64 && NonPIC) + bool UseAbiCalls = false; + + Arg *ABICallsArg = + Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); + UseAbiCalls = + !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls); + + if (UseAbiCalls && IsN64 && NonPIC) { + D.Diag(diag::warn_drv_unsupported_abicalls); + UseAbiCalls = false; + } + + if (!UseAbiCalls) Features.push_back("+noabicalls"); else - AddTargetFeature(Args, Features, options::OPT_mno_abicalls, - options::OPT_mabicalls, "noabicalls"); + Features.push_back("-noabicalls"); + + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mno_long_calls)) + Features.push_back("-long-calls"); + else if (!UseAbiCalls) + Features.push_back("+long-calls"); + else + D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); + } mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args); if (FloatABI == mips::FloatABI::Soft) { @@ -244,14 +265,14 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { StringRef Val = StringRef(A->getValue()); if (Val == "2008") { - if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008) + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) Features.push_back("+nan2008"); else { Features.push_back("-nan2008"); D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; } } else if (Val == "legacy") { - if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy) + if (mips::getIEEE754Standard(CPUName) & mips::Legacy) Features.push_back("-nan2008"); else { Features.push_back("+nan2008"); @@ -262,6 +283,28 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, << A->getOption().getName() << Val; } + if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { + StringRef Val = StringRef(A->getValue()); + if (Val == "2008") { + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { + Features.push_back("+abs2008"); + } else { + Features.push_back("-abs2008"); + D.Diag(diag::warn_target_unsupported_abs2008) << CPUName; + } + } else if (Val == "legacy") { + if (mips::getIEEE754Standard(CPUName) & mips::Legacy) { + Features.push_back("-abs2008"); + } else { + Features.push_back("+abs2008"); + D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName; + } + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } + } + AddTargetFeature(Args, Features, options::OPT_msingle_float, options::OPT_mdouble_float, "single-float"); AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, @@ -299,32 +342,31 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, options::OPT_modd_spreg, "nooddspreg"); AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, "nomadd4"); - AddTargetFeature(Args, Features, options::OPT_mlong_calls, - options::OPT_mno_long_calls, "long-calls"); - AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt,"mt"); + AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt"); } -mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { - // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008 - // was first introduced in Release 3. However, other compilers have - // traditionally allowed it for Release 2 so we should do the same. - return (NanEncoding)llvm::StringSwitch<int>(CPU) - .Case("mips1", NanLegacy) - .Case("mips2", NanLegacy) - .Case("mips3", NanLegacy) - .Case("mips4", NanLegacy) - .Case("mips5", NanLegacy) - .Case("mips32", NanLegacy) - .Case("mips32r2", NanLegacy | Nan2008) - .Case("mips32r3", NanLegacy | Nan2008) - .Case("mips32r5", NanLegacy | Nan2008) - .Case("mips32r6", Nan2008) - .Case("mips64", NanLegacy) - .Case("mips64r2", NanLegacy | Nan2008) - .Case("mips64r3", NanLegacy | Nan2008) - .Case("mips64r5", NanLegacy | Nan2008) - .Case("mips64r6", Nan2008) - .Default(NanLegacy); +mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { + // Strictly speaking, mips32r2 and mips64r2 do not conform to the + // IEEE754-2008 standard. Support for this standard was first introduced + // in Release 3. However, other compilers have traditionally allowed it + // for Release 2 so we should do the same. + return (IEEE754Standard)llvm::StringSwitch<int>(CPU) + .Case("mips1", Legacy) + .Case("mips2", Legacy) + .Case("mips3", Legacy) + .Case("mips4", Legacy) + .Case("mips5", Legacy) + .Case("mips32", Legacy) + .Case("mips32r2", Legacy | Std2008) + .Case("mips32r3", Legacy | Std2008) + .Case("mips32r5", Legacy | Std2008) + .Case("mips32r6", Std2008) + .Case("mips64", Legacy) + .Case("mips64r2", Legacy | Std2008) + .Case("mips64r3", Legacy | Std2008) + .Case("mips64r5", Legacy | Std2008) + .Case("mips64r6", Std2008) + .Default(Std2008); } bool mips::hasCompactBranches(StringRef &CPU) { diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h index 0b788660948c4..89eea9a1514cd 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -24,7 +24,7 @@ namespace tools { bool isMipsArch(llvm::Triple::ArchType Arch); namespace mips { -typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding; +typedef enum { Legacy = 1, Std2008 = 2 } IEEE754Standard; enum class FloatABI { Invalid, @@ -32,7 +32,7 @@ enum class FloatABI { Hard, }; -NanEncoding getSupportedNanEncoding(StringRef &CPU); +IEEE754Standard getIEEE754Standard(StringRef &CPU); bool hasCompactBranches(StringRef &CPU); void getMipsCPUAndABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef &CPUName, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 541323127f9a8..7c7e1c70e5502 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -86,6 +86,18 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { return ""; } +const char *ppc::getPPCAsmModeForCPU(StringRef Name) { + return llvm::StringSwitch<const char *>(Name) + .Case("pwr7", "-mpower7") + .Case("power7", "-mpower7") + .Case("pwr8", "-mpower8") + .Case("power8", "-mpower8") + .Case("ppc64le", "-mpower8") + .Case("pwr9", "-mpower9") + .Case("power9", "-mpower9") + .Default("-many"); +} + void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h index 892eb2c341588..7d7c68101b7b6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h @@ -32,6 +32,7 @@ enum class FloatABI { FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); +const char *getPPCAsmModeForCPU(StringRef Name); void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp index a85a7f1f63714..a18b2aa35b03a 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -101,8 +101,6 @@ const char *x86::getX86TargetCPU(const ArgList &Args, return "i486"; case llvm::Triple::Haiku: return "i586"; - case llvm::Triple::Bitrig: - return "i686"; default: // Fallback to p4. return "pentium4"; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp index 28e4f5b0e5836..57a668650e6bc 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -184,10 +184,9 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + if (TC.ShouldLinkCXXStdlib(Args)) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (C.getDriver().CCCIsCXX()) - TC.AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h index 5e9fd9bffdb9e..0bed63332cad0 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h @@ -37,7 +37,6 @@ public: bool isPIEDefault() const override { return false; } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } - bool SupportsObjCGC() const override { return false; } RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp deleted file mode 100644 index d8f541dfbaf1b..0000000000000 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp +++ /dev/null @@ -1,190 +0,0 @@ -//===--- Bitrig.cpp - Bitrig ToolChain Implementations ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Bitrig.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang::driver::tools; -using namespace clang; -using namespace llvm::opt; - -void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); - ArgStringList CmdArgs; - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { - CmdArgs.push_back("-e"); - CmdArgs.push_back("__start"); - } - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - CmdArgs.push_back("--eh-frame-hdr"); - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-shared"); - } else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/usr/libexec/ld.so"); - } - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); - } - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lm_p"); - else - CmdArgs.push_back("-lm"); - } - - if (Args.hasArg(options::OPT_pthread)) { - if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lpthread_p"); - else - CmdArgs.push_back("-lpthread"); - } - - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lc_p"); - else - CmdArgs.push_back("-lc"); - } - - StringRef MyArch; - switch (getToolChain().getArch()) { - case llvm::Triple::arm: - MyArch = "arm"; - break; - case llvm::Triple::x86: - MyArch = "i386"; - break; - case llvm::Triple::x86_64: - MyArch = "amd64"; - break; - default: - llvm_unreachable("Unsupported architecture"); - } - CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch)); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. - -Bitrig::Bitrig(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); -} - -Tool *Bitrig::buildAssembler() const { - return new tools::bitrig::Assembler(*this); -} - -Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); } - -ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const { - return ToolChain::CST_Libcxx; -} - -void Bitrig::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - std::string Triple = getTriple().str(); - if (StringRef(Triple).startswith("amd64")) - Triple = "x86_64" + Triple.substr(5); - addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/stdc++", - Triple, "", "", "", DriverArgs, CC1Args); -} - -void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - switch (GetCXXStdlibType(Args)) { - case ToolChain::CST_Libcxx: - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lpthread"); - break; - case ToolChain::CST_Libstdcxx: - CmdArgs.push_back("-lstdc++"); - break; - } -} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h deleted file mode 100644 index 6edb2e8c7e8c7..0000000000000 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h +++ /dev/null @@ -1,79 +0,0 @@ -//===--- Bitrig.h - Bitrig ToolChain Implementations ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H - -#include "Gnu.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { -/// bitrig -- Directly call GNU Binutils assembler and linker -namespace bitrig { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("bitrig::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace bitrig -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { -public: - Bitrig(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - - CXXStdlibType GetDefaultCXXStdlibType() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - return 1; - } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index 497f0b493261a..0a89ff96d3c8e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -15,6 +15,7 @@ #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" +#include "AMDGPU.h" #include "CommonArgs.h" #include "Hexagon.h" #include "InputInfo.h" @@ -273,19 +274,25 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, OutStrings.push_back(Args.MakeArgString(Out)); } -static void getHexagonTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, - options::OPT_m_hexagon_Features_Group); +/// The -mprefer-vector-width option accepts either a positive integer +/// or the string "none". +static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return; - bool UseLongCalls = false; - if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, - options::OPT_mno_long_calls)) { - if (A->getOption().matches(options::OPT_mlong_calls)) - UseLongCalls = true; + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-mprefer-vector-width=none"); + } else { + unsigned Width; + if (Value.getAsInteger(10, Width)) { + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; + return; + } + CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + Value)); } - - Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); } static void getWebAssemblyTargetFeatures(const ArgList &Args, @@ -293,23 +300,6 @@ static void getWebAssemblyTargetFeatures(const ArgList &Args, handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); } -static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features) { - if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { - StringRef value = dAbi->getValue(); - if (value == "1.0") { - Features.push_back("+amdgpu-debugger-insert-nops"); - Features.push_back("+amdgpu-debugger-reserve-regs"); - Features.push_back("+amdgpu-debugger-emit-prologue"); - } else { - D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); - } - } - - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); -} - static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { @@ -349,7 +339,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, x86::getX86TargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::hexagon: - getHexagonTargetFeatures(Args, Features); + hexagon::getHexagonTargetFeatures(D, Args, Features); break; case llvm::Triple::wasm32: case llvm::Triple::wasm64: @@ -362,7 +352,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, break; case llvm::Triple::r600: case llvm::Triple::amdgcn: - getAMDGPUTargetFeatures(D, Args, Features); + amdgpu::getAMDGPUTargetFeatures(D, Args, Features); break; } @@ -1360,6 +1350,77 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, CmdArgs.push_back("-no-implicit-float"); } +void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, + const ArgList &Args, bool KernelOrKext, + ArgStringList &CmdArgs) const { + const ToolChain &TC = getToolChain(); + + // Add the target features + getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false); + + // Add target specific flags. + switch (TC.getArch()) { + default: + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + // Use the effective triple, which takes into account the deployment target. + AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext); + CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + AddAArch64TargetArgs(Args, CmdArgs); + CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + AddMIPSTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + AddPPCTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + AddSparcTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::systemz: + AddSystemZTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + AddX86TargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::lanai: + AddLanaiTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::hexagon: + AddHexagonTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + AddWebAssemblyTargetArgs(Args, CmdArgs); + break; + } +} + void Clang::AddAArch64TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); @@ -1462,6 +1523,80 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, A->claim(); } + Arg *GPOpt = Args.getLastArg(options::OPT_mgpopt, options::OPT_mno_gpopt); + Arg *ABICalls = + Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); + + // -mabicalls is the default for many MIPS environments, even with -fno-pic. + // -mgpopt is the default for static, -fno-pic environments but these two + // options conflict. We want to be certain that -mno-abicalls -mgpopt is + // the only case where -mllvm -mgpopt is passed. + // NOTE: We need a warning here or in the backend to warn when -mgpopt is + // passed explicitly when compiling something with -mabicalls + // (implictly) in affect. Currently the warning is in the backend. + // + // When the ABI in use is N64, we also need to determine the PIC mode that + // is in use, as -fno-pic for N64 implies -mno-abicalls. + bool NoABICalls = + ABICalls && ABICalls->getOption().matches(options::OPT_mno_abicalls); + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + NoABICalls = NoABICalls || + (RelocationModel == llvm::Reloc::Static && ABIName == "n64"); + + bool WantGPOpt = GPOpt && GPOpt->getOption().matches(options::OPT_mgpopt); + // We quietly ignore -mno-gpopt as the backend defaults to -mno-gpopt. + if (NoABICalls && (!GPOpt || WantGPOpt)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mgpopt"); + + Arg *LocalSData = Args.getLastArg(options::OPT_mlocal_sdata, + options::OPT_mno_local_sdata); + Arg *ExternSData = Args.getLastArg(options::OPT_mextern_sdata, + options::OPT_mno_extern_sdata); + Arg *EmbeddedData = Args.getLastArg(options::OPT_membedded_data, + options::OPT_mno_embedded_data); + if (LocalSData) { + CmdArgs.push_back("-mllvm"); + if (LocalSData->getOption().matches(options::OPT_mlocal_sdata)) { + CmdArgs.push_back("-mlocal-sdata=1"); + } else { + CmdArgs.push_back("-mlocal-sdata=0"); + } + LocalSData->claim(); + } + + if (ExternSData) { + CmdArgs.push_back("-mllvm"); + if (ExternSData->getOption().matches(options::OPT_mextern_sdata)) { + CmdArgs.push_back("-mextern-sdata=1"); + } else { + CmdArgs.push_back("-mextern-sdata=0"); + } + ExternSData->claim(); + } + + if (EmbeddedData) { + CmdArgs.push_back("-mllvm"); + if (EmbeddedData->getOption().matches(options::OPT_membedded_data)) { + CmdArgs.push_back("-membedded-data=1"); + } else { + CmdArgs.push_back("-membedded-data=0"); + } + EmbeddedData->claim(); + } + + } else if ((!ABICalls || (!NoABICalls && ABICalls)) && WantGPOpt) + D.Diag(diag::warn_drv_unsupported_gpopt) << (ABICalls ? 0 : 1); + + if (GPOpt) + GPOpt->claim(); + if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) { StringRef Val = StringRef(A->getValue()); if (mips::hasCompactBranches(CPUName)) { @@ -1755,7 +1890,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, // arg after parsing the '-I' arg. bool TakeNextArg = false; - bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; + bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); const char *MipsTargetFeature = nullptr; for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { @@ -1775,6 +1910,15 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, switch (C.getDefaultToolChain().getArch()) { default: break; + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::arm: + case llvm::Triple::armeb: + if (Value == "-mthumb") + // -mthumb has already been processed in ComputeLLVMTriple() + // recognize but skip over here. + continue; + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1894,9 +2038,987 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } +static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, + bool OFastEnabled, const ArgList &Args, + ArgStringList &CmdArgs) { + // Handle various floating point optimization flags, mapping them to the + // appropriate LLVM code generation flags. This is complicated by several + // "umbrella" flags, so we do this by stepping through the flags incrementally + // adjusting what we think is enabled/disabled, then at the end settting the + // LLVM flags based on the final state. + bool HonorINFs = true; + bool HonorNaNs = true; + // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. + bool MathErrno = TC.IsMathErrnoDefault(); + bool AssociativeMath = false; + bool ReciprocalMath = false; + bool SignedZeros = true; + bool TrappingMath = true; + StringRef DenormalFPMath = ""; + StringRef FPContract = ""; + + for (const Arg *A : Args) { + switch (A->getOption().getID()) { + // If this isn't an FP option skip the claim below + default: continue; + + // Options controlling individual features + case options::OPT_fhonor_infinities: HonorINFs = true; break; + case options::OPT_fno_honor_infinities: HonorINFs = false; break; + case options::OPT_fhonor_nans: HonorNaNs = true; break; + case options::OPT_fno_honor_nans: HonorNaNs = false; break; + case options::OPT_fmath_errno: MathErrno = true; break; + case options::OPT_fno_math_errno: MathErrno = false; break; + case options::OPT_fassociative_math: AssociativeMath = true; break; + case options::OPT_fno_associative_math: AssociativeMath = false; break; + case options::OPT_freciprocal_math: ReciprocalMath = true; break; + case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; + case options::OPT_fsigned_zeros: SignedZeros = true; break; + case options::OPT_fno_signed_zeros: SignedZeros = false; break; + case options::OPT_ftrapping_math: TrappingMath = true; break; + case options::OPT_fno_trapping_math: TrappingMath = false; break; + + case options::OPT_fdenormal_fp_math_EQ: + DenormalFPMath = A->getValue(); + break; + + // Validate and pass through -fp-contract option. + case options::OPT_ffp_contract: { + StringRef Val = A->getValue(); + if (Val == "fast" || Val == "on" || Val == "off") + FPContract = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + case options::OPT_ffinite_math_only: + HonorINFs = false; + HonorNaNs = false; + break; + case options::OPT_fno_finite_math_only: + HonorINFs = true; + HonorNaNs = true; + break; + + case options::OPT_funsafe_math_optimizations: + AssociativeMath = true; + ReciprocalMath = true; + SignedZeros = false; + TrappingMath = false; + break; + case options::OPT_fno_unsafe_math_optimizations: + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + // -fno_unsafe_math_optimizations restores default denormal handling + DenormalFPMath = ""; + break; + + case options::OPT_Ofast: + // If -Ofast is the optimization level, then -ffast-math should be enabled + if (!OFastEnabled) + continue; + LLVM_FALLTHROUGH; + case options::OPT_ffast_math: + HonorINFs = false; + HonorNaNs = false; + MathErrno = false; + AssociativeMath = true; + ReciprocalMath = true; + SignedZeros = false; + TrappingMath = false; + // If fast-math is set then set the fp-contract mode to fast. + FPContract = "fast"; + break; + case options::OPT_fno_fast_math: + HonorINFs = true; + HonorNaNs = true; + // Turning on -ffast-math (with either flag) removes the need for + // MathErrno. However, turning *off* -ffast-math merely restores the + // toolchain default (which may be false). + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + break; + } + + // If we handled this option claim it + A->claim(); + } + + if (!HonorINFs) + CmdArgs.push_back("-menable-no-infs"); + + if (!HonorNaNs) + CmdArgs.push_back("-menable-no-nans"); + + if (MathErrno) + CmdArgs.push_back("-fmath-errno"); + + if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && + !TrappingMath) + CmdArgs.push_back("-menable-unsafe-fp-math"); + + if (!SignedZeros) + CmdArgs.push_back("-fno-signed-zeros"); + + if (AssociativeMath && !SignedZeros && !TrappingMath) + CmdArgs.push_back("-mreassociate"); + + if (ReciprocalMath) + CmdArgs.push_back("-freciprocal-math"); + + if (!TrappingMath) + CmdArgs.push_back("-fno-trapping-math"); + + if (!DenormalFPMath.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath)); + + if (!FPContract.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + + ParseMRecip(D, Args, CmdArgs); + + // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the + // individual features enabled by -ffast-math instead of the option itself as + // that's consistent with gcc's behaviour. + if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && + ReciprocalMath && !SignedZeros && !TrappingMath) + CmdArgs.push_back("-ffast-math"); + + // Handle __FINITE_MATH_ONLY__ similarly. + if (!HonorINFs && !HonorNaNs) + CmdArgs.push_back("-ffinite-math-only"); + + if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { + CmdArgs.push_back("-mfpmath"); + CmdArgs.push_back(A->getValue()); + } +} + +static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Input) { + // Enable region store model by default. + CmdArgs.push_back("-analyzer-store=region"); + + // Treat blocks as analysis entry points. + CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + + CmdArgs.push_back("-analyzer-eagerly-assume"); + + // Add default argument set. + if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { + CmdArgs.push_back("-analyzer-checker=core"); + CmdArgs.push_back("-analyzer-checker=apiModeling"); + + if (!Triple.isWindowsMSVCEnvironment()) { + CmdArgs.push_back("-analyzer-checker=unix"); + } else { + // Enable "unix" checkers that also work on Windows. + CmdArgs.push_back("-analyzer-checker=unix.API"); + CmdArgs.push_back("-analyzer-checker=unix.Malloc"); + CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof"); + CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator"); + CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg"); + CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); + } + + // Disable some unix checkers for PS4. + if (Triple.isPS4CPU()) { + CmdArgs.push_back("-analyzer-disable-checker=unix.API"); + CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); + } + + if (Triple.isOSDarwin()) + CmdArgs.push_back("-analyzer-checker=osx"); + + CmdArgs.push_back("-analyzer-checker=deadcode"); + + if (types::isCXX(Input.getType())) + CmdArgs.push_back("-analyzer-checker=cplusplus"); + + if (!Triple.isPS4CPU()) { + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); + } + + // Default nullability checks. + CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); + CmdArgs.push_back("-analyzer-checker=nullability.NullReturnedFromNonnull"); + } + + // Set the output format. The default is plist, for (lame) historical reasons. + CmdArgs.push_back("-analyzer-output"); + if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) + CmdArgs.push_back(A->getValue()); + else + CmdArgs.push_back("plist"); + + // Disable the presentation of standard compiler warnings when using + // --analyze. We only want to show static analyzer diagnostics or frontend + // errors. + CmdArgs.push_back("-w"); + + // Add -Xanalyzer arguments when running as analyzer. + Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); +} + +static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs, bool KernelOrKext) { + const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); + + // NVPTX doesn't support stack protectors; from the compiler's perspective, it + // doesn't even have a stack! + if (EffectiveTriple.isNVPTX()) + return; + + // -stack-protector=0 is default. + unsigned StackProtectorLevel = 0; + unsigned DefaultStackProtectorLevel = + TC.GetDefaultStackProtectorLevel(KernelOrKext); + + if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + options::OPT_fstack_protector_all, + options::OPT_fstack_protector_strong, + options::OPT_fstack_protector)) { + if (A->getOption().matches(options::OPT_fstack_protector)) + StackProtectorLevel = + std::max<unsigned>(LangOptions::SSPOn, DefaultStackProtectorLevel); + else if (A->getOption().matches(options::OPT_fstack_protector_strong)) + StackProtectorLevel = LangOptions::SSPStrong; + else if (A->getOption().matches(options::OPT_fstack_protector_all)) + StackProtectorLevel = LangOptions::SSPReq; + } else { + StackProtectorLevel = DefaultStackProtectorLevel; + } + + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector"); + CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); + } + + // --param ssp-buffer-size= + for (const Arg *A : Args.filtered(options::OPT__param)) { + StringRef Str(A->getValue()); + if (Str.startswith("ssp-buffer-size=")) { + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector-buffer-size"); + // FIXME: Verify the argument is a valid integer. + CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); + } + A->claim(); + } + } +} + +static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { + const unsigned ForwardedArguments[] = { + options::OPT_cl_opt_disable, + options::OPT_cl_strict_aliasing, + options::OPT_cl_single_precision_constant, + options::OPT_cl_finite_math_only, + options::OPT_cl_kernel_arg_info, + options::OPT_cl_unsafe_math_optimizations, + options::OPT_cl_fast_relaxed_math, + options::OPT_cl_mad_enable, + options::OPT_cl_no_signed_zeros, + options::OPT_cl_denorms_are_zero, + options::OPT_cl_fp32_correctly_rounded_divide_sqrt, + }; + + if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { + std::string CLStdStr = std::string("-cl-std=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(CLStdStr)); + } + + for (const auto &Arg : ForwardedArguments) + if (const auto *A = Args.getLastArg(Arg)) + CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName())); +} + +static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + bool ARCMTEnabled = false; + if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { + if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, + options::OPT_ccc_arcmt_modify, + options::OPT_ccc_arcmt_migrate)) { + ARCMTEnabled = true; + switch (A->getOption().getID()) { + default: llvm_unreachable("missed a case"); + case options::OPT_ccc_arcmt_check: + CmdArgs.push_back("-arcmt-check"); + break; + case options::OPT_ccc_arcmt_modify: + CmdArgs.push_back("-arcmt-modify"); + break; + case options::OPT_ccc_arcmt_migrate: + CmdArgs.push_back("-arcmt-migrate"); + CmdArgs.push_back("-mt-migrate-directory"); + CmdArgs.push_back(A->getValue()); + + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); + break; + } + } + } else { + Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); + } + + if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { + if (ARCMTEnabled) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-ccc-arcmt-migrate"; + + CmdArgs.push_back("-mt-migrate-directory"); + CmdArgs.push_back(A->getValue()); + + if (!Args.hasArg(options::OPT_objcmt_migrate_literals, + options::OPT_objcmt_migrate_subscripting, + options::OPT_objcmt_migrate_property)) { + // None specified, means enable them all. + CmdArgs.push_back("-objcmt-migrate-literals"); + CmdArgs.push_back("-objcmt-migrate-subscripting"); + CmdArgs.push_back("-objcmt-migrate-property"); + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); + } + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); + } +} + +static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, + const ArgList &Args, ArgStringList &CmdArgs) { + // -fbuiltin is default unless -mkernel is used. + bool UseBuiltins = + Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, + !Args.hasArg(options::OPT_mkernel)); + if (!UseBuiltins) + CmdArgs.push_back("-fno-builtin"); + + // -ffreestanding implies -fno-builtin. + if (Args.hasArg(options::OPT_ffreestanding)) + UseBuiltins = false; + + // Process the -fno-builtin-* options. + for (const auto &Arg : Args) { + const Option &O = Arg->getOption(); + if (!O.matches(options::OPT_fno_builtin_)) + continue; + + Arg->claim(); + + // If -fno-builtin is specified, then there's no need to pass the option to + // the frontend. + if (!UseBuiltins) + continue; + + StringRef FuncName = Arg->getValue(); + CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); + } + + // le32-specific flags: + // -fno-math-builtin: clang should not convert math builtins to intrinsics + // by default. + if (TC.getArch() == llvm::Triple::le32) + CmdArgs.push_back("-fno-math-builtin"); +} + +static void RenderModulesOptions(Compilation &C, const Driver &D, + const ArgList &Args, const InputInfo &Input, + const InputInfo &Output, + ArgStringList &CmdArgs, bool &HaveModules) { + // -fmodules enables the use of precompiled modules (off by default). + // Users can pass -fno-cxx-modules to turn off modules support for + // C++/Objective-C++ programs. + bool HaveClangModules = false; + if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { + bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, + options::OPT_fno_cxx_modules, true); + if (AllowedInCXX || !types::isCXX(Input.getType())) { + CmdArgs.push_back("-fmodules"); + HaveClangModules = true; + } + } + + HaveModules = HaveClangModules; + if (Args.hasArg(options::OPT_fmodules_ts)) { + CmdArgs.push_back("-fmodules-ts"); + HaveModules = true; + } + + // -fmodule-maps enables implicit reading of module map files. By default, + // this is enabled if we are using Clang's flavor of precompiled modules. + if (Args.hasFlag(options::OPT_fimplicit_module_maps, + options::OPT_fno_implicit_module_maps, HaveClangModules)) + CmdArgs.push_back("-fimplicit-module-maps"); + + // -fmodules-decluse checks that modules used are declared so (off by default) + if (Args.hasFlag(options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse, false)) + CmdArgs.push_back("-fmodules-decluse"); + + // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that + // all #included headers are part of modules. + if (Args.hasFlag(options::OPT_fmodules_strict_decluse, + options::OPT_fno_modules_strict_decluse, false)) + CmdArgs.push_back("-fmodules-strict-decluse"); + + // -fno-implicit-modules turns off implicitly compiling modules on demand. + if (!Args.hasFlag(options::OPT_fimplicit_modules, + options::OPT_fno_implicit_modules, HaveClangModules)) { + if (HaveModules) + CmdArgs.push_back("-fno-implicit-modules"); + } else if (HaveModules) { + // -fmodule-cache-path specifies where our implicitly-built module files + // should be written. + SmallString<128> Path; + if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) + Path = A->getValue(); + + if (C.isForDiagnostics()) { + // When generating crash reports, we want to emit the modules along with + // the reproduction sources, so we ignore any provided module path. + Path = Output.getFilename(); + llvm::sys::path::replace_extension(Path, ".cache"); + llvm::sys::path::append(Path, "modules"); + } else if (Path.empty()) { + // No module path was provided: use the default. + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); + llvm::sys::path::append(Path, "org.llvm.clang."); + appendUserToPath(Path); + llvm::sys::path::append(Path, "ModuleCache"); + } + + const char Arg[] = "-fmodules-cache-path="; + Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(Path)); + } + + if (HaveModules) { + // -fprebuilt-module-path specifies where to load the prebuilt module files. + for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { + CmdArgs.push_back(Args.MakeArgString( + std::string("-fprebuilt-module-path=") + A->getValue())); + A->claim(); + } + } + + // -fmodule-name specifies the module that is currently being built (or + // used for header checking by -fmodule-maps). + Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); + + // -fmodule-map-file can be used to specify files containing module + // definitions. + Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); + + // -fbuiltin-module-map can be used to load the clang + // builtin headers modulemap file. + if (Args.hasArg(options::OPT_fbuiltin_module_map)) { + SmallString<128> BuiltinModuleMap(D.ResourceDir); + llvm::sys::path::append(BuiltinModuleMap, "include"); + llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); + if (llvm::sys::fs::exists(BuiltinModuleMap)) + CmdArgs.push_back( + Args.MakeArgString("-fmodule-map-file=" + BuiltinModuleMap)); + } + + // The -fmodule-file=<name>=<file> form specifies the mapping of module + // names to precompiled module files (the module is loaded only if used). + // The -fmodule-file=<file> form can be used to unconditionally load + // precompiled module files (whether used or not). + if (HaveModules) + Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); + else + Args.ClaimAllArgs(options::OPT_fmodule_file); + + // When building modules and generating crashdumps, we need to dump a module + // dependency VFS alongside the output. + if (HaveClangModules && C.isForDiagnostics()) { + SmallString<128> VFSDir(Output.getFilename()); + llvm::sys::path::replace_extension(VFSDir, ".cache"); + // Add the cache directory as a temp so the crash diagnostics pick it up. + C.addTempFile(Args.MakeArgString(VFSDir)); + + llvm::sys::path::append(VFSDir, "vfs"); + CmdArgs.push_back("-module-dependency-dir"); + CmdArgs.push_back(Args.MakeArgString(VFSDir)); + } + + if (HaveClangModules) + Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); + + // Pass through all -fmodules-ignore-macro arguments. + Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); + + Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); + + if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { + if (Args.hasArg(options::OPT_fbuild_session_timestamp)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fbuild-session-timestamp"; + + llvm::sys::fs::file_status Status; + if (llvm::sys::fs::status(A->getValue(), Status)) + D.Diag(diag::err_drv_no_such_file) << A->getValue(); + CmdArgs.push_back( + Args.MakeArgString("-fbuild-session-timestamp=" + + Twine((uint64_t)Status.getLastModificationTime() + .time_since_epoch() + .count()))); + } + + if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { + if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, + options::OPT_fbuild_session_file)) + D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + + Args.AddLastArg(CmdArgs, + options::OPT_fmodules_validate_once_per_build_session); + } + + Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); +} + +static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, + ArgStringList &CmdArgs) { + // -fsigned-char is default. + if (const Arg *A = Args.getLastArg(options::OPT_fsigned_char, + options::OPT_fno_signed_char, + options::OPT_funsigned_char, + options::OPT_fno_unsigned_char)) { + if (A->getOption().matches(options::OPT_funsigned_char) || + A->getOption().matches(options::OPT_fno_signed_char)) { + CmdArgs.push_back("-fno-signed-char"); + } + } else if (!isSignedCharDefault(T)) { + CmdArgs.push_back("-fno-signed-char"); + } + + if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar, + options::OPT_fno_short_wchar)) { + if (A->getOption().matches(options::OPT_fshort_wchar)) { + CmdArgs.push_back("-fwchar-type=short"); + CmdArgs.push_back("-fno-signed-wchar"); + } else { + bool IsARM = T.isARM() || T.isThumb() || T.isAArch64(); + CmdArgs.push_back("-fwchar-type=int"); + if (IsARM && !(T.isOSWindows() || T.getOS() == llvm::Triple::NetBSD || + T.getOS() == llvm::Triple::OpenBSD)) + CmdArgs.push_back("-fno-signed-wchar"); + else + CmdArgs.push_back("-fsigned-wchar"); + } + } +} + +static void RenderObjCOptions(const ToolChain &TC, const Driver &D, + const llvm::Triple &T, const ArgList &Args, + ObjCRuntime &Runtime, bool InferCovariantReturns, + const InputInfo &Input, ArgStringList &CmdArgs) { + const llvm::Triple::ArchType Arch = TC.getArch(); + + // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and legacy + // is the default. Except for deployment target of 10.5, next runtime is + // always legacy dispatch and -fno-objc-legacy-dispatch gets ignored silently. + if (Runtime.isNonFragile()) { + if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, + options::OPT_fno_objc_legacy_dispatch, + Runtime.isLegacyDispatchDefaultForArch(Arch))) { + if (TC.UseObjCMixedDispatch()) + CmdArgs.push_back("-fobjc-dispatch-method=mixed"); + else + CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); + } + } + + // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option + // to do Array/Dictionary subscripting by default. + if (Arch == llvm::Triple::x86 && T.isMacOSX() && + !T.isMacOSXVersionLT(10, 7) && + Runtime.getKind() == ObjCRuntime::FragileMacOSX && Runtime.isNeXTFamily()) + CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); + + // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. + // NOTE: This logic is duplicated in ToolChains.cpp. + if (isObjCAutoRefCount(Args)) { + TC.CheckObjCARC(); + + CmdArgs.push_back("-fobjc-arc"); + + // FIXME: It seems like this entire block, and several around it should be + // wrapped in isObjC, but for now we just use it here as this is where it + // was being used previously. + if (types::isCXX(Input.getType()) && types::isObjC(Input.getType())) { + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); + else + CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); + } + + // Allow the user to enable full exceptions code emission. + // We default off for Objective-C, on for Objective-C++. + if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, + options::OPT_fno_objc_arc_exceptions, + /*default=*/types::isCXX(Input.getType()))) + CmdArgs.push_back("-fobjc-arc-exceptions"); + } + + // Silence warning for full exception code emission options when explicitly + // set to use no ARC. + if (Args.hasArg(options::OPT_fno_objc_arc)) { + Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions); + Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions); + } + + // -fobjc-infer-related-result-type is the default, except in the Objective-C + // rewriter. + if (InferCovariantReturns) + CmdArgs.push_back("-fno-objc-infer-related-result-type"); + + // Pass down -fobjc-weak or -fno-objc-weak if present. + if (types::isObjC(Input.getType())) { + auto WeakArg = + Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak); + if (!WeakArg) { + // nothing to do + } else if (!Runtime.allowsWeak()) { + if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) + D.Diag(diag::err_objc_weak_unsupported); + } else { + WeakArg->render(Args, CmdArgs); + } + } +} + +static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + bool CaretDefault = true; + bool ColumnDefault = true; + + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diagnostics_classic, + options::OPT__SLASH_diagnostics_column, + options::OPT__SLASH_diagnostics_caret)) { + switch (A->getOption().getID()) { + case options::OPT__SLASH_diagnostics_caret: + CaretDefault = true; + ColumnDefault = true; + break; + case options::OPT__SLASH_diagnostics_column: + CaretDefault = false; + ColumnDefault = true; + break; + case options::OPT__SLASH_diagnostics_classic: + CaretDefault = false; + ColumnDefault = false; + break; + } + } + + // -fcaret-diagnostics is default. + if (!Args.hasFlag(options::OPT_fcaret_diagnostics, + options::OPT_fno_caret_diagnostics, CaretDefault)) + CmdArgs.push_back("-fno-caret-diagnostics"); + + // -fdiagnostics-fixit-info is default, only pass non-default. + if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, + options::OPT_fno_diagnostics_fixit_info)) + CmdArgs.push_back("-fno-diagnostics-fixit-info"); + + // Enable -fdiagnostics-show-option by default. + if (Args.hasFlag(options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option)) + CmdArgs.push_back("-fdiagnostics-show-option"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { + CmdArgs.push_back("-fdiagnostics-show-category"); + CmdArgs.push_back(A->getValue()); + } + + if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness, false)) + CmdArgs.push_back("-fdiagnostics-show-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + std::string Opt = + std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { + CmdArgs.push_back("-fdiagnostics-format"); + CmdArgs.push_back(A->getValue()); + } + + if (const Arg *A = Args.getLastArg( + options::OPT_fdiagnostics_show_note_include_stack, + options::OPT_fno_diagnostics_show_note_include_stack)) { + const Option &O = A->getOption(); + if (O.matches(options::OPT_fdiagnostics_show_note_include_stack)) + CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); + else + CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); + } + + // Color diagnostics are parsed by the driver directly from argv and later + // re-parsed to construct this job; claim any possible color diagnostic here + // to avoid warn_drv_unused_argument and diagnose bad + // OPT_fdiagnostics_color_EQ values. + for (const Arg *A : Args) { + const Option &O = A->getOption(); + if (!O.matches(options::OPT_fcolor_diagnostics) && + !O.matches(options::OPT_fdiagnostics_color) && + !O.matches(options::OPT_fno_color_diagnostics) && + !O.matches(options::OPT_fno_diagnostics_color) && + !O.matches(options::OPT_fdiagnostics_color_EQ)) + continue; + + if (O.matches(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") + D.Diag(diag::err_drv_clang_unsupported) + << ("-fdiagnostics-color=" + Value).str(); + } + A->claim(); + } + + if (D.getDiags().getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); + + if (Args.hasArg(options::OPT_fansi_escape_codes)) + CmdArgs.push_back("-fansi-escape-codes"); + + if (!Args.hasFlag(options::OPT_fshow_source_location, + options::OPT_fno_show_source_location)) + CmdArgs.push_back("-fno-show-source-location"); + + if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) + CmdArgs.push_back("-fdiagnostics-absolute-paths"); + + if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, + ColumnDefault)) + CmdArgs.push_back("-fno-show-column"); + + if (!Args.hasFlag(options::OPT_fspell_checking, + options::OPT_fno_spell_checking)) + CmdArgs.push_back("-fno-spell-checking"); +} + +static void RenderDebugOptions(const ToolChain &TC, const Driver &D, + const llvm::Triple &T, const ArgList &Args, + bool EmitCodeView, bool IsWindowsMSVC, + ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind &DebugInfoKind, + const Arg *&SplitDWARFArg) { + if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, + options::OPT_fno_debug_info_for_profiling, false)) + CmdArgs.push_back("-fdebug-info-for-profiling"); + + // The 'g' groups options involve a somewhat intricate sequence of decisions + // about what to pass from the driver to the frontend, but by the time they + // reach cc1 they've been factored into three well-defined orthogonal choices: + // * what level of debug info to generate + // * what dwarf version to write + // * what debugger tuning to use + // This avoids having to monkey around further in cc1 other than to disable + // codeview if not running in a Windows environment. Perhaps even that + // decision should be made in the driver as well though. + unsigned DWARFVersion = 0; + llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); + + bool SplitDWARFInlining = + Args.hasFlag(options::OPT_fsplit_dwarf_inlining, + options::OPT_fno_split_dwarf_inlining, true); + + Args.ClaimAllArgs(options::OPT_g_Group); + + SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf); + + if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { + // If the last option explicitly specified a debug-info level, use it. + if (A->getOption().matches(options::OPT_gN_Group)) { + DebugInfoKind = DebugLevelToInfoKind(*A); + // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. + // But -gsplit-dwarf is not a g_group option, hence we have to check the + // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. + // This gets a bit more complicated if you've disabled inline info in the + // skeleton CUs (SplitDWARFInlining) - then there's value in composing + // split-dwarf and line-tables-only, so let those compose naturally in + // that case. + // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. + if (SplitDWARFArg) { + if (A->getIndex() > SplitDWARFArg->getIndex()) { + if (DebugInfoKind == codegenoptions::NoDebugInfo || + (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + SplitDWARFInlining)) + SplitDWARFArg = nullptr; + } else if (SplitDWARFInlining) + DebugInfoKind = codegenoptions::NoDebugInfo; + } + } else { + // For any other 'g' option, use Limited. + DebugInfoKind = codegenoptions::LimitedDebugInfo; + } + } + + // If a debugger tuning argument appeared, remember it. + if (const Arg *A = + Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { + if (A->getOption().matches(options::OPT_glldb)) + DebuggerTuning = llvm::DebuggerKind::LLDB; + else if (A->getOption().matches(options::OPT_gsce)) + DebuggerTuning = llvm::DebuggerKind::SCE; + else + DebuggerTuning = llvm::DebuggerKind::GDB; + } + + // If a -gdwarf argument appeared, remember it. + if (const Arg *A = + Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5)) + DWARFVersion = DwarfVersionNum(A->getSpelling()); + + // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility + // argument parsing. + if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { + // DWARFVersion remains at 0 if no explicit choice was made. + CmdArgs.push_back("-gcodeview"); + } else if (DWARFVersion == 0 && + DebugInfoKind != codegenoptions::NoDebugInfo) { + DWARFVersion = TC.GetDefaultDwarfVersion(); + } + + // We ignore flag -gstrict-dwarf for now. + // And we handle flag -grecord-gcc-switches later with DWARFDebugFlags. + Args.ClaimAllArgs(options::OPT_g_flags_Group); + + // Column info is included by default for everything except SCE and CodeView. + // Clang doesn't track end columns, just starting columns, which, in theory, + // is fine for CodeView (and PDB). In practice, however, the Microsoft + // debuggers don't handle missing end columns well, so it's better not to + // include any column info. + if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, + /*Default=*/!(IsWindowsMSVC && EmitCodeView) && + DebuggerTuning != llvm::DebuggerKind::SCE)) + CmdArgs.push_back("-dwarf-column-info"); + + // FIXME: Move backend command line options to the module. + // If -gline-tables-only is the last option it wins. + if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && + Args.hasArg(options::OPT_gmodules)) { + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-dwarf-ext-refs"); + CmdArgs.push_back("-fmodule-format=obj"); + } + + // -gsplit-dwarf should turn on -g and enable the backend dwarf + // splitting and extraction. + // FIXME: Currently only works on Linux. + if (T.isOSLinux()) { + if (!SplitDWARFInlining) + CmdArgs.push_back("-fno-split-dwarf-inlining"); + + if (SplitDWARFArg) { + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-enable-split-dwarf"); + } + } + + // After we've dealt with all combinations of things that could + // make DebugInfoKind be other than None or DebugLineTablesOnly, + // figure out if we need to "upgrade" it to standalone debug info. + // We parse these two '-f' options whether or not they will be used, + // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" + bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, + options::OPT_fno_standalone_debug, + TC.GetDefaultStandaloneDebug()); + if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = codegenoptions::FullDebugInfo; + + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, + DebuggerTuning); + + // -fdebug-macro turns on macro debug info generation. + if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, + false)) + CmdArgs.push_back("-debug-info-macro"); + + // -ggnu-pubnames turns on gnu style pubnames in the backend. + if (Args.hasArg(options::OPT_ggnu_pubnames)) + CmdArgs.push_back("-ggnu-pubnames"); + + // -gdwarf-aranges turns on the emission of the aranges section in the + // backend. + // Always enabled for SCE tuning. + if (Args.hasArg(options::OPT_gdwarf_aranges) || + DebuggerTuning == llvm::DebuggerKind::SCE) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-generate-arange-section"); + } + + if (Args.hasFlag(options::OPT_fdebug_types_section, + options::OPT_fno_debug_types_section, false)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-generate-type-units"); + } + + // Decide how to render forward declarations of template instantiations. + // SCE wants full descriptions, others just get them in the name. + if (DebuggerTuning == llvm::DebuggerKind::SCE) + CmdArgs.push_back("-debug-forward-template-params"); + + // Do we need to explicitly import anonymous namespaces into the parent scope? + if (DebuggerTuning == llvm::DebuggerKind::SCE) + CmdArgs.push_back("-dwarf-explicit-import"); + + RenderDebugInfoCompressionArgs(Args, CmdArgs, D); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const llvm::Triple &RawTriple = getToolChain().getTriple(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const std::string &TripleStr = Triple.getTriple(); @@ -1918,18 +3040,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Inputs.size() == 1) && "Unable to handle multiple inputs."); - bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment(); - bool IsWindowsCygnus = - getToolChain().getTriple().isWindowsCygwinEnvironment(); - bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); - bool IsPS4CPU = getToolChain().getTriple().isPS4CPU(); - bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); + const llvm::Triple *AuxTriple = + IsCuda ? getToolChain().getAuxTriple() : nullptr; + + bool IsWindowsGNU = RawTriple.isWindowsGNUEnvironment(); + bool IsWindowsCygnus = RawTriple.isWindowsCygwinEnvironment(); + bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); + bool IsIAMCU = RawTriple.isOSIAMCU(); // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to // pass Windows-specific flags to cc1. if (IsCuda) { - const llvm::Triple *AuxTriple = getToolChain().getAuxTriple(); IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment(); IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment(); @@ -2073,8 +3195,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // The Darwin and PS4 linkers currently use the legacy LTO API, which // does not support LTO unit features (CFI, whole program vtable opt) // under ThinLTO. - if (!(getToolChain().getTriple().isOSDarwin() || - getToolChain().getTriple().isPS4()) || + if (!(RawTriple.isOSDarwin() || RawTriple.isPS4()) || D.getLTOMode() == LTOK_Full) CmdArgs.push_back("-flto-unit"); } @@ -2121,78 +3242,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-static-define"); - if (isa<AnalyzeJobAction>(JA)) { - // Enable region store model by default. - CmdArgs.push_back("-analyzer-store=region"); - - // Treat blocks as analysis entry points. - CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); - - CmdArgs.push_back("-analyzer-eagerly-assume"); - - // Add default argument set. - if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { - CmdArgs.push_back("-analyzer-checker=core"); - CmdArgs.push_back("-analyzer-checker=apiModeling"); - - if (!IsWindowsMSVC) { - CmdArgs.push_back("-analyzer-checker=unix"); - } else { - // Enable "unix" checkers that also work on Windows. - CmdArgs.push_back("-analyzer-checker=unix.API"); - CmdArgs.push_back("-analyzer-checker=unix.Malloc"); - CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof"); - CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator"); - CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg"); - CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); - } - - // Disable some unix checkers for PS4. - if (IsPS4CPU) { - CmdArgs.push_back("-analyzer-disable-checker=unix.API"); - CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); - } - - if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) - CmdArgs.push_back("-analyzer-checker=osx"); - - CmdArgs.push_back("-analyzer-checker=deadcode"); - - if (types::isCXX(Input.getType())) - CmdArgs.push_back("-analyzer-checker=cplusplus"); - - if (!IsPS4CPU) { - CmdArgs.push_back( - "-analyzer-checker=security.insecureAPI.UncheckedReturn"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); - } - - // Default nullability checks. - CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); - CmdArgs.push_back( - "-analyzer-checker=nullability.NullReturnedFromNonnull"); - } - - // Set the output format. The default is plist, for (lame) historical - // reasons. - CmdArgs.push_back("-analyzer-output"); - if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) - CmdArgs.push_back(A->getValue()); - else - CmdArgs.push_back("plist"); - - // Disable the presentation of standard compiler warnings when - // using --analyze. We only want to show static analyzer diagnostics - // or frontend errors. - CmdArgs.push_back("-w"); - - // Add -Xanalyzer arguments when running as analyzer. - Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); - } + if (isa<AnalyzeJobAction>(JA)) + RenderAnalyzerOptions(Args, CmdArgs, Triple, Input); CheckCodeGenerationOptions(D, Args); @@ -2270,6 +3321,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, true)) CmdArgs.push_back("-fno-jump-tables"); + if (Args.hasFlag(options::OPT_fprofile_sample_accurate, + options::OPT_fno_profile_sample_accurate, false)) + CmdArgs.push_back("-fprofile-sample-accurate"); + if (!Args.hasFlag(options::OPT_fpreserve_as_comments, options::OPT_fno_preserve_as_comments, true)) CmdArgs.push_back("-fno-preserve-as-comments"); @@ -2283,7 +3338,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_freg_struct_return)) { if (getToolChain().getArch() != llvm::Triple::x86) { D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << getToolChain().getTriple().str(); + << A->getSpelling() << RawTriple.str(); } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { CmdArgs.push_back("-fpcc-struct-return"); } else { @@ -2295,7 +3350,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-fdefault-calling-conv=stdcall"); - if (shouldUseFramePointer(Args, getToolChain().getTriple())) + if (shouldUseFramePointer(Args, RawTriple)) CmdArgs.push_back("-mdisable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) @@ -2308,7 +3363,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; // We turn strict aliasing off by default if we're in CL mode, since MSVC // doesn't do any TBAA. - bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode(); + bool TBAAOnByDefault = !D.IsCLMode(); if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, options::OPT_fno_strict_aliasing, TBAAOnByDefault)) CmdArgs.push_back("-relaxed-aliasing"); @@ -2332,164 +3387,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, + options::OPT_fno_fine_grained_bitfield_accesses); + // Handle segmented stacks. if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("-split-stacks"); - // Handle various floating point optimization flags, mapping them to the - // appropriate LLVM code generation flags. This is complicated by several - // "umbrella" flags, so we do this by stepping through the flags incrementally - // adjusting what we think is enabled/disabled, then at the end settting the - // LLVM flags based on the final state. - bool HonorInfs = true; - bool HonorNans = true; - // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. - bool MathErrno = getToolChain().IsMathErrnoDefault(); - bool AssociativeMath = false; - bool ReciprocalMath = false; - bool SignedZeros = true; - bool TrappingMath = true; - StringRef DenormalFpMath = ""; - StringRef FpContract = ""; - - for (Arg *A : Args) { - switch (A->getOption().getID()) { - // If this isn't an FP option skip the claim below - default: - continue; - - // Options controlling individual features - case options::OPT_fhonor_infinities: HonorInfs = true; break; - case options::OPT_fno_honor_infinities: HonorInfs = false; break; - case options::OPT_fhonor_nans: HonorNans = true; break; - case options::OPT_fno_honor_nans: HonorNans = false; break; - case options::OPT_fmath_errno: MathErrno = true; break; - case options::OPT_fno_math_errno: MathErrno = false; break; - case options::OPT_fassociative_math: AssociativeMath = true; break; - case options::OPT_fno_associative_math: AssociativeMath = false; break; - case options::OPT_freciprocal_math: ReciprocalMath = true; break; - case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; - case options::OPT_fsigned_zeros: SignedZeros = true; break; - case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; - case options::OPT_fno_trapping_math: TrappingMath = false; break; - - case options::OPT_fdenormal_fp_math_EQ: - DenormalFpMath = A->getValue(); - break; - - // Validate and pass through -fp-contract option. - case options::OPT_ffp_contract: { - StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") { - FpContract = Val; - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } - break; - } - - case options::OPT_ffinite_math_only: - HonorInfs = false; - HonorNans = false; - break; - case options::OPT_fno_finite_math_only: - HonorInfs = true; - HonorNans = true; - break; - - case options::OPT_funsafe_math_optimizations: - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - break; - case options::OPT_fno_unsafe_math_optimizations: - AssociativeMath = false; - ReciprocalMath = false; - SignedZeros = true; - TrappingMath = true; - // -fno_unsafe_math_optimizations restores default denormal handling - DenormalFpMath = ""; - break; - - case options::OPT_Ofast: - // If -Ofast is the optimization level, then -ffast-math should be enabled - if (!OFastEnabled) - continue; - LLVM_FALLTHROUGH; - case options::OPT_ffast_math: - HonorInfs = false; - HonorNans = false; - MathErrno = false; - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - // If fast-math is set then set the fp-contract mode to fast. - FpContract = "fast"; - break; - case options::OPT_fno_fast_math: - HonorInfs = true; - HonorNans = true; - // Turning on -ffast-math (with either flag) removes the need for - // MathErrno. However, turning *off* -ffast-math merely restores the - // toolchain default (which may be false). - MathErrno = getToolChain().IsMathErrnoDefault(); - AssociativeMath = false; - ReciprocalMath = false; - SignedZeros = true; - TrappingMath = true; - // -fno_fast_math restores default denormal and fpcontract handling - DenormalFpMath = ""; - FpContract = ""; - break; - } - // If we handled this option claim it - A->claim(); - } - - if (!HonorInfs) - CmdArgs.push_back("-menable-no-infs"); - - if (!HonorNans) - CmdArgs.push_back("-menable-no-nans"); - - if (MathErrno) - CmdArgs.push_back("-fmath-errno"); - - if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - !TrappingMath) - CmdArgs.push_back("-menable-unsafe-fp-math"); - - if (!SignedZeros) - CmdArgs.push_back("-fno-signed-zeros"); - - if (ReciprocalMath) - CmdArgs.push_back("-freciprocal-math"); - - if (!TrappingMath) - CmdArgs.push_back("-fno-trapping-math"); - - if (!DenormalFpMath.empty()) - CmdArgs.push_back(Args.MakeArgString("-fdenormal-fp-math="+DenormalFpMath)); - - if (!FpContract.empty()) - CmdArgs.push_back(Args.MakeArgString("-ffp-contract="+FpContract)); - - ParseMRecip(getToolChain().getDriver(), Args, CmdArgs); - - // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the - // individual features enabled by -ffast-math instead of the option itself as - // that's consistent with gcc's behaviour. - if (!HonorInfs && !HonorNans && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) - CmdArgs.push_back("-ffast-math"); - - // Handle __FINITE_MATH_ONLY__ similarly. - if (!HonorInfs && !HonorNans) - CmdArgs.push_back("-ffinite-math-only"); + RenderFloatingPointOptions(getToolChain(), D, OFastEnabled, Args, CmdArgs); // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. @@ -2516,13 +3421,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable -mconstructor-aliases except on darwin, where we have to work around // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where // aliases aren't supported. - if (!getToolChain().getTriple().isOSDarwin() && - !getToolChain().getTriple().isNVPTX()) + if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we // try to use them. - if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) + if (KernelOrKext && RawTriple.isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, @@ -2536,6 +3440,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mpie-copy-relocations"); } + if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) { + CmdArgs.push_back("-fno-plt"); + } + + // -fhosted is default. + // TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to + // use Freestanding. + bool Freestanding = + Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || + KernelOrKext; + if (Freestanding) + CmdArgs.push_back("-ffreestanding"); + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. @@ -2544,7 +3461,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_asynchronous_unwind_tables, (getToolChain().IsUnwindTablesDefault(Args) || getToolChain().getSanitizerArgs().needsUnwindTables()) && - !KernelOrKext); + !Freestanding); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); @@ -2572,108 +3489,47 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(CPU)); } - if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { - CmdArgs.push_back("-mfpmath"); - CmdArgs.push_back(A->getValue()); - } - - // Add the target features - getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, false); - - // Add target specific flags. - switch (getToolChain().getArch()) { - default: - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - // Use the effective triple, which takes into account the deployment target. - AddARMTargetArgs(Triple, Args, CmdArgs, KernelOrKext); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - AddAArch64TargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - AddMIPSTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - AddPPCTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - AddSparcTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::systemz: - AddSystemZTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - AddX86TargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::lanai: - AddLanaiTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::hexagon: - AddHexagonTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - AddWebAssemblyTargetArgs(Args, CmdArgs); - break; - } + RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs); - // The 'g' groups options involve a somewhat intricate sequence of decisions - // about what to pass from the driver to the frontend, but by the time they - // reach cc1 they've been factored into three well-defined orthogonal choices: - // * what level of debug info to generate - // * what dwarf version to write - // * what debugger tuning to use - // This avoids having to monkey around further in cc1 other than to disable - // codeview if not running in a Windows environment. Perhaps even that - // decision should be made in the driver as well though. - unsigned DwarfVersion = 0; - llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning(); // These two are potentially updated by AddClangCLArgs. codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; bool EmitCodeView = false; // Add clang-cl arguments. types::ID InputType = Input.getType(); - if (getToolChain().getDriver().IsCLMode()) + if (D.IsCLMode()) AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + const Arg *SplitDWARFArg = nullptr; + RenderDebugOptions(getToolChain(), D, RawTriple, Args, EmitCodeView, + IsWindowsMSVC, CmdArgs, DebugInfoKind, SplitDWARFArg); + + // Add the split debug info name to the command lines here so we + // can propagate it to the backend. + bool SplitDWARF = SplitDWARFArg && RawTriple.isOSLinux() && + (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || + isa<BackendJobAction>(JA)); + const char *SplitDWARFOut; + if (SplitDWARF) { + CmdArgs.push_back("-split-dwarf-file"); + SplitDWARFOut = SplitDebugName(Args, Input); + CmdArgs.push_back(SplitDWARFOut); + } + // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { CmdArgs.push_back("-target-linker-version"); CmdArgs.push_back(A->getValue()); } - if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple())) + if (!shouldUseLeafFramePointer(Args, RawTriple)) CmdArgs.push_back("-momit-leaf-frame-pointer"); // Explicitly error on some things we know we don't support and can't just // ignore. if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; - if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && + if (types::isCXX(InputType) && RawTriple.isOSDarwin() && getToolChain().getArch() == llvm::Triple::x86) { if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || (Unsupported = Args.getLastArg(options::OPT_mkernel))) @@ -2706,139 +3562,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } - bool splitDwarfInlining = - Args.hasFlag(options::OPT_fsplit_dwarf_inlining, - options::OPT_fno_split_dwarf_inlining, true); - - Args.ClaimAllArgs(options::OPT_g_Group); - Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); - if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { - // If the last option explicitly specified a debug-info level, use it. - if (A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); - // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. - // But -gsplit-dwarf is not a g_group option, hence we have to check the - // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.) - // This gets a bit more complicated if you've disabled inline info in the - // skeleton CUs (splitDwarfInlining) - then there's value in composing - // split-dwarf and line-tables-only, so let those compose naturally in - // that case. - // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. - if (SplitDwarfArg) { - if (A->getIndex() > SplitDwarfArg->getIndex()) { - if (DebugInfoKind == codegenoptions::NoDebugInfo || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && - splitDwarfInlining)) - SplitDwarfArg = nullptr; - } else if (splitDwarfInlining) - DebugInfoKind = codegenoptions::NoDebugInfo; - } - } else - // For any other 'g' option, use Limited. - DebugInfoKind = codegenoptions::LimitedDebugInfo; - } - - // If a debugger tuning argument appeared, remember it. - if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, - options::OPT_ggdbN_Group)) { - if (A->getOption().matches(options::OPT_glldb)) - DebuggerTuning = llvm::DebuggerKind::LLDB; - else if (A->getOption().matches(options::OPT_gsce)) - DebuggerTuning = llvm::DebuggerKind::SCE; - else - DebuggerTuning = llvm::DebuggerKind::GDB; - } - - // If a -gdwarf argument appeared, remember it. - if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - DwarfVersion = DwarfVersionNum(A->getSpelling()); - - // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility - // argument parsing. - if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { - // DwarfVersion remains at 0 if no explicit choice was made. - CmdArgs.push_back("-gcodeview"); - } else if (DwarfVersion == 0 && - DebugInfoKind != codegenoptions::NoDebugInfo) { - DwarfVersion = getToolChain().GetDefaultDwarfVersion(); - } - - // We ignore flag -gstrict-dwarf for now. - // And we handle flag -grecord-gcc-switches later with DwarfDebugFlags. - Args.ClaimAllArgs(options::OPT_g_flags_Group); - - // Column info is included by default for everything except PS4 and CodeView. - // Clang doesn't track end columns, just starting columns, which, in theory, - // is fine for CodeView (and PDB). In practice, however, the Microsoft - // debuggers don't handle missing end columns well, so it's better not to - // include any column info. - if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/ !IsPS4CPU && !(IsWindowsMSVC && EmitCodeView))) - CmdArgs.push_back("-dwarf-column-info"); - - // FIXME: Move backend command line options to the module. - // If -gline-tables-only is the last option it wins. - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - Args.hasArg(options::OPT_gmodules)) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-dwarf-ext-refs"); - CmdArgs.push_back("-fmodule-format=obj"); - } - - // -gsplit-dwarf should turn on -g and enable the backend dwarf - // splitting and extraction. - // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().isOSLinux()) { - if (!splitDwarfInlining) - CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (SplitDwarfArg) { - if (DebugInfoKind == codegenoptions::NoDebugInfo) - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-enable-split-dwarf"); - } - } - - // After we've dealt with all combinations of things that could - // make DebugInfoKind be other than None or DebugLineTablesOnly, - // figure out if we need to "upgrade" it to standalone debug info. - // We parse these two '-f' options whether or not they will be used, - // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" - bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, - options::OPT_fno_standalone_debug, - getToolChain().GetDefaultStandaloneDebug()); - if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) - DebugInfoKind = codegenoptions::FullDebugInfo; - RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, - DebuggerTuning); - - // -fdebug-macro turns on macro debug info generation. - if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, - false)) - CmdArgs.push_back("-debug-info-macro"); - - // -ggnu-pubnames turns on gnu style pubnames in the backend. - if (Args.hasArg(options::OPT_ggnu_pubnames)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-gnu-dwarf-pub-sections"); - } - - // -gdwarf-aranges turns on the emission of the aranges section in the - // backend. - // Always enabled on the PS4. - if (Args.hasArg(options::OPT_gdwarf_aranges) || IsPS4CPU) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-arange-section"); - } - - if (Args.hasFlag(options::OPT_fdebug_types_section, - options::OPT_fno_debug_types_section, false)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-type-units"); - } - - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); - bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, @@ -2855,7 +3578,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); - Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (auto *A = Args.getLastArg( + options::OPT_finstrument_functions, + options::OPT_finstrument_functions_after_inlining, + options::OPT_finstrument_function_entry_bare)) + A->render(Args, CmdArgs); addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); @@ -2863,7 +3590,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ABICompatArg->render(Args, CmdArgs); // Add runtime flag for PS4 when PGO or Coverage are enabled. - if (getToolChain().getTriple().isPS4CPU()) + if (RawTriple.isPS4CPU()) PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); // Pass options for controlling the default header search paths. @@ -2883,75 +3610,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_working_directory); - bool ARCMTEnabled = false; - if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { - if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, - options::OPT_ccc_arcmt_modify, - options::OPT_ccc_arcmt_migrate)) { - ARCMTEnabled = true; - switch (A->getOption().getID()) { - default: - llvm_unreachable("missed a case"); - case options::OPT_ccc_arcmt_check: - CmdArgs.push_back("-arcmt-check"); - break; - case options::OPT_ccc_arcmt_modify: - CmdArgs.push_back("-arcmt-modify"); - break; - case options::OPT_ccc_arcmt_migrate: - CmdArgs.push_back("-arcmt-migrate"); - CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue()); - - Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); - Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); - break; - } - } - } else { - Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); - Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); - Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); - } - - if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { - if (ARCMTEnabled) { - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-ccc-arcmt-migrate"; - } - CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue()); - - if (!Args.hasArg(options::OPT_objcmt_migrate_literals, - options::OPT_objcmt_migrate_subscripting, - options::OPT_objcmt_migrate_property)) { - // None specified, means enable them all. - CmdArgs.push_back("-objcmt-migrate-literals"); - CmdArgs.push_back("-objcmt-migrate-subscripting"); - CmdArgs.push_back("-objcmt-migrate-property"); - } else { - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); - } - } else { - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); - } + RenderARCMigrateToolOptions(D, Args, CmdArgs); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -3196,14 +3855,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); - // -fhosted is default. - bool IsHosted = true; - if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || - KernelOrKext) { - CmdArgs.push_back("-ffreestanding"); - IsHosted = false; - } - // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); @@ -3228,7 +3879,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp, false) && (JA.isDeviceOffloading(Action::OFK_None) || JA.isDeviceOffloading(Action::OFK_OpenMP))) { - switch (getToolChain().getDriver().getOpenMPRuntime(Args)) { + switch (D.getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: case Driver::OMPRT_IOMP5: // Clang can generate useful OpenMP code for these two runtime libraries. @@ -3309,49 +3960,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pthread); - // -stack-protector=0 is default. - unsigned StackProtectorLevel = 0; - // NVPTX doesn't support stack protectors; from the compiler's perspective, it - // doesn't even have a stack! - if (!Triple.isNVPTX()) { - if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, - options::OPT_fstack_protector_all, - options::OPT_fstack_protector_strong, - options::OPT_fstack_protector)) { - if (A->getOption().matches(options::OPT_fstack_protector)) { - StackProtectorLevel = std::max<unsigned>( - LangOptions::SSPOn, - getToolChain().GetDefaultStackProtectorLevel(KernelOrKext)); - } else if (A->getOption().matches(options::OPT_fstack_protector_strong)) - StackProtectorLevel = LangOptions::SSPStrong; - else if (A->getOption().matches(options::OPT_fstack_protector_all)) - StackProtectorLevel = LangOptions::SSPReq; - } else { - StackProtectorLevel = - getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); - // Only use a default stack protector on Darwin in case -ffreestanding - // is not specified. - if (Triple.isOSDarwin() && !IsHosted) - StackProtectorLevel = 0; - } - } - if (StackProtectorLevel) { - CmdArgs.push_back("-stack-protector"); - CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); - } - - // --param ssp-buffer-size= - for (const Arg *A : Args.filtered(options::OPT__param)) { - StringRef Str(A->getValue()); - if (Str.startswith("ssp-buffer-size=")) { - if (StackProtectorLevel) { - CmdArgs.push_back("-stack-protector-buffer-size"); - // FIXME: Verify the argument is a valid integer. - CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); - } - A->claim(); - } - } + RenderSSPOptions(getToolChain(), Args, CmdArgs, KernelOrKext); // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, @@ -3372,20 +3981,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } - switch (getToolChain().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - CmdArgs.push_back("-fallow-half-arguments-and-returns"); - break; - - default: - break; - } - if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { @@ -3404,44 +3999,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Forward -cl options to -cc1 - if (Args.getLastArg(options::OPT_cl_opt_disable)) { - CmdArgs.push_back("-cl-opt-disable"); - } - if (Args.getLastArg(options::OPT_cl_strict_aliasing)) { - CmdArgs.push_back("-cl-strict-aliasing"); - } - if (Args.getLastArg(options::OPT_cl_single_precision_constant)) { - CmdArgs.push_back("-cl-single-precision-constant"); - } - if (Args.getLastArg(options::OPT_cl_finite_math_only)) { - CmdArgs.push_back("-cl-finite-math-only"); - } - if (Args.getLastArg(options::OPT_cl_kernel_arg_info)) { - CmdArgs.push_back("-cl-kernel-arg-info"); - } - if (Args.getLastArg(options::OPT_cl_unsafe_math_optimizations)) { - CmdArgs.push_back("-cl-unsafe-math-optimizations"); - } - if (Args.getLastArg(options::OPT_cl_fast_relaxed_math)) { - CmdArgs.push_back("-cl-fast-relaxed-math"); - } - if (Args.getLastArg(options::OPT_cl_mad_enable)) { - CmdArgs.push_back("-cl-mad-enable"); - } - if (Args.getLastArg(options::OPT_cl_no_signed_zeros)) { - CmdArgs.push_back("-cl-no-signed-zeros"); - } - if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { - std::string CLStdStr = "-cl-std="; - CLStdStr += A->getValue(); - CmdArgs.push_back(Args.MakeArgString(CLStdStr)); - } - if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) { - CmdArgs.push_back("-cl-denorms-are-zero"); - } - if (Args.getLastArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt)) { - CmdArgs.push_back("-cl-fp32-correctly-rounded-divide-sqrt"); - } + RenderOpenCLOptions(Args, CmdArgs); // Forward -f options with positive and negative forms; we translate // these by hand. @@ -3453,36 +4011,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, - options::OPT_fno_debug_info_for_profiling, false)) - CmdArgs.push_back("-fdebug-info-for-profiling"); - - // -fbuiltin is default unless -mkernel is used. - bool UseBuiltins = - Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, - !Args.hasArg(options::OPT_mkernel)); - if (!UseBuiltins) - CmdArgs.push_back("-fno-builtin"); - - // -ffreestanding implies -fno-builtin. - if (Args.hasArg(options::OPT_ffreestanding)) - UseBuiltins = false; - - // Process the -fno-builtin-* options. - for (const auto &Arg : Args) { - const Option &O = Arg->getOption(); - if (!O.matches(options::OPT_fno_builtin_)) - continue; - - Arg->claim(); - // If -fno-builtin is specified, then there's no need to pass the option to - // the frontend. - if (!UseBuiltins) - continue; - - StringRef FuncName = Arg->getValue(); - CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); - } + RenderBuiltinOptions(getToolChain(), RawTriple, Args, CmdArgs); if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) @@ -3501,163 +4030,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks-runtime-optional"); } + // -fencode-extended-block-signature=1 is default. + if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) + CmdArgs.push_back("-fencode-extended-block-signature"); + if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, false) && types::isCXX(InputType)) { CmdArgs.push_back("-fcoroutines-ts"); } - // -fmodules enables the use of precompiled modules (off by default). - // Users can pass -fno-cxx-modules to turn off modules support for - // C++/Objective-C++ programs. - bool HaveClangModules = false; - if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { - bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, - options::OPT_fno_cxx_modules, true); - if (AllowedInCXX || !types::isCXX(InputType)) { - CmdArgs.push_back("-fmodules"); - HaveClangModules = true; - } - } - - bool HaveAnyModules = HaveClangModules; - if (Args.hasArg(options::OPT_fmodules_ts)) { - CmdArgs.push_back("-fmodules-ts"); - HaveAnyModules = true; - } - - // -fmodule-maps enables implicit reading of module map files. By default, - // this is enabled if we are using Clang's flavor of precompiled modules. - if (Args.hasFlag(options::OPT_fimplicit_module_maps, - options::OPT_fno_implicit_module_maps, HaveClangModules)) { - CmdArgs.push_back("-fimplicit-module-maps"); - } - - // -fmodules-decluse checks that modules used are declared so (off by - // default). - if (Args.hasFlag(options::OPT_fmodules_decluse, - options::OPT_fno_modules_decluse, false)) { - CmdArgs.push_back("-fmodules-decluse"); - } - - // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that - // all #included headers are part of modules. - if (Args.hasFlag(options::OPT_fmodules_strict_decluse, - options::OPT_fno_modules_strict_decluse, false)) { - CmdArgs.push_back("-fmodules-strict-decluse"); - } - - // -fno-implicit-modules turns off implicitly compiling modules on demand. - if (!Args.hasFlag(options::OPT_fimplicit_modules, - options::OPT_fno_implicit_modules, HaveClangModules)) { - if (HaveAnyModules) - CmdArgs.push_back("-fno-implicit-modules"); - } else if (HaveAnyModules) { - // -fmodule-cache-path specifies where our implicitly-built module files - // should be written. - SmallString<128> Path; - if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) - Path = A->getValue(); - if (C.isForDiagnostics()) { - // When generating crash reports, we want to emit the modules along with - // the reproduction sources, so we ignore any provided module path. - Path = Output.getFilename(); - llvm::sys::path::replace_extension(Path, ".cache"); - llvm::sys::path::append(Path, "modules"); - } else if (Path.empty()) { - // No module path was provided: use the default. - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); - llvm::sys::path::append(Path, "org.llvm.clang."); - appendUserToPath(Path); - llvm::sys::path::append(Path, "ModuleCache"); - } - const char Arg[] = "-fmodules-cache-path="; - Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(Path)); - } - - if (HaveAnyModules) { - // -fprebuilt-module-path specifies where to load the prebuilt module files. - for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) - CmdArgs.push_back(Args.MakeArgString( - std::string("-fprebuilt-module-path=") + A->getValue())); - } - - // -fmodule-name specifies the module that is currently being built (or - // used for header checking by -fmodule-maps). - Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); - - // -fmodule-map-file can be used to specify files containing module - // definitions. - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); - - // -fbuiltin-module-map can be used to load the clang - // builtin headers modulemap file. - if (Args.hasArg(options::OPT_fbuiltin_module_map)) { - SmallString<128> BuiltinModuleMap(getToolChain().getDriver().ResourceDir); - llvm::sys::path::append(BuiltinModuleMap, "include"); - llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); - if (llvm::sys::fs::exists(BuiltinModuleMap)) { - CmdArgs.push_back(Args.MakeArgString("-fmodule-map-file=" + - BuiltinModuleMap)); - } - } - - // -fmodule-file can be used to specify files containing precompiled modules. - if (HaveAnyModules) - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); - else - Args.ClaimAllArgs(options::OPT_fmodule_file); - - // When building modules and generating crashdumps, we need to dump a module - // dependency VFS alongside the output. - if (HaveClangModules && C.isForDiagnostics()) { - SmallString<128> VFSDir(Output.getFilename()); - llvm::sys::path::replace_extension(VFSDir, ".cache"); - // Add the cache directory as a temp so the crash diagnostics pick it up. - C.addTempFile(Args.MakeArgString(VFSDir)); - - llvm::sys::path::append(VFSDir, "vfs"); - CmdArgs.push_back("-module-dependency-dir"); - CmdArgs.push_back(Args.MakeArgString(VFSDir)); - } - - if (HaveClangModules) - Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); - - // Pass through all -fmodules-ignore-macro arguments. - Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); - - Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); - - if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { - if (Args.hasArg(options::OPT_fbuild_session_timestamp)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "-fbuild-session-timestamp"; - - llvm::sys::fs::file_status Status; - if (llvm::sys::fs::status(A->getValue(), Status)) - D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back( - Args.MakeArgString("-fbuild-session-timestamp=" + - Twine((uint64_t)Status.getLastModificationTime() - .time_since_epoch() - .count()))); - } - - if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { - if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, - options::OPT_fbuild_session_file)) - D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); - - Args.AddLastArg(CmdArgs, - options::OPT_fmodules_validate_once_per_build_session); - } + Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, + options::OPT_fno_double_square_bracket_attributes); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); + bool HaveModules = false; + RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, @@ -3681,28 +4068,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getArch() == llvm::Triple::hexagon)) CmdArgs.push_back("-fshort-enums"); - // -fsigned-char is default. - if (Arg *A = Args.getLastArg( - options::OPT_fsigned_char, options::OPT_fno_signed_char, - options::OPT_funsigned_char, options::OPT_fno_unsigned_char)) { - if (A->getOption().matches(options::OPT_funsigned_char) || - A->getOption().matches(options::OPT_fno_signed_char)) { - CmdArgs.push_back("-fno-signed-char"); - } - } else if (!isSignedCharDefault(getToolChain().getTriple())) { - CmdArgs.push_back("-fno-signed-char"); - } + RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs); // -fuse-cxa-atexit is default. if (!Args.hasFlag( options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, - !IsWindowsCygnus && !IsWindowsGNU && - getToolChain().getTriple().getOS() != llvm::Triple::Solaris && + !RawTriple.isOSWindows() && + RawTriple.getOS() != llvm::Triple::Solaris && getToolChain().getArch() != llvm::Triple::hexagon && getToolChain().getArch() != llvm::Triple::xcore && - ((getToolChain().getTriple().getVendor() != - llvm::Triple::MipsTechnologies) || - getToolChain().getTriple().hasEnvironment())) || + ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) || + RawTriple.hasEnvironment())) || KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); @@ -3724,8 +4100,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_ms_extensions, true)))) CmdArgs.push_back("-fms-compatibility"); - VersionTuple MSVT = - getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args); + VersionTuple MSVT = getToolChain().computeMSVCVersion(&D, Args); if (!MSVT.empty()) CmdArgs.push_back( Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); @@ -3736,7 +4111,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) { LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue()) .Case("c++14", "-std=c++14") - .Case("c++latest", "-std=c++1z") + .Case("c++17", "-std=c++17") + .Case("c++latest", "-std=c++2a") .Default(""); if (LanguageStandard.empty()) D.Diag(clang::diag::warn_drv_unused_argument) @@ -3760,7 +4136,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-declspec is default, except for PS4. if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, - getToolChain().getTriple().isPS4())) + RawTriple.isPS4())) CmdArgs.push_back("-fdeclspec"); else if (Args.hasArg(options::OPT_fno_declspec)) CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. @@ -3772,8 +4148,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !IsWindowsMSVC || IsMSVC2015Compatible)) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except for Windows where MSVC STL - // needs it. + // -fno-delayed-template-parsing is default, except when targetting MSVC. + // Many old Windows SDK versions require this to parse. + // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their + // compiler. We should be able to disable this by default at some point. if (Args.hasFlag(options::OPT_fdelayed_template_parsing, options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) CmdArgs.push_back("-fdelayed-template-parsing"); @@ -3799,90 +4177,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager); - ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); - - // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. Except for deployment target of 10.5, - // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch - // gets ignored silently. - if (objcRuntime.isNonFragile()) { - if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, - options::OPT_fno_objc_legacy_dispatch, - objcRuntime.isLegacyDispatchDefaultForArch( - getToolChain().getArch()))) { - if (getToolChain().UseObjCMixedDispatch()) - CmdArgs.push_back("-fobjc-dispatch-method=mixed"); - else - CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); - } - } - - // When ObjectiveC legacy runtime is in effect on MacOSX, - // turn on the option to do Array/Dictionary subscripting - // by default. - if (getToolChain().getArch() == llvm::Triple::x86 && - getToolChain().getTriple().isMacOSX() && - !getToolChain().getTriple().isMacOSXVersionLT(10, 7) && - objcRuntime.getKind() == ObjCRuntime::FragileMacOSX && - objcRuntime.isNeXTFamily()) - CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); - - // -fencode-extended-block-signature=1 is default. - if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) { - CmdArgs.push_back("-fencode-extended-block-signature"); - } - - // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. - // NOTE: This logic is duplicated in ToolChains.cpp. - bool ARC = isObjCAutoRefCount(Args); - if (ARC) { - getToolChain().CheckObjCARC(); - - CmdArgs.push_back("-fobjc-arc"); - - // FIXME: It seems like this entire block, and several around it should be - // wrapped in isObjC, but for now we just use it here as this is where it - // was being used previously. - if (types::isCXX(InputType) && types::isObjC(InputType)) { - if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); - else - CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); - } - - // Allow the user to enable full exceptions code emission. - // We define off for Objective-CC, on for Objective-C++. - if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, - options::OPT_fno_objc_arc_exceptions, - /*default*/ types::isCXX(InputType))) - CmdArgs.push_back("-fobjc-arc-exceptions"); - } - - // Silence warning for full exception code emission options when explicitly - // set to use no ARC. - if (Args.hasArg(options::OPT_fno_objc_arc)) { - Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions); - Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions); - } - - // -fobjc-infer-related-result-type is the default, except in the Objective-C - // rewriter. - if (rewriteKind != RK_None) - CmdArgs.push_back("-fno-objc-infer-related-result-type"); - - // Pass down -fobjc-weak or -fno-objc-weak if present. - if (types::isObjC(InputType)) { - auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak, - options::OPT_fno_objc_weak); - if (!WeakArg) { - // nothing to do - } else if (!objcRuntime.allowsWeak()) { - if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) - D.Diag(diag::err_objc_weak_unsupported); - } else { - WeakArg->render(Args, CmdArgs); - } - } + ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); + RenderObjCOptions(getToolChain(), D, RawTriple, Args, Runtime, + rewriteKind != RK_None, Input, CmdArgs); if (Args.hasFlag(options::OPT_fapplication_extension, options::OPT_fno_application_extension, false)) @@ -3890,12 +4187,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle GCC-style exception args. if (!C.getDriver().IsCLMode()) - addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, + addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, Runtime, CmdArgs); - if (Args.hasArg(options::OPT_fsjlj_exceptions) || - getToolChain().UseSjLjExceptions(Args)) - CmdArgs.push_back("-fsjlj-exceptions"); + // Handle exception personalities + Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, + options::OPT_fseh_exceptions, + options::OPT_fdwarf_exceptions); + if (A) { + const Option &Opt = A->getOption(); + if (Opt.matches(options::OPT_fsjlj_exceptions)) + CmdArgs.push_back("-fsjlj-exceptions"); + if (Opt.matches(options::OPT_fseh_exceptions)) + CmdArgs.push_back("-fseh-exceptions"); + if (Opt.matches(options::OPT_fdwarf_exceptions)) + CmdArgs.push_back("-fdwarf-exceptions"); + } else { + switch (getToolChain().GetExceptionModel(Args)) { + default: + break; + case llvm::ExceptionHandling::DwarfCFI: + CmdArgs.push_back("-fdwarf-exceptions"); + break; + case llvm::ExceptionHandling::SjLj: + CmdArgs.push_back("-fsjlj-exceptions"); + break; + case llvm::ExceptionHandling::WinEH: + CmdArgs.push_back("-fseh-exceptions"); + break; + } + } // C++ "sane" operator new. if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, @@ -3941,12 +4262,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_mno_constant_cfstrings)) CmdArgs.push_back("-fno-constant-cfstrings"); - // -fshort-wchar default varies depending on platform; only - // pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar, - options::OPT_fno_short_wchar)) - A->render(Args, CmdArgs); - // -fno-pascal-strings is default, only pass non-default. if (Args.hasFlag(options::OPT_fpascal_strings, options::OPT_fno_pascal_strings, false)) @@ -3971,7 +4286,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, MaxTypeAlignStr += A->getValue(); CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); } - } else if (getToolChain().getTriple().isOSDarwin()) { + } else if (RawTriple.isOSDarwin()) { if (!SkipMaxTypeAlign) { std::string MaxTypeAlignStr = "-fmax-type-align=16"; CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); @@ -3979,8 +4294,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // -fcommon is the default unless compiling kernel code or the target says so - bool NoCommonDefault = - KernelOrKext || isNoCommonDefault(getToolChain().getTriple()); + bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, !NoCommonDefault)) CmdArgs.push_back("-fno-common"); @@ -4013,113 +4327,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << value; } - bool CaretDefault = true; - bool ColumnDefault = true; - if (Arg *DiagArg = Args.getLastArg(options::OPT__SLASH_diagnostics_classic, - options::OPT__SLASH_diagnostics_column, - options::OPT__SLASH_diagnostics_caret)) { - switch (DiagArg->getOption().getID()) { - case options::OPT__SLASH_diagnostics_caret: - CaretDefault = true; - ColumnDefault = true; - break; - case options::OPT__SLASH_diagnostics_column: - CaretDefault = false; - ColumnDefault = true; - break; - case options::OPT__SLASH_diagnostics_classic: - CaretDefault = false; - ColumnDefault = false; - break; - } - } - - // -fcaret-diagnostics is default. - if (!Args.hasFlag(options::OPT_fcaret_diagnostics, - options::OPT_fno_caret_diagnostics, CaretDefault)) - CmdArgs.push_back("-fno-caret-diagnostics"); - - // -fdiagnostics-fixit-info is default, only pass non-default. - if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, - options::OPT_fno_diagnostics_fixit_info)) - CmdArgs.push_back("-fno-diagnostics-fixit-info"); - - // Enable -fdiagnostics-show-option by default. - if (Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option)) - CmdArgs.push_back("-fdiagnostics-show-option"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { - CmdArgs.push_back("-fdiagnostics-show-category"); - CmdArgs.push_back(A->getValue()); - } - - if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, - options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("-fdiagnostics-show-hotness"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { - std::string Opt = std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - - if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { - CmdArgs.push_back("-fdiagnostics-format"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg( - options::OPT_fdiagnostics_show_note_include_stack, - options::OPT_fno_diagnostics_show_note_include_stack)) { - if (A->getOption().matches( - options::OPT_fdiagnostics_show_note_include_stack)) - CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); - else - CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); - } - - // Color diagnostics are parsed by the driver directly from argv - // and later re-parsed to construct this job; claim any possible - // color diagnostic here to avoid warn_drv_unused_argument and - // diagnose bad OPT_fdiagnostics_color_EQ values. - for (Arg *A : Args) { - const Option &O = A->getOption(); - if (!O.matches(options::OPT_fcolor_diagnostics) && - !O.matches(options::OPT_fdiagnostics_color) && - !O.matches(options::OPT_fno_color_diagnostics) && - !O.matches(options::OPT_fno_diagnostics_color) && - !O.matches(options::OPT_fdiagnostics_color_EQ)) - continue; - if (O.matches(options::OPT_fdiagnostics_color_EQ)) { - StringRef Value(A->getValue()); - if (Value != "always" && Value != "never" && Value != "auto") - getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) - << ("-fdiagnostics-color=" + Value).str(); - } - A->claim(); - } - if (D.getDiags().getDiagnosticOptions().ShowColors) - CmdArgs.push_back("-fcolor-diagnostics"); - - if (Args.hasArg(options::OPT_fansi_escape_codes)) - CmdArgs.push_back("-fansi-escape-codes"); - - if (!Args.hasFlag(options::OPT_fshow_source_location, - options::OPT_fno_show_source_location)) - CmdArgs.push_back("-fno-show-source-location"); - - if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) - CmdArgs.push_back("-fdiagnostics-absolute-paths"); - - if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, - ColumnDefault)) - CmdArgs.push_back("-fno-show-column"); - - if (!Args.hasFlag(options::OPT_fspell_checking, - options::OPT_fno_spell_checking)) - CmdArgs.push_back("-fno-spell-checking"); + RenderDiagnosticsOptions(D, Args, CmdArgs); // -fno-asm-blocks is default. if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, @@ -4149,6 +4357,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_slp_vectorize, EnableSLPVec)) CmdArgs.push_back("-vectorize-slp"); + ParseMPreferVectorWidth(D, Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -4178,13 +4388,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_apple_pragma_pack, false)) CmdArgs.push_back("-fapple-pragma-pack"); - // le32-specific flags: - // -fno-math-builtin: clang should not convert math builtins to intrinsics - // by default. - if (getToolChain().getArch() == llvm::Triple::le32) { - CmdArgs.push_back("-fno-math-builtin"); - } - if (Args.hasFlag(options::OPT_fsave_optimization_record, options::OPT_fno_save_optimization_record, false)) { CmdArgs.push_back("-opt-record-file"); @@ -4194,10 +4397,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } else { SmallString<128> F; - if (Output.isFilename() && (Args.hasArg(options::OPT_c) || - Args.hasArg(options::OPT_S))) { - F = Output.getFilename(); - } else { + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } + + if (F.empty()) { // Use the input filename. F = llvm::sys::path::stem(Input.getBaseInput()); @@ -4219,20 +4425,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } -// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. -// -// FIXME: Now that PR4941 has been fixed this can be enabled. -#if 0 - if (getToolChain().getTriple().isOSDarwin() && - (getToolChain().getArch() == llvm::Triple::arm || - getToolChain().getArch() == llvm::Triple::thumb)) { - if (!Args.hasArg(options::OPT_fbuiltin_strcat)) - CmdArgs.push_back("-fno-builtin-strcat"); - if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) - CmdArgs.push_back("-fno-builtin-strcpy"); - } -#endif - bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, options::OPT_fno_rewrite_imports, false); if (RewriteImports) @@ -4244,7 +4436,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - (C.isForDiagnostics() && (RewriteImports || !HaveAnyModules))) + (C.isForDiagnostics() && (RewriteImports || !HaveModules))) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. @@ -4366,7 +4558,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_undef); - const char *Exec = getToolChain().getDriver().getClangProgramPath(); + const char *Exec = D.getClangProgramPath(); // Optionally embed the -cc1 level arguments into the debug info, for build // analysis. @@ -4392,18 +4584,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags)); } - // Add the split debug info name to the command lines here so we - // can propagate it to the backend. - bool SplitDwarf = SplitDwarfArg && getToolChain().getTriple().isOSLinux() && - (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || - isa<BackendJobAction>(JA)); - const char *SplitDwarfOut; - if (SplitDwarf) { - CmdArgs.push_back("-split-dwarf-file"); - SplitDwarfOut = SplitDebugName(Args, Input); - CmdArgs.push_back(SplitDwarfOut); - } - // Host-side cuda compilation receives device-side outputs as Inputs[1...]. // Include them with -fcuda-include-gpubinary. if (IsCuda && Inputs.size() > 1) @@ -4476,8 +4656,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. - if (SplitDwarf && Output.getType() == types::TY_Object) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut); + if (SplitDWARF && Output.getType() == types::TY_Object) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDWARFOut); if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) @@ -4752,7 +4932,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // Both /showIncludes and /E (and /EP) write to stdout. Allowing both // would produce interleaved output, so ignore /showIncludes in such cases. - if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) + if ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) || + (Args.hasArg(options::OPT__SLASH_P) && + Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E))) if (Arg *A = Args.getLastArg(options::OPT_show_includes)) A->render(Args, CmdArgs); @@ -4841,7 +5023,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // Parse the default calling convention options. if (Arg *CCArg = Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr, - options::OPT__SLASH_Gz, options::OPT__SLASH_Gv)) { + options::OPT__SLASH_Gz, options::OPT__SLASH_Gv, + options::OPT__SLASH_Gregcall)) { unsigned DCCOptId = CCArg->getOption().getID(); const char *DCCFlag = nullptr; bool ArchSupported = true; @@ -4862,6 +5045,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; DCCFlag = "-fdefault-calling-conv=vectorcall"; break; + case options::OPT__SLASH_Gregcall: + ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; + DCCFlag = "-fdefault-calling-conv=regcall"; + break; } // MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either. @@ -5176,12 +5363,15 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, if (I) Triples += ','; + // Find ToolChain for this input. Action::OffloadKind CurKind = Action::OFK_Host; const ToolChain *CurTC = &getToolChain(); const Action *CurDep = JA.getInputs()[I]; if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { + CurTC = nullptr; OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { + assert(CurTC == nullptr && "Expected one dependence!"); CurKind = A->getOffloadingDeviceKind(); CurTC = TC; }); @@ -5202,7 +5392,17 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, for (unsigned I = 0; I < Inputs.size(); ++I) { if (I) UB += ','; - UB += Inputs[I].getFilename(); + + // Find ToolChain for this input. + const ToolChain *CurTC = &getToolChain(); + if (const auto *OA = dyn_cast<OffloadAction>(JA.getInputs()[I])) { + CurTC = nullptr; + OA->doOnEachDependence([&](Action *, const ToolChain *TC, const char *) { + assert(CurTC == nullptr && "Expected one dependence!"); + CurTC = TC; + }); + } + UB += CurTC->getInputFilename(Inputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); @@ -5262,7 +5462,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( for (unsigned I = 0; I < Outputs.size(); ++I) { if (I) UB += ','; - UB += Outputs[I].getFilename(); + UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); CmdArgs.push_back("-unbundle"); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h index d53c3b4413c83..e23822b9c6781 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h @@ -42,6 +42,10 @@ private: const InputInfo &Output, const InputInfoList &Inputs) const; + void RenderTargetOptions(const llvm::Triple &EffectiveTriple, + const llvm::opt::ArgList &Args, bool KernelOrKext, + llvm::opt::ArgStringList &CmdArgs) const; + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddARMTargetArgs(const llvm::Triple &Triple, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp index 0f6c712c5d28e..cdf807f7f91ff 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -80,9 +80,9 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lcompiler_rt"); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp index 00bd60bc24bba..ab51a8c3cc901 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -320,6 +320,8 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, return TargetCPUName; } + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: @@ -376,8 +378,20 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. CmdArgs.push_back("-plugin"); - std::string Plugin = - ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so"; + +#if defined(LLVM_ON_WIN32) + const char *Suffix = ".dll"; +#elif defined(__APPLE__) + const char *Suffix = ".dylib"; +#else + const char *Suffix = ".so"; +#endif + + SmallString<1024> Plugin; + llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) + + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + + Suffix, + Plugin); CmdArgs.push_back(Args.MakeArgString(Plugin)); // Try to pass driver level flags relevant to LTO code generation down to @@ -440,6 +454,14 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); } + + // Need this flag to turn on new pass manager via Gold plugin. + if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, + options::OPT_fno_experimental_new_pass_manager, + /* Default */ false)) { + CmdArgs.push_back("-plugin-opt=new-pass-manager"); + } + } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, @@ -522,7 +544,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-lrt"); } CmdArgs.push_back("-lm"); - // There's no libdl on FreeBSD or RTEMS. + // There's no libdl on all OSes. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && TC.getTriple().getOS() != llvm::Triple::NetBSD && TC.getTriple().getOS() != llvm::Triple::RTEMS) @@ -538,26 +560,44 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl<StringRef> &RequiredSymbols) { const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Collect shared runtimes. - if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { - SharedRuntimes.push_back("asan"); + if (SanArgs.needsSharedRt()) { + if (SanArgs.needsAsanRt()) { + SharedRuntimes.push_back("asan"); + if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) + HelperStaticRuntimes.push_back("asan-preinit"); + } + if (SanArgs.needsUbsanRt()) { + if (SanArgs.requiresMinimalRuntime()) { + SharedRuntimes.push_back("ubsan_minimal"); + } else { + SharedRuntimes.push_back("ubsan_standalone"); + } + } + if (SanArgs.needsScudoRt()) + SharedRuntimes.push_back("scudo"); + if (SanArgs.needsHwasanRt()) + SharedRuntimes.push_back("hwasan"); } + // The stats_client library is also statically linked into DSOs. if (SanArgs.needsStatsRt()) StaticRuntimes.push_back("stats_client"); // Collect static runtimes. - if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) { - // Don't link static runtimes into DSOs or if compiling for Android. + if (Args.hasArg(options::OPT_shared) || SanArgs.needsSharedRt()) { + // Don't link static runtimes into DSOs or if -shared-libasan. return; } if (SanArgs.needsAsanRt()) { - if (SanArgs.needsSharedAsanRt()) { - HelperStaticRuntimes.push_back("asan-preinit"); - } else { - StaticRuntimes.push_back("asan"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("asan_cxx"); - } + StaticRuntimes.push_back("asan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("asan_cxx"); + } + + if (SanArgs.needsHwasanRt()) { + StaticRuntimes.push_back("hwasan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("hwasan_cxx"); } if (SanArgs.needsDfsanRt()) StaticRuntimes.push_back("dfsan"); @@ -574,9 +614,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("tsan_cxx"); } if (SanArgs.needsUbsanRt()) { - StaticRuntimes.push_back("ubsan_standalone"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); + if (SanArgs.requiresMinimalRuntime()) { + StaticRuntimes.push_back("ubsan_minimal"); + } else { + StaticRuntimes.push_back("ubsan_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } } if (SanArgs.needsSafeStackRt()) { NonWholeStaticRuntimes.push_back("safestack"); @@ -595,19 +639,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } if (SanArgs.needsEsanRt()) StaticRuntimes.push_back("esan"); + if (SanArgs.needsScudoRt()) { + StaticRuntimes.push_back("scudo"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_cxx"); + } } -static void addLibFuzzerRuntime(const ToolChain &TC, - const ArgList &Args, - ArgStringList &CmdArgs) { - StringRef ParentDir = llvm::sys::path::parent_path(TC.getDriver().InstalledDir); - SmallString<128> P(ParentDir); - llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); - CmdArgs.push_back(Args.MakeArgString(P)); - TC.AddCXXStdlibLibArgs(Args, CmdArgs); -} - - // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, @@ -617,10 +655,14 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); + // Inject libfuzzer dependencies. if (TC.getSanitizerArgs().needsFuzzer() && !Args.hasArg(options::OPT_shared)) { - addLibFuzzerRuntime(TC, Args, CmdArgs); + + addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true); + if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx)) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); } for (auto RT : SharedRuntimes) @@ -691,7 +733,8 @@ void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, ExtractArgs.push_back(Output.getFilename()); ExtractArgs.push_back(OutFile); - const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); + const char *Exec = + Args.MakeArgString(TC.GetProgramPath(CLANG_DEFAULT_OBJCOPY)); InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); // First extract the dwo sections. @@ -999,15 +1042,7 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, switch (RLT) { case ToolChain::RLT_CompilerRT: - switch (TC.getTriple().getOS()) { - default: - llvm_unreachable("unsupported OS"); - case llvm::Triple::Win32: - case llvm::Triple::Linux: - case llvm::Triple::Fuchsia: - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); - break; - } + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); break; case ToolChain::RLT_Libgcc: // Make sure libgcc is not used under MSVC environment by default @@ -1023,3 +1058,128 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, break; } } + +/// Add OpenMP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding each of the device images into the +/// host. The linker script also defines a few symbols required by the code +/// generation so that the images can be easily retrieved at runtime by the +/// offloading library. This should be used only in tool chains that support +/// linker scripts. +void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { + + // If this is not an OpenMP host toolchain, we don't need to do anything. + if (!JA.isHostOffloading(Action::OFK_OpenMP)) + return; + + // Create temporary linker script. Keep it if save-temps is enabled. + const char *LKS; + SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); + if (C.getDriver().isSaveTempsEnabled()) { + llvm::sys::path::replace_extension(Name, "lk"); + LKS = C.getArgs().MakeArgString(Name.c_str()); + } else { + llvm::sys::path::replace_extension(Name, ""); + Name = C.getDriver().GetTemporaryPath(Name, "lk"); + LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); + } + + // Add linker script option to the command. + CmdArgs.push_back("-T"); + CmdArgs.push_back(LKS); + + // Create a buffer to write the contents of the linker script. + std::string LksBuffer; + llvm::raw_string_ostream LksStream(LksBuffer); + + // Get the OpenMP offload tool chains so that we can extract the triple + // associated with each device input. + auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); + assert(OpenMPToolChains.first != OpenMPToolChains.second && + "No OpenMP toolchains??"); + + // Track the input file name and device triple in order to build the script, + // inserting binaries in the designated sections. + SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; + + // Add commands to embed target binaries. We ensure that each section and + // image is 16-byte aligned. This is not mandatory, but increases the + // likelihood of data to be aligned with a cache block in several main host + // machines. + LksStream << "/*\n"; + LksStream << " OpenMP Offload Linker Script\n"; + LksStream << " *** Automatically generated by Clang ***\n"; + LksStream << "*/\n"; + LksStream << "TARGET(binary)\n"; + auto DTC = OpenMPToolChains.first; + for (auto &II : Inputs) { + const Action *A = II.getAction(); + // Is this a device linking action? + if (A && isa<LinkJobAction>(A) && + A->isDeviceOffloading(Action::OFK_OpenMP)) { + assert(DTC != OpenMPToolChains.second && + "More device inputs than device toolchains??"); + InputBinaryInfo.push_back(std::make_pair( + DTC->second->getTriple().normalize(), II.getFilename())); + ++DTC; + LksStream << "INPUT(" << II.getFilename() << ")\n"; + } + } + + assert(DTC == OpenMPToolChains.second && + "Less device inputs than device toolchains??"); + + LksStream << "SECTIONS\n"; + LksStream << "{\n"; + + // Put each target binary into a separate section. + for (const auto &BI : InputBinaryInfo) { + LksStream << " .omp_offloading." << BI.first << " :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first + << " = .);\n"; + LksStream << " " << BI.second << "\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first + << " = .);\n"; + LksStream << " }\n"; + } + + // Add commands to define host entries begin and end. We use 1-byte subalign + // so that the linker does not add any padding and the elements in this + // section form an array. + LksStream << " .omp_offloading.entries :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " SUBALIGN(0x01)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; + LksStream << " *(.omp_offloading.entries)\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; + LksStream << " }\n"; + LksStream << "}\n"; + LksStream << "INSERT BEFORE .data\n"; + LksStream.flush(); + + // Dump the contents of the linker script if the user requested that. We + // support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) + llvm::errs() << LksBuffer; + + // If this is a dry run, do not create the linker script file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Lksf << LksBuffer; +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h index fdeb6669b0a8d..012f5b9f87ae9 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h @@ -39,6 +39,13 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); +void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const JobAction &JA); + const char *SplitDebugName(const llvm::opt::ArgList &Args, const InputInfo &Input); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp index 04b71c48cd4cd..5049033c41372 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -36,6 +36,7 @@ void tools::CrossWindows::Assembler::ConstructJob( llvm_unreachable("unsupported architecture"); case llvm::Triple::arm: case llvm::Triple::thumb: + case llvm::Triple::aarch64: break; case llvm::Triple::x86: CmdArgs.push_back("--32"); @@ -98,6 +99,9 @@ void tools::CrossWindows::Linker::ConstructJob( // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); break; + case llvm::Triple::aarch64: + CmdArgs.push_back("arm64pe"); + break; case llvm::Triple::x86: CmdArgs.push_back("i386pe"); EntryPoint.append("_"); @@ -111,6 +115,7 @@ void tools::CrossWindows::Linker::ConstructJob( switch (T.getArch()) { default: llvm_unreachable("unsupported architecture"); + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::x86_64: @@ -160,8 +165,7 @@ void tools::CrossWindows::Linker::ConstructJob( TC.AddFilePathLibArgs(Args, CmdArgs); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (TC.ShouldLinkCXXStdlib(Args)) { bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (StaticCXX) @@ -203,16 +207,7 @@ void tools::CrossWindows::Linker::ConstructJob( CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args) - : Generic_GCC(D, T, Args) { - if (D.CCCIsCXX() && GetCXXStdlibType(Args) == ToolChain::CST_Libstdcxx) { - const std::string &SysRoot = D.SysRoot; - - // libstdc++ resides in /usr/lib, but depends on libgcc which is placed in - // /usr/lib/gcc. - getFilePaths().push_back(SysRoot + "/usr/lib"); - getFilePaths().push_back(SysRoot + "/usr/lib/gcc"); - } -} + : Generic_GCC(D, T, Args) {} bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does @@ -261,43 +256,21 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, void CrossWindowsToolChain:: AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - const llvm::Triple &Triple = getTriple(); const std::string &SysRoot = getDriver().SysRoot; if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: + if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1"); - break; - - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++"); - addSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/c++/" + Triple.str()); - addSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/c++/backwards"); - } } void CrossWindowsToolChain:: AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: + if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) CC1Args.push_back("-lc++"); - break; - case ToolChain::CST_Libstdcxx: - CC1Args.push_back("-lstdc++"); - CC1Args.push_back("-lmingw32"); - CC1Args.push_back("-lmingwex"); - CC1Args.push_back("-lgcc"); - CC1Args.push_back("-lmoldname"); - CC1Args.push_back("-lmingw32"); - break; - } } clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp index 935a5a37ada52..bc4820797b2f4 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp @@ -9,8 +9,11 @@ #include "Cuda.h" #include "InputInfo.h" +#include "CommonArgs.h" #include "clang/Basic/Cuda.h" +#include "clang/Config/config.h" #include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Distro.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -47,6 +50,8 @@ static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { return CudaVersion::CUDA_75; if (Major == 8 && Minor == 0) return CudaVersion::CUDA_80; + if (Major == 9 && Minor == 0) + return CudaVersion::CUDA_90; return CudaVersion::UNKNOWN; } @@ -71,6 +76,11 @@ CudaInstallationDetector::CudaInstallationDetector( CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); for (const char *Ver : Versions) CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); + + if (Distro(D.getVFS()).IsDebian()) + // Special case for Debian to have nvidia-cuda-toolkit work + // out of the box. More info on http://bugs.debian.org/882505 + CudaPathCandidates.push_back(D.SysRoot + "/usr/lib/cuda"); } for (const auto &CudaPath : CudaPathCandidates) { @@ -83,8 +93,7 @@ CudaInstallationDetector::CudaInstallationDetector( LibDevicePath = InstallPath + "/nvvm/libdevice"; auto &FS = D.getVFS(); - if (!(FS.exists(IncludePath) && FS.exists(BinPath) && - FS.exists(LibDevicePath))) + if (!(FS.exists(IncludePath) && FS.exists(BinPath))) continue; // On Linux, we have both lib and lib64 directories, and we need to choose @@ -110,47 +119,64 @@ CudaInstallationDetector::CudaInstallationDetector( Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); } - std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef FilePath = LI->path(); - StringRef FileName = llvm::sys::path::filename(FilePath); - // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc - const StringRef LibDeviceName = "libdevice."; - if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) - continue; - StringRef GpuArch = FileName.slice( - LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); - LibDeviceMap[GpuArch] = FilePath.str(); - // Insert map entries for specifc devices with this compute - // capability. NVCC's choice of the libdevice library version is - // rather peculiar and depends on the CUDA version. - if (GpuArch == "compute_20") { - LibDeviceMap["sm_20"] = FilePath; - LibDeviceMap["sm_21"] = FilePath; - LibDeviceMap["sm_32"] = FilePath; - } else if (GpuArch == "compute_30") { - LibDeviceMap["sm_30"] = FilePath; - if (Version < CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; - } - LibDeviceMap["sm_60"] = FilePath; - LibDeviceMap["sm_61"] = FilePath; - LibDeviceMap["sm_62"] = FilePath; - } else if (GpuArch == "compute_35") { - LibDeviceMap["sm_35"] = FilePath; - LibDeviceMap["sm_37"] = FilePath; - } else if (GpuArch == "compute_50") { - if (Version >= CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; + if (Version == CudaVersion::CUDA_90) { + // CUDA-9 uses single libdevice file for all GPU variants. + std::string FilePath = LibDevicePath + "/libdevice.10.bc"; + if (FS.exists(FilePath)) { + for (const char *GpuArch : + {"sm_20", "sm_30", "sm_32", "sm_35", "sm_50", "sm_52", "sm_53", + "sm_60", "sm_61", "sm_62", "sm_70"}) + LibDeviceMap[GpuArch] = FilePath; + } + } else { + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + // Process all bitcode filenames that look like + // libdevice.compute_XX.YY.bc + const StringRef LibDeviceName = "libdevice."; + if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + continue; + StringRef GpuArch = FileName.slice( + LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); + LibDeviceMap[GpuArch] = FilePath.str(); + // Insert map entries for specifc devices with this compute + // capability. NVCC's choice of the libdevice library version is + // rather peculiar and depends on the CUDA version. + if (GpuArch == "compute_20") { + LibDeviceMap["sm_20"] = FilePath; + LibDeviceMap["sm_21"] = FilePath; + LibDeviceMap["sm_32"] = FilePath; + } else if (GpuArch == "compute_30") { + LibDeviceMap["sm_30"] = FilePath; + if (Version < CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } + LibDeviceMap["sm_60"] = FilePath; + LibDeviceMap["sm_61"] = FilePath; + LibDeviceMap["sm_62"] = FilePath; + } else if (GpuArch == "compute_35") { + LibDeviceMap["sm_35"] = FilePath; + LibDeviceMap["sm_37"] = FilePath; + } else if (GpuArch == "compute_50") { + if (Version >= CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } } } } + // Check that we have found at least one libdevice that we can link in if + // -nocudalib hasn't been specified. + if (LibDeviceMap.empty() && !Args.hasArg(options::OPT_nocudalib)) + continue; + IsValid = true; break; } @@ -185,15 +211,17 @@ void CudaInstallationDetector::AddCudaIncludeArgs( void CudaInstallationDetector::CheckCudaVersionSupportsArch( CudaArch Arch) const { if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || - ArchsWithVersionTooLowErrors.count(Arch) > 0) + ArchsWithBadVersion.count(Arch) > 0) return; - auto RequiredVersion = MinVersionForCudaArch(Arch); - if (Version < RequiredVersion) { - ArchsWithVersionTooLowErrors.insert(Arch); - D.Diag(diag::err_drv_cuda_version_too_low) - << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version) - << CudaVersionToString(RequiredVersion); + auto MinVersion = MinVersionForCudaArch(Arch); + auto MaxVersion = MaxVersionForCudaArch(Arch); + if (Version < MinVersion || Version > MaxVersion) { + ArchsWithBadVersion.insert(Arch); + D.Diag(diag::err_drv_cuda_version_unsupported) + << CudaArchToString(Arch) << CudaVersionToString(MinVersion) + << CudaVersionToString(MaxVersion) << InstallPath + << CudaVersionToString(Version); } } @@ -212,8 +240,18 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); + StringRef GPUArchName; + // If this is an OpenMP action we need to extract the device architecture + // from the -march=arch option. This option may come from -Xopenmp-target + // flag or the default value. + if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { + GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArchName.empty() && "Must have an architecture passed in."); + } else + GPUArchName = JA.getOffloadingArch(); + // Obtain architecture from the action. - CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); + CudaArch gpu_arch = StringToCudaArch(GPUArchName); assert(gpu_arch != CudaArch::UNKNOWN && "Device action expected to have an architecture."); @@ -262,16 +300,27 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-O0"); } + // Pass -v to ptxas if it was passed to the driver. + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + CmdArgs.push_back("--gpu-name"); CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); - CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); for (const auto& II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); + // In OpenMP we need to generate relocatable code. + if (JA.isOffloading(Action::OFK_OpenMP) && + Args.hasFlag(options::OPT_fopenmp_relocatable_target, + options::OPT_fnoopenmp_relocatable_target, + /*Default=*/ true)) + CmdArgs.push_back("-c"); + const char *Exec; if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) Exec = A->getValue(); @@ -324,16 +373,108 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } +void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = + static_cast<const toolchains::CudaToolChain &>(getToolChain()); + assert(TC.getTriple().isNVPTX() && "Wrong platform"); + + ArgStringList CmdArgs; + + // OpenMP uses nvlink to link cubin files. The result will be embedded in the + // host binary by the host linker. + assert(!JA.isHostOffloading(Action::OFK_OpenMP) && + "CUDA toolchain not expected for an OpenMP host device."); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else + assert(Output.isNothing() && "Invalid output."); + if (Args.hasArg(options::OPT_g_Flag)) + CmdArgs.push_back("-g"); + + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + + StringRef GPUArch = + Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); + + CmdArgs.push_back("-arch"); + CmdArgs.push_back(Args.MakeArgString(GPUArch)); + + // Add paths specified in LIBRARY_PATH environment variable as -L options. + addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + + // Add paths for the default clang library path. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); + CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); + + // Add linking against library implementing OpenMP calls on NVPTX target. + CmdArgs.push_back("-lomptarget-nvptx"); + + for (const auto &II : Inputs) { + if (II.getType() == types::TY_LLVM_IR || + II.getType() == types::TY_LTO_IR || + II.getType() == types::TY_LTO_BC || + II.getType() == types::TY_LLVM_BC) { + C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + continue; + } + + // Currently, we only pass the input files to the linker, we do not pass + // any libraries that may be valid only for the host. + if (!II.isFilename()) + continue; + + const char *CubinF = C.addTempFile( + C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + + CmdArgs.push_back(CubinF); + } + + AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + /// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, /// which isn't properly a linker but nonetheless performs the step of stitching /// together object files from the assembler into a single blob. CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args) + const ToolChain &HostTC, const ArgList &Args, + const Action::OffloadKind OK) : ToolChain(D, Triple, Args), HostTC(HostTC), - CudaInstallation(D, HostTC.getTriple(), Args) { + CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { if (CudaInstallation.isValid()) getProgramPaths().push_back(CudaInstallation.getBinPath()); + // Lookup binaries into the driver directory, this is used to + // discover the clang-offload-bundler executable. + getProgramPaths().push_back(getDriver().Dir); +} + +std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { + // Only object files are changed, for example assembly files keep their .s + // extensions. CUDA also continues to use .o as they don't use nvlink but + // fatbinary. + if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object)) + return ToolChain::getInputFilename(Input); + + // Replace extension for object files with cubin because nvlink relies on + // these particular file names. + SmallString<256> Filename(ToolChain::getInputFilename(Input)); + llvm::sys::path::replace_extension(Filename, "cubin"); + return Filename.str(); } void CudaToolChain::addClangTargetOptions( @@ -358,14 +499,18 @@ void CudaToolChain::addClangTargetOptions( if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) CC1Args.push_back("-fcuda-approx-transcendentals"); - - if (DriverArgs.hasArg(options::OPT_nocudalib)) - return; } + if (DriverArgs.hasArg(options::OPT_nocudalib)) + return; + std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); if (LibDeviceFile.empty()) { + if (DeviceOffloadingKind == Action::OFK_OpenMP && + DriverArgs.hasArg(options::OPT_S)) + return; + getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; return; } @@ -373,11 +518,17 @@ void CudaToolChain::addClangTargetOptions( CC1Args.push_back("-mlink-cuda-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); - // Libdevice in CUDA-7.0 requires PTX version that's more recent - // than LLVM defaults to. Use PTX4.2 which is the PTX version that - // came with CUDA-7.0. - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+ptx42"); + if (CudaInstallation.version() >= CudaVersion::CUDA_90) { + // CUDA-9 uses new instructions that are only available in PTX6.0 + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx60"); + } else { + // Libdevice in CUDA-7.0 requires PTX version that's more recent + // than LLVM defaults to. Use PTX4.2 which is the PTX version that + // came with CUDA-7.0. + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx42"); + } } void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, @@ -405,11 +556,11 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // For OpenMP device offloading, append derived arguments. Make sure // flags are not duplicated. - // TODO: Append the compute capability. + // Also append the compute capability. if (DeviceOffloadKind == Action::OFK_OpenMP) { - for (Arg *A : Args){ + for (Arg *A : Args) { bool IsDuplicate = false; - for (Arg *DALArg : *DAL){ + for (Arg *DALArg : *DAL) { if (A == DALArg) { IsDuplicate = true; break; @@ -418,6 +569,12 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!IsDuplicate) DAL->append(A); } + + StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); + if (Arch.empty()) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + CLANG_OPENMP_NVPTX_DEFAULT_ARCH); + return DAL; } @@ -467,6 +624,8 @@ Tool *CudaToolChain::buildAssembler() const { } Tool *CudaToolChain::buildLinker() const { + if (OK == Action::OFK_OpenMP) + return new tools::NVPTX::OpenMPLinker(*this); return new tools::NVPTX::Linker(*this); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h index e66fc23d82f35..3d08cec1643ee 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h @@ -40,7 +40,7 @@ private: // CUDA architectures for which we have raised an error in // CheckCudaVersionSupportsArch. - mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; + mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion; public: CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, @@ -112,6 +112,20 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { + public: + OpenMPLinker(const ToolChain &TC) + : Tool("NVPTX::OpenMPLinker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8, + "--options-file") {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + } // end namespace NVPTX } // end namespace tools @@ -120,12 +134,15 @@ namespace toolchains { class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { public: CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args); + const ToolChain &HostTC, const llvm::opt::ArgList &Args, + const Action::OffloadKind OK); - virtual const llvm::Triple *getAuxTriple() const override { + const llvm::Triple *getAuxTriple() const override { return &HostTC.getTriple(); } + std::string getInputFilename(const InputInfo &Input) const override; + llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; @@ -141,7 +158,7 @@ public: bool isPIEDefault() const override { return false; } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } - bool SupportsObjCGC() const override { return false; } + bool IsMathErrnoDefault() const override { return false; } void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -169,6 +186,9 @@ public: protected: Tool *buildAssembler() const override; // ptxas Tool *buildLinker() const override; // fatbinary (ok, not really a linker) + +private: + const Action::OffloadKind OK; }; } // end namespace toolchains diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp index 32103a6120d40..28efa86538edf 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp @@ -10,6 +10,7 @@ #include "Darwin.h" #include "Arch/ARM.h" #include "CommonArgs.h" +#include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Driver/Compilation.h" @@ -67,14 +68,14 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); - unsigned ArchKind = llvm::ARM::parseArch(Str); + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str); T.setArch(Arch); if (Str == "x86_64h") T.setArchName(Str); - else if (ArchKind == llvm::ARM::AK_ARMV6M || - ArchKind == llvm::ARM::AK_ARMV7M || - ArchKind == llvm::ARM::AK_ARMV7EM) { + else if (ArchKind == llvm::ARM::ArchKind::ARMV6M || + ArchKind == llvm::ARM::ArchKind::ARMV7M || + ArchKind == llvm::ARM::ArchKind::ARMV7EM) { T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } @@ -493,7 +494,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.safestack_osx.a", - /*AlwaysLink=*/true); + toolchains::Darwin::RLO_AlwaysLink); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -548,10 +549,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism))); } + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX()) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - // link_ssp spec is empty. // Let the tool chain choose which runtime library to link. @@ -739,8 +739,8 @@ static const char *ArmMachOArchName(StringRef Arch) { } static const char *ArmMachOArchNameCPU(StringRef CPU) { - unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); - if (ArchKind == llvm::ARM::AK_INVALID) + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); + if (ArchKind == llvm::ARM::ArchKind::INVALID) return nullptr; StringRef Arch = llvm::ARM::getArchName(ArchKind); @@ -897,10 +897,11 @@ unsigned DarwinClang::GetDefaultDwarfVersion() const { } void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink, - bool IsEmbedded, bool AddRPath) const { + StringRef DarwinLibName, + RuntimeLinkOptions Opts) const { SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin"); + llvm::sys::path::append( + Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin"); SmallString<128> P(Dir); llvm::sys::path::append(P, DarwinLibName); @@ -908,14 +909,19 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). - if (AlwaysLink || getVFS().exists(P)) - CmdArgs.push_back(Args.MakeArgString(P)); + if ((Opts & RLO_AlwaysLink) || getVFS().exists(P)) { + const char *LibArg = Args.MakeArgString(P); + if (Opts & RLO_FirstLink) + CmdArgs.insert(CmdArgs.begin(), LibArg); + else + CmdArgs.push_back(LibArg); + } // Adding the rpaths might negatively interact when other rpaths are involved, // so we should make sure we add the rpaths last, after all user-specified // rpaths. This is currently true from this place, but we need to be // careful if this function is ever called before user's rpaths are emitted. - if (AddRPath) { + if (Opts & RLO_AddRPath) { assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); // Add @executable_path to rpath to support having the dylib copied with @@ -930,30 +936,15 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, } } -void MachO::AddFuzzerLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - - // Go up one directory from Clang to find the libfuzzer archive file. - StringRef ParentDir = llvm::sys::path::parent_path(getDriver().InstalledDir); - SmallString<128> P(ParentDir); - llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); - CmdArgs.push_back(Args.MakeArgString(P)); - - // Libfuzzer is written in C++ and requires libcxx. - AddCXXStdlibLibArgs(Args, CmdArgs); -} - StringRef Darwin::getPlatformFamily() const { switch (TargetPlatform) { case DarwinPlatformKind::MacOS: return "MacOSX"; case DarwinPlatformKind::IPhoneOS: - case DarwinPlatformKind::IPhoneOSSimulator: return "iPhone"; case DarwinPlatformKind::TvOS: - case DarwinPlatformKind::TvOSSimulator: return "AppleTV"; case DarwinPlatformKind::WatchOS: - case DarwinPlatformKind::WatchOSSimulator: return "Watch"; } llvm_unreachable("Unsupported platform"); @@ -977,39 +968,65 @@ StringRef Darwin::getOSLibraryNameSuffix() const { case DarwinPlatformKind::MacOS: return "osx"; case DarwinPlatformKind::IPhoneOS: - return "ios"; - case DarwinPlatformKind::IPhoneOSSimulator: - return "iossim"; + return TargetEnvironment == NativeEnvironment ? "ios" : "iossim"; case DarwinPlatformKind::TvOS: - return "tvos"; - case DarwinPlatformKind::TvOSSimulator: - return "tvossim"; + return TargetEnvironment == NativeEnvironment ? "tvos" : "tvossim"; case DarwinPlatformKind::WatchOS: - return "watchos"; - case DarwinPlatformKind::WatchOSSimulator: - return "watchossim"; + return TargetEnvironment == NativeEnvironment ? "watchos" : "watchossim"; } llvm_unreachable("Unsupported platform"); } +/// Check if the link command contains a symbol export directive. +static bool hasExportSymbolDirective(const ArgList &Args) { + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT_Wl_COMMA) && + !A->getOption().matches(options::OPT_Xlinker)) + continue; + if (A->containsValue("-exported_symbols_list") || + A->containsValue("-exported_symbol")) + return true; + } + return false; +} + +/// Add an export directive for \p Symbol to the link command. +static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) { + CmdArgs.push_back("-exported_symbol"); + CmdArgs.push_back(Symbol); +} + void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; - AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") + - getOSLibraryNameSuffix() + ".a").str(), - /*AlwaysLink*/ true); + AddLinkRuntimeLib( + Args, CmdArgs, + (Twine("libclang_rt.profile_") + getOSLibraryNameSuffix() + ".a").str(), + RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); + + // If we have a symbol export directive and we're linking in the profile + // runtime, automatically export symbols necessary to implement some of the + // runtime's functionality. + if (hasExportSymbolDirective(Args)) { + addExportedSymbol(CmdArgs, "_VPMergeHook"); + addExportedSymbol(CmdArgs, "___llvm_profile_filename"); + addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); + addExportedSymbol(CmdArgs, "_lprofCurFilename"); + } } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, ArgStringList &CmdArgs, - StringRef Sanitizer) const { - AddLinkRuntimeLib( - Args, CmdArgs, - (Twine("libclang_rt.") + Sanitizer + "_" + - getOSLibraryNameSuffix() + "_dynamic.dylib").str(), - /*AlwaysLink*/ true, /*IsEmbedded*/ false, - /*AddRPath*/ true); + StringRef Sanitizer, + bool Shared) const { + auto RLO = RuntimeLinkOptions(RLO_AlwaysLink | (Shared ? RLO_AddRPath : 0U)); + AddLinkRuntimeLib(Args, CmdArgs, + (Twine("libclang_rt.") + Sanitizer + "_" + + getOSLibraryNameSuffix() + + (Shared ? "_dynamic.dylib" : ".a")) + .str(), + RLO); } ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( @@ -1050,16 +1067,23 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, if (Sanitize.needsLsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); + AddLinkSanitizerLibArgs(Args, CmdArgs, + Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" + : "ubsan", + Sanitize.needsSharedRt()); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) - AddFuzzerLinkArgs(Args, CmdArgs); + if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + + // Libfuzzer is written in C++ and requires libcxx. + AddCXXStdlibLibArgs(Args, CmdArgs); + } if (Sanitize.needsStatsRt()) { StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.stats_client_") + OS + ".a").str(), - /*AlwaysLink=*/true); + RLO_AlwaysLink); AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); } if (Sanitize.needsEsanRt()) @@ -1139,28 +1163,132 @@ static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { return MacOSSDKVersion; } -void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { - const OptTable &Opts = getDriver().getOpts(); +namespace { - // Support allowing the SDKROOT environment variable used by xcrun and other - // Xcode tools to define the default sysroot, by making it the default for - // isysroot. - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - // Warn if the path does not exist. - if (!getVFS().exists(A->getValue())) - getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); - } else { - if (char *env = ::getenv("SDKROOT")) { - // We only use this value as the default if it is an absolute path, - // exists, and it is not the root path. - if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && - StringRef(env) != "/") { - Args.append(Args.MakeSeparateArg( - nullptr, Opts.getOption(options::OPT_isysroot), env)); - } +/// The Darwin OS that was selected or inferred from arguments / environment. +struct DarwinPlatform { + enum SourceKind { + /// The OS was specified using the -target argument. + TargetArg, + /// The OS was specified using the -m<os>-version-min argument. + OSVersionArg, + /// The OS was specified using the OS_DEPLOYMENT_TARGET environment. + DeploymentTargetEnv, + /// The OS was inferred from the SDK. + InferredFromSDK, + /// The OS was inferred from the -arch. + InferredFromArch + }; + + using DarwinPlatformKind = Darwin::DarwinPlatformKind; + + DarwinPlatformKind getPlatform() const { return Platform; } + + StringRef getOSVersion() const { + if (Kind == OSVersionArg) + return Argument->getValue(); + return OSVersion; + } + + /// Returns true if the target OS was explicitly specified. + bool isExplicitlySpecified() const { return Kind <= DeploymentTargetEnv; } + + /// Adds the -m<os>-version-min argument to the compiler invocation. + void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { + if (Argument) + return; + assert(Kind != TargetArg && Kind != OSVersionArg && "Invalid kind"); + options::ID Opt; + switch (Platform) { + case DarwinPlatformKind::MacOS: + Opt = options::OPT_mmacosx_version_min_EQ; + break; + case DarwinPlatformKind::IPhoneOS: + Opt = options::OPT_miphoneos_version_min_EQ; + break; + case DarwinPlatformKind::TvOS: + Opt = options::OPT_mtvos_version_min_EQ; + break; + case DarwinPlatformKind::WatchOS: + Opt = options::OPT_mwatchos_version_min_EQ; + break; + } + Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); + Args.append(Argument); + } + + /// Returns the OS version with the argument / environment variable that + /// specified it. + std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { + switch (Kind) { + case TargetArg: + case OSVersionArg: + case InferredFromSDK: + case InferredFromArch: + assert(Argument && "OS version argument not yet inferred"); + return Argument->getAsString(Args); + case DeploymentTargetEnv: + return (llvm::Twine(EnvVarName) + "=" + OSVersion).str(); + } + llvm_unreachable("Unsupported Darwin Source Kind"); + } + + static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, + Arg *A) { + return DarwinPlatform(OSVersionArg, Platform, A); + } + static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform, + StringRef EnvVarName, + StringRef Value) { + DarwinPlatform Result(DeploymentTargetEnv, Platform, Value); + Result.EnvVarName = EnvVarName; + return Result; + } + static DarwinPlatform createFromSDK(DarwinPlatformKind Platform, + StringRef Value) { + return DarwinPlatform(InferredFromSDK, Platform, Value); + } + static DarwinPlatform createFromArch(llvm::Triple::OSType OS, + StringRef Value) { + DarwinPlatformKind Platform; + switch (OS) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + Platform = DarwinPlatformKind::MacOS; + break; + case llvm::Triple::IOS: + Platform = DarwinPlatformKind::IPhoneOS; + break; + case llvm::Triple::TvOS: + Platform = DarwinPlatformKind::TvOS; + break; + case llvm::Triple::WatchOS: + Platform = DarwinPlatformKind::WatchOS; + break; + default: + llvm_unreachable("Unable to infer Darwin variant"); } + return DarwinPlatform(InferredFromArch, Platform, Value); } +private: + DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg *Argument) + : Kind(Kind), Platform(Platform), Argument(Argument) {} + DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef Value) + : Kind(Kind), Platform(Platform), OSVersion(Value), Argument(nullptr) {} + + SourceKind Kind; + DarwinPlatformKind Platform; + std::string OSVersion; + Arg *Argument; + StringRef EnvVarName; +}; + +/// Returns the deployment target that's specified using the -m<os>-version-min +/// argument. +Optional<DarwinPlatform> +getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, + const Driver &TheDriver) { Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ, options::OPT_mios_simulator_version_min_EQ); @@ -1170,232 +1298,249 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ, options::OPT_mwatchos_simulator_version_min_EQ); + if (OSXVersion) { + if (iOSVersion || TvOSVersion || WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << OSXVersion->getAsString(Args) + << (iOSVersion ? iOSVersion + : TvOSVersion ? TvOSVersion : WatchOSVersion) + ->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); + } else if (iOSVersion) { + if (TvOSVersion || WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << iOSVersion->getAsString(Args) + << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion); + } else if (TvOSVersion) { + if (WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << TvOSVersion->getAsString(Args) + << WatchOSVersion->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion); + } else if (WatchOSVersion) + return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion); + return None; +} - unsigned Major, Minor, Micro; - bool HadExtra; +/// Returns the deployment target that's specified using the +/// OS_DEPLOYMENT_TARGET environment variable. +Optional<DarwinPlatform> +getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, + const llvm::Triple &Triple) { + std::string Targets[Darwin::LastDarwinPlatform + 1]; + const char *EnvVars[] = { + "MACOSX_DEPLOYMENT_TARGET", + "IPHONEOS_DEPLOYMENT_TARGET", + "TVOS_DEPLOYMENT_TARGET", + "WATCHOS_DEPLOYMENT_TARGET", + }; + static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1, + "Missing platform"); + for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) { + if (char *Env = ::getenv(I.value())) + Targets[I.index()] = Env; + } - // The iOS deployment target that is explicitly specified via a command line - // option or an environment variable. - std::string ExplicitIOSDeploymentTargetStr; + // Do not allow conflicts with the watchOS target. + if (!Targets[Darwin::WatchOS].empty() && + (!Targets[Darwin::IPhoneOS].empty() || !Targets[Darwin::TvOS].empty())) { + TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) + << "WATCHOS_DEPLOYMENT_TARGET" + << (!Targets[Darwin::IPhoneOS].empty() ? "IPHONEOS_DEPLOYMENT_TARGET" + : "TVOS_DEPLOYMENT_TARGET"); + } - if (iOSVersion) - ExplicitIOSDeploymentTargetStr = iOSVersion->getAsString(Args); + // Do not allow conflicts with the tvOS target. + if (!Targets[Darwin::TvOS].empty() && !Targets[Darwin::IPhoneOS].empty()) { + TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) + << "TVOS_DEPLOYMENT_TARGET" + << "IPHONEOS_DEPLOYMENT_TARGET"; + } - // Add a macro to differentiate between m(iphone|tv|watch)os-version-min=X.Y and - // -m(iphone|tv|watch)simulator-version-min=X.Y. - if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ) || - Args.hasArg(options::OPT_mtvos_simulator_version_min_EQ) || - Args.hasArg(options::OPT_mwatchos_simulator_version_min_EQ)) - Args.append(Args.MakeSeparateArg(nullptr, Opts.getOption(options::OPT_D), - " __APPLE_EMBEDDED_SIMULATOR__=1")); + // Allow conflicts among OSX and iOS for historical reasons, but choose the + // default platform. + if (!Targets[Darwin::MacOS].empty() && + (!Targets[Darwin::IPhoneOS].empty() || + !Targets[Darwin::WatchOS].empty() || !Targets[Darwin::TvOS].empty())) { + if (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::aarch64 || + Triple.getArch() == llvm::Triple::thumb) + Targets[Darwin::MacOS] = ""; + else + Targets[Darwin::IPhoneOS] = Targets[Darwin::WatchOS] = + Targets[Darwin::TvOS] = ""; + } - if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << OSXVersion->getAsString(Args) - << (iOSVersion ? iOSVersion : - TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); - iOSVersion = TvOSVersion = WatchOSVersion = nullptr; - } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << iOSVersion->getAsString(Args) - << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); - TvOSVersion = WatchOSVersion = nullptr; - } else if (TvOSVersion && WatchOSVersion) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << TvOSVersion->getAsString(Args) - << WatchOSVersion->getAsString(Args); - WatchOSVersion = nullptr; - } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) { - // If no deployment target was specified on the command line, check for - // environment defines. - std::string OSXTarget; - std::string iOSTarget; - std::string TvOSTarget; - std::string WatchOSTarget; + for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) { + if (!Target.value().empty()) + return DarwinPlatform::createDeploymentTargetEnv( + (Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()], + Target.value()); + } + return None; +} - if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) - OSXTarget = env; - if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) - iOSTarget = env; - if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET")) - TvOSTarget = env; - if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET")) - WatchOSTarget = env; +/// Tries to infer the deployment target from the SDK specified by -isysroot +/// (or SDKROOT). +Optional<DarwinPlatform> inferDeploymentTargetFromSDK(DerivedArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_isysroot); + if (!A) + return None; + StringRef isysroot = A->getValue(); + StringRef SDK = Darwin::getSDKName(isysroot); + if (!SDK.size()) + return None; + // Slice the version number out. + // Version number is between the first and the last number. + size_t StartVer = SDK.find_first_of("0123456789"); + size_t EndVer = SDK.find_last_of("0123456789"); + if (StartVer != StringRef::npos && EndVer > StartVer) { + StringRef Version = SDK.slice(StartVer, EndVer + 1); + if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) + return DarwinPlatform::createFromSDK(Darwin::IPhoneOS, Version); + else if (SDK.startswith("MacOSX")) + return DarwinPlatform::createFromSDK(Darwin::MacOS, + getSystemOrSDKMacOSVersion(Version)); + else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) + return DarwinPlatform::createFromSDK(Darwin::WatchOS, Version); + else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) + return DarwinPlatform::createFromSDK(Darwin::TvOS, Version); + } + return None; +} - if (!iOSTarget.empty()) - ExplicitIOSDeploymentTargetStr = - std::string("IPHONEOS_DEPLOYMENT_TARGET=") + iOSTarget; +std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, + const Driver &TheDriver) { + unsigned Major, Minor, Micro; + switch (OS) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + if (!Triple.getMacOSXVersion(Major, Minor, Micro)) + TheDriver.Diag(diag::err_drv_invalid_darwin_version) + << Triple.getOSName(); + break; + case llvm::Triple::IOS: + Triple.getiOSVersion(Major, Minor, Micro); + break; + case llvm::Triple::TvOS: + Triple.getOSVersion(Major, Minor, Micro); + break; + case llvm::Triple::WatchOS: + Triple.getWatchOSVersion(Major, Minor, Micro); + break; + default: + llvm_unreachable("Unexpected OS type"); + break; + } - // If there is no command-line argument to specify the Target version and - // no environment variable defined, see if we can set the default based - // on -isysroot. - if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() && - TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) { - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - StringRef isysroot = A->getValue(); - StringRef SDK = getSDKName(isysroot); - if (SDK.size() > 0) { - // Slice the version number out. - // Version number is between the first and the last number. - size_t StartVer = SDK.find_first_of("0123456789"); - size_t EndVer = SDK.find_last_of("0123456789"); - if (StartVer != StringRef::npos && EndVer > StartVer) { - StringRef Version = SDK.slice(StartVer, EndVer + 1); - if (SDK.startswith("iPhoneOS") || - SDK.startswith("iPhoneSimulator")) - iOSTarget = Version; - else if (SDK.startswith("MacOSX")) - OSXTarget = getSystemOrSDKMacOSVersion(Version); - else if (SDK.startswith("WatchOS") || - SDK.startswith("WatchSimulator")) - WatchOSTarget = Version; - else if (SDK.startswith("AppleTVOS") || - SDK.startswith("AppleTVSimulator")) - TvOSTarget = Version; - } - } - } - } + std::string OSVersion; + llvm::raw_string_ostream(OSVersion) << Major << '.' << Minor << '.' << Micro; + return OSVersion; +} - // If no OS targets have been specified, try to guess platform from -target - // or arch name and compute the version from the triple. - if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && - WatchOSTarget.empty()) { - llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; +/// Tries to infer the target OS from the -arch. +Optional<DarwinPlatform> +inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, + const llvm::Triple &Triple, + const Driver &TheDriver) { + llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; - // Set the OSTy based on -target if -arch isn't present. - if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) { - OSTy = getTriple().getOS(); - } else { - StringRef MachOArchName = getMachOArchName(Args); - if (MachOArchName == "armv7" || MachOArchName == "armv7s" || - MachOArchName == "arm64") - OSTy = llvm::Triple::IOS; - else if (MachOArchName == "armv7k") - OSTy = llvm::Triple::WatchOS; - else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && - MachOArchName != "armv7em") - OSTy = llvm::Triple::MacOSX; - } + // Set the OSTy based on -target if -arch isn't present. + if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) { + OSTy = Triple.getOS(); + } else { + StringRef MachOArchName = Toolchain.getMachOArchName(Args); + if (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "arm64") + OSTy = llvm::Triple::IOS; + else if (MachOArchName == "armv7k") + OSTy = llvm::Triple::WatchOS; + else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && + MachOArchName != "armv7em") + OSTy = llvm::Triple::MacOSX; + } + if (OSTy == llvm::Triple::UnknownOS) + return None; + return DarwinPlatform::createFromArch(OSTy, + getOSVersion(OSTy, Triple, TheDriver)); +} - if (OSTy != llvm::Triple::UnknownOS) { - unsigned Major, Minor, Micro; - std::string *OSTarget; +} // namespace - switch (OSTy) { - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: - if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) - getDriver().Diag(diag::err_drv_invalid_darwin_version) - << getTriple().getOSName(); - OSTarget = &OSXTarget; - break; - case llvm::Triple::IOS: - getTriple().getiOSVersion(Major, Minor, Micro); - OSTarget = &iOSTarget; - break; - case llvm::Triple::TvOS: - getTriple().getOSVersion(Major, Minor, Micro); - OSTarget = &TvOSTarget; - break; - case llvm::Triple::WatchOS: - getTriple().getWatchOSVersion(Major, Minor, Micro); - OSTarget = &WatchOSTarget; - break; - default: - llvm_unreachable("Unexpected OS type"); - break; - } +void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { + const OptTable &Opts = getDriver().getOpts(); - llvm::raw_string_ostream(*OSTarget) << Major << '.' << Minor << '.' - << Micro; + // Support allowing the SDKROOT environment variable used by xcrun and other + // Xcode tools to define the default sysroot, by making it the default for + // isysroot. + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + // Warn if the path does not exist. + if (!getVFS().exists(A->getValue())) + getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); + } else { + if (char *env = ::getenv("SDKROOT")) { + // We only use this value as the default if it is an absolute path, + // exists, and it is not the root path. + if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && + StringRef(env) != "/") { + Args.append(Args.MakeSeparateArg( + nullptr, Opts.getOption(options::OPT_isysroot), env)); } } - - // Do not allow conflicts with the watchOS target. - if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) { - getDriver().Diag(diag::err_drv_conflicting_deployment_targets) - << "WATCHOS_DEPLOYMENT_TARGET" - << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" : - "TVOS_DEPLOYMENT_TARGET"); - } - - // Do not allow conflicts with the tvOS target. - if (!TvOSTarget.empty() && !iOSTarget.empty()) { - getDriver().Diag(diag::err_drv_conflicting_deployment_targets) - << "TVOS_DEPLOYMENT_TARGET" - << "IPHONEOS_DEPLOYMENT_TARGET"; - } - - // Allow conflicts among OSX and iOS for historical reasons, but choose the - // default platform. - if (!OSXTarget.empty() && (!iOSTarget.empty() || - !WatchOSTarget.empty() || - !TvOSTarget.empty())) { - if (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::thumb) - OSXTarget = ""; - else - iOSTarget = WatchOSTarget = TvOSTarget = ""; - } - - if (!OSXTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget); - Args.append(OSXVersion); - } else if (!iOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); - Args.append(iOSVersion); - } else if (!TvOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ); - TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget); - Args.append(TvOSVersion); - } else if (!WatchOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ); - WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget); - Args.append(WatchOSVersion); - } } - DarwinPlatformKind Platform; - if (OSXVersion) - Platform = MacOS; - else if (iOSVersion) - Platform = IPhoneOS; - else if (TvOSVersion) - Platform = TvOS; - else if (WatchOSVersion) - Platform = WatchOS; - else - llvm_unreachable("Unable to infer Darwin variant"); + // The OS target can be specified using the -m<os>version-min argument. + Optional<DarwinPlatform> OSTarget = + getDeploymentTargetFromOSVersionArg(Args, getDriver()); + // If no deployment target was specified on the command line, check for + // environment defines. + if (!OSTarget) + OSTarget = + getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); + // If there is no command-line argument to specify the Target version and + // no environment variable defined, see if we can set the default based + // on -isysroot. + if (!OSTarget) + OSTarget = inferDeploymentTargetFromSDK(Args); + // If no OS targets have been specified, try to guess platform from -target + // or arch name and compute the version from the triple. + if (!OSTarget) + OSTarget = + inferDeploymentTargetFromArch(Args, *this, getTriple(), getDriver()); + + assert(OSTarget && "Unable to infer Darwin variant"); + OSTarget->addOSVersionMinArgument(Args, Opts); + DarwinPlatformKind Platform = OSTarget->getPlatform(); + unsigned Major, Minor, Micro; + bool HadExtra; // Set the tool chain target information. if (Platform == MacOS) { - assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && - "Unknown target platform!"); - if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, - HadExtra) || + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << OSXVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else if (Platform == IPhoneOS) { - assert(iOSVersion && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, - HadExtra) || + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << iOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); + ; // For 32-bit targets, the deployment target for iOS has to be earlier than // iOS 11. if (getTriple().isArch32Bit() && Major >= 11) { // If the deployment target is explicitly specified, print a diagnostic. - if (!ExplicitIOSDeploymentTargetStr.empty()) { + if (OSTarget->isExplicitlySpecified()) { getDriver().Diag(diag::warn_invalid_ios_deployment_target) - << ExplicitIOSDeploymentTargetStr; - // Otherwise, set it to 10.99.99. + << OSTarget->getAsString(Args, Opts); + // Otherwise, set it to 10.99.99. } else { Major = 10; Minor = 99; @@ -1403,32 +1548,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } } else if (Platform == TvOS) { - if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 100 || Minor >= 100 || Micro >= 100) + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << TvOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else if (Platform == WatchOS) { - if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 10 || Minor >= 100 || Micro >= 100) + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << WatchOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else llvm_unreachable("unknown kind of Darwin platform"); + DarwinEnvironmentKind Environment = NativeEnvironment; // Recognize iOS targets with an x86 architecture as the iOS simulator. - if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = IPhoneOSSimulator; - if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = TvOSSimulator; - if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = WatchOSSimulator; + if (Platform != MacOS && (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64)) + Environment = Simulator; - setTarget(Platform, Major, Minor, Micro); + setTarget(Platform, Environment, Major, Minor, Micro); if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef SDK = getSDKName(A->getValue()); @@ -1741,23 +1881,28 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, : "soft"; CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; - AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); + AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, RLO_IsEmbedded); } bool Darwin::isAlignedAllocationUnavailable() const { + llvm::Triple::OSType OS; + switch (TargetPlatform) { case MacOS: // Earlier than 10.13. - return TargetVersion < VersionTuple(10U, 13U, 0U); + OS = llvm::Triple::MacOSX; + break; case IPhoneOS: - case IPhoneOSSimulator: - case TvOS: - case TvOSSimulator: // Earlier than 11.0. - return TargetVersion < VersionTuple(11U, 0U, 0U); - case WatchOS: - case WatchOSSimulator: // Earlier than 4.0. - return TargetVersion < VersionTuple(4U, 0U, 0U); + OS = llvm::Triple::IOS; + break; + case TvOS: // Earlier than 11.0. + OS = llvm::Triple::TvOS; + break; + case WatchOS: // Earlier than 4.0. + OS = llvm::Triple::WatchOS; + break; } - llvm_unreachable("Unsupported platform"); + + return TargetVersion < alignedAllocMinVersion(OS); } void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, @@ -1840,7 +1985,7 @@ bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { // Unwind tables are not emitted if -fno-exceptions is supplied (except when // targeting x86_64). return getArch() == llvm::Triple::x86_64 || - (!UseSjLjExceptions(Args) && + (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true)); } @@ -1851,15 +1996,18 @@ bool MachO::UseDwarfDebugFlags() const { return false; } -bool Darwin::UseSjLjExceptions(const ArgList &Args) const { +llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. if (getTriple().getArch() != llvm::Triple::arm && getTriple().getArch() != llvm::Triple::thumb) - return false; + return llvm::ExceptionHandling::None; // Only watchOS uses the new DWARF/Compact unwinding method. llvm::Triple Triple(ComputeLLVMTriple(Args)); - return !Triple.isWatchABI(); + if(Triple.isWatchABI()) + return llvm::ExceptionHandling::DwarfCFI; + + return llvm::ExceptionHandling::SjLj; } bool Darwin::SupportsEmbeddedBitcode() const { @@ -2000,8 +2148,6 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, } } -bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } - void Darwin::CheckObjCARC() const { if (isTargetIOSBased() || isTargetWatchOSBased() || (isTargetMacOS() && !isMacosxVersionLT(10, 6))) @@ -2015,6 +2161,8 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Address; Res |= SanitizerKind::Leak; Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Function; if (isTargetMacOS()) { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h index 77c569e8f865d..87d553bd7e0b2 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h @@ -152,10 +152,11 @@ public: llvm::opt::ArgStringList &CmdArgs) const {} /// Add the linker arguments to link the compiler runtime library. + /// + /// FIXME: This API is intended for use with embedded libraries only, and is + /// misleadingly named. virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - virtual void AddFuzzerLinkArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { @@ -171,10 +172,26 @@ public: /// Is the target either iOS or an iOS simulator? bool isTargetIOSBased() const { return false; } + /// Options to control how a runtime library is linked. + enum RuntimeLinkOptions : unsigned { + /// Link the library in even if it can't be found in the VFS. + RLO_AlwaysLink = 1 << 0, + + /// Use the embedded runtime from the macho_embedded directory. + RLO_IsEmbedded = 1 << 1, + + /// Emit rpaths for @executable_path as well as the resource directory. + RLO_AddRPath = 1 << 2, + + /// Link the library in before any others. + RLO_FirstLink = 1 << 3, + }; + + /// Add a runtime library to the list of items to link. void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink = false, - bool IsEmbedded = false, bool AddRPath = false) const; + StringRef DarwinLibName, + RuntimeLinkOptions Opts = RuntimeLinkOptions()) const; /// Add any profiling runtime libraries that are needed. This is essentially a /// MachO specific version of addProfileRT in Tools.cpp. @@ -228,12 +245,11 @@ public: bool SupportsProfiling() const override; - bool SupportsObjCGC() const override { return false; } - bool UseDwarfDebugFlags() const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override { - return false; + llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const override { + return llvm::ExceptionHandling::None; } /// } @@ -252,14 +268,17 @@ public: enum DarwinPlatformKind { MacOS, IPhoneOS, - IPhoneOSSimulator, TvOS, - TvOSSimulator, WatchOS, - WatchOSSimulator + LastDarwinPlatform = WatchOS + }; + enum DarwinEnvironmentKind { + NativeEnvironment, + Simulator, }; mutable DarwinPlatformKind TargetPlatform; + mutable DarwinEnvironmentKind TargetEnvironment; /// The OS version we are targeting. mutable VersionTuple TargetVersion; @@ -301,29 +320,34 @@ protected: // FIXME: Eliminate these ...Target functions and derive separate tool chains // for these targets and put version in constructor. - void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor, - unsigned Micro) const { + void setTarget(DarwinPlatformKind Platform, DarwinEnvironmentKind Environment, + unsigned Major, unsigned Minor, unsigned Micro) const { // FIXME: For now, allow reinitialization as long as values don't // change. This will go away when we move away from argument translation. if (TargetInitialized && TargetPlatform == Platform && + TargetEnvironment == Environment && TargetVersion == VersionTuple(Major, Minor, Micro)) return; assert(!TargetInitialized && "Target already initialized!"); TargetInitialized = true; TargetPlatform = Platform; + TargetEnvironment = Environment; TargetVersion = VersionTuple(Major, Minor, Micro); + if (Environment == Simulator) + const_cast<Darwin *>(this)->setTripleEnvironment(llvm::Triple::Simulator); } bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; + return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && + TargetEnvironment == NativeEnvironment; } bool isTargetIOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOSSimulator || - TargetPlatform == TvOSSimulator; + return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && + TargetEnvironment == Simulator; } bool isTargetIOSBased() const { @@ -333,32 +357,32 @@ protected: bool isTargetTvOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS; + return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment; } bool isTargetTvOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOSSimulator; + return TargetPlatform == TvOS && TargetEnvironment == Simulator; } bool isTargetTvOSBased() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; + return TargetPlatform == TvOS; } bool isTargetWatchOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS; + return TargetPlatform == WatchOS && TargetEnvironment == NativeEnvironment; } bool isTargetWatchOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOSSimulator; + return TargetPlatform == WatchOS && TargetEnvironment == Simulator; } bool isTargetWatchOSBased() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; + return TargetPlatform == WatchOS; } bool isTargetMacOS() const { @@ -394,10 +418,11 @@ protected: Action::OffloadKind DeviceOffloadKind) const override; StringRef getPlatformFamily() const; - static StringRef getSDKName(StringRef isysroot); StringRef getOSLibraryNameSuffix() const; public: + static StringRef getSDKName(StringRef isysroot); + /// } /// @name ToolChain Implementation /// { @@ -438,11 +463,10 @@ public: return 0; } - bool SupportsObjCGC() const override; - void CheckObjCARC() const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; bool SupportsEmbeddedBitcode() const override; @@ -489,7 +513,8 @@ public: private: void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - StringRef Sanitizer) const; + StringRef Sanitizer, + bool shared = true) const; }; } // end namespace toolchains diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp index bd2c7fc6c4bd2..648469e4cec51 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -127,7 +127,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp index c6626e922eef8..dd0334b9c28bd 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -240,7 +240,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else @@ -358,17 +359,18 @@ Tool *FreeBSD::buildAssembler() const { Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } -bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const { +llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { // FreeBSD uses SjLj exceptions on ARM oabi. switch (getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: - return false; - + return llvm::ExceptionHandling::None; default: - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); + if (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb) + return llvm::ExceptionHandling::SjLj; + return llvm::ExceptionHandling::None; } } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h index 25e9df72bc80f..2943e1cacfbb9 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h @@ -66,7 +66,8 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override { return 2; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp index 78053aafd16e5..10ee7b7829be4 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -14,6 +14,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" @@ -43,10 +44,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_w); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - if (llvm::sys::path::stem(Exec).equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - + if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || + llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { CmdArgs.push_back("-z"); CmdArgs.push_back("rodynamic"); } @@ -63,27 +62,28 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); - if (Args.hasArg(options::OPT_r)) + if (Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-r"); - else + } else { CmdArgs.push_back("--build-id"); + CmdArgs.push_back("--hash-style=gnu"); + } - if (!Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bstatic"); else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - if (!Args.hasArg(options::OPT_static)) { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1")); - } + if (!Args.hasArg(options::OPT_shared)) { + std::string Dyld = D.DyldPrefix; + if (ToolChain.getSanitizerArgs().needsAsanRt() && + ToolChain.getSanitizerArgs().needsSharedRt()) + Dyld += "asan/"; + Dyld += "ld.so.1"; + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back(Args.MakeArgString(Dyld)); } CmdArgs.push_back("-o"); @@ -100,6 +100,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); + addSanitizerRuntimes(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -107,13 +109,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Bdynamic"); if (D.CCCIsCXX()) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bstatic"); - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } @@ -282,5 +279,6 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, SanitizerMask Fuchsia::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Address; return Res; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h index a723a99dfa3bf..6f438deca7ff1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h @@ -42,12 +42,17 @@ public: bool HasNativeLLVMSupport() const override { return true; } bool IsIntegratedAssemblerDefault() const override { return true; } + bool IsMathErrnoDefault() const override { return false; } + bool useRelaxRelocations() const override { return true; }; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } CXXStdlibType GetDefaultCXXStdlibType() const override { return ToolChain::CST_Libcxx; } + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { + return true; + } bool isPICDefault() const override { return false; } bool isPIEDefault() const override { return true; } bool isPICDefaultForced() const override { return false; } @@ -78,7 +83,7 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; const char *getDefaultLinker() const override { - return "lld"; + return "ld.lld"; } protected: diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp index 72a9f85ba389a..7845781f12c42 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp @@ -11,6 +11,7 @@ #include "Linux.h" #include "Arch/ARM.h" #include "Arch/Mips.h" +#include "Arch/PPC.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "CommonArgs.h" @@ -41,6 +42,22 @@ static bool forwardToGCC(const Option &O) { !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } +// Switch CPU names not recognized by GNU assembler to a close CPU that it does +// recognize, instead of a lower march from being picked in the absence of a cpu +// flag. +static void normalizeCPUNamesForAssembler(const ArgList &Args, + ArgStringList &CmdArgs) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPUArg(A->getValue()); + if (CPUArg.equals_lower("krait")) + CmdArgs.push_back("-mcpu=cortex-a15"); + else if(CPUArg.equals_lower("kryo")) + CmdArgs.push_back("-mcpu=cortex-a57"); + else + Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + } +} + void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -203,133 +220,12 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // The types are (hopefully) good enough. } -/// Add OpenMP linker script arguments at the end of the argument list so that -/// the fat binary is built by embedding each of the device images into the -/// host. The linker script also defines a few symbols required by the code -/// generation so that the images can be easily retrieved at runtime by the -/// offloading library. This should be used only in tool chains that support -/// linker scripts. -static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs, - const JobAction &JA) { - - // If this is not an OpenMP host toolchain, we don't need to do anything. - if (!JA.isHostOffloading(Action::OFK_OpenMP)) - return; - - // Create temporary linker script. Keep it if save-temps is enabled. - const char *LKS; - SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); - if (C.getDriver().isSaveTempsEnabled()) { - llvm::sys::path::replace_extension(Name, "lk"); - LKS = C.getArgs().MakeArgString(Name.c_str()); - } else { - llvm::sys::path::replace_extension(Name, ""); - Name = C.getDriver().GetTemporaryPath(Name, "lk"); - LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); - } - - // Add linker script option to the command. - CmdArgs.push_back("-T"); - CmdArgs.push_back(LKS); - - // Create a buffer to write the contents of the linker script. - std::string LksBuffer; - llvm::raw_string_ostream LksStream(LksBuffer); - - // Get the OpenMP offload tool chains so that we can extract the triple - // associated with each device input. - auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); - assert(OpenMPToolChains.first != OpenMPToolChains.second && - "No OpenMP toolchains??"); - - // Track the input file name and device triple in order to build the script, - // inserting binaries in the designated sections. - SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; - - // Add commands to embed target binaries. We ensure that each section and - // image is 16-byte aligned. This is not mandatory, but increases the - // likelihood of data to be aligned with a cache block in several main host - // machines. - LksStream << "/*\n"; - LksStream << " OpenMP Offload Linker Script\n"; - LksStream << " *** Automatically generated by Clang ***\n"; - LksStream << "*/\n"; - LksStream << "TARGET(binary)\n"; - auto DTC = OpenMPToolChains.first; - for (auto &II : Inputs) { - const Action *A = II.getAction(); - // Is this a device linking action? - if (A && isa<LinkJobAction>(A) && - A->isDeviceOffloading(Action::OFK_OpenMP)) { - assert(DTC != OpenMPToolChains.second && - "More device inputs than device toolchains??"); - InputBinaryInfo.push_back(std::make_pair( - DTC->second->getTriple().normalize(), II.getFilename())); - ++DTC; - LksStream << "INPUT(" << II.getFilename() << ")\n"; - } - } - - assert(DTC == OpenMPToolChains.second && - "Less device inputs than device toolchains??"); - - LksStream << "SECTIONS\n"; - LksStream << "{\n"; - - // Put each target binary into a separate section. - for (const auto &BI : InputBinaryInfo) { - LksStream << " .omp_offloading." << BI.first << " :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " {\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first - << " = .);\n"; - LksStream << " " << BI.second << "\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first - << " = .);\n"; - LksStream << " }\n"; - } - - // Add commands to define host entries begin and end. We use 1-byte subalign - // so that the linker does not add any padding and the elements in this - // section form an array. - LksStream << " .omp_offloading.entries :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " SUBALIGN(0x01)\n"; - LksStream << " {\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; - LksStream << " *(.omp_offloading.entries)\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; - LksStream << " }\n"; - LksStream << "}\n"; - LksStream << "INSERT BEFORE .data\n"; - LksStream.flush(); - - // Dump the contents of the linker script if the user requested that. We - // support this option to enable testing of behavior with -###. - if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) - llvm::errs() << LksBuffer; - - // If this is a dry run, do not create the linker script file. - if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) - return; - - // Open script file and write the contents. - std::error_code EC; - llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); - - if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return; - } - - Lksf << LksBuffer; -} - static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + // Do not add the XRay runtime to shared libraries. + if (Args.hasArg(options::OPT_shared)) + return false; + if (Args.hasFlag(options::OPT_fxray_instrument, options::OPT_fnoxray_instrument, false)) { CmdArgs.push_back("-whole-archive"); @@ -337,6 +233,7 @@ static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-no-whole-archive"); return true; } + return false; } @@ -347,7 +244,8 @@ static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-lrt"); CmdArgs.push_back("-lm"); - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::NetBSD) CmdArgs.push_back("-ldl"); } @@ -401,6 +299,17 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { } } +static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static)) + return false; + + Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, + options::OPT_nopie); + if (!A) + return ToolChain.isPIEDefault(); + return A->getOption().matches(options::OPT_pie); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -415,9 +324,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); - const bool IsPIE = - !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + const bool IsPIE = getPIE(Args, ToolChain); const bool HasCRTBeginEndFiles = ToolChain.getTriple().hasEnvironment() || (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); @@ -560,13 +467,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bstatic"); - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + } CmdArgs.push_back("-lm"); } // Silence warnings when linking C code with a C++ '-stdlib' argument. @@ -693,22 +602,28 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, else CmdArgs.push_back("--64"); break; - case llvm::Triple::ppc: + case llvm::Triple::ppc: { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); - CmdArgs.push_back("-many"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; - case llvm::Triple::ppc64: + } + case llvm::Triple::ppc64: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; - case llvm::Triple::ppc64le: + } + case llvm::Triple::ppc64le: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); CmdArgs.push_back("-mlittle-endian"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; + } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); @@ -754,23 +669,16 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } Args.AddLastArg(CmdArgs, options::OPT_march_EQ); + normalizeCPUNamesForAssembler(Args, CmdArgs); - // FIXME: remove krait check when GNU tools support krait cpu - // for now replace it with -mcpu=cortex-a15 to avoid a lower - // march from being picked in the absence of a cpu flag. - Arg *A; - if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && - StringRef(A->getValue()).equals_lower("krait")) - CmdArgs.push_back("-mcpu=cortex-a15"); - else - Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); break; } case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: { Args.AddLastArg(CmdArgs, options::OPT_march_EQ); - Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + normalizeCPUNamesForAssembler(Args, CmdArgs); + break; } case llvm::Triple::mips: @@ -1427,12 +1335,12 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) + TargetTriple.isGNUEnvironment()) return findMipsMtiMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) + TargetTriple.isGNUEnvironment()) return findMipsImgMultilibs(Flags, NonExistent, Result); if (findMipsCsMultilibs(Flags, NonExistent, Result)) @@ -1482,7 +1390,7 @@ static void findAndroidArmMultilibs(const Driver &D, bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; bool IsThumbMode = IsThumbArch || Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || - (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB); + (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB); bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); @@ -2468,7 +2376,8 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || (getTriple().getOS() == llvm::Triple::Linux && - (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || + ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || + getTriple().isAndroid())) || getTriple().getOS() == llvm::Triple::NaCl || (getTriple().getVendor() == llvm::Triple::MipsTechnologies && !getTriple().hasEnvironment()) || diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp index 9bf1590e6a37e..f21af5b4dcf50 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -27,6 +27,101 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +// Default hvx-length for various versions. +static StringRef getDefaultHvxLength(StringRef Cpu) { + return llvm::StringSwitch<StringRef>(Cpu) + .Case("v60", "64b") + .Case("v62", "64b") + .Case("v65", "64b") + .Default("128b"); +} + +static void handleHVXWarnings(const Driver &D, const ArgList &Args) { + // Handle deprecated HVX double warnings. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_double)) + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << "-mhvx-length=128B"; + if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx_double)) + D.Diag(diag::warn_drv_deprecated_arg) << A->getAsString(Args) << "-mno-hvx"; + // Handle the unsupported values passed to mhvx-length. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { + StringRef Val = A->getValue(); + if (Val != "64B" && Val != "128B") + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } +} + +// Handle hvx target features explicitly. +static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<StringRef> &Features, + bool &HasHVX) { + // Handle HVX warnings. + handleHVXWarnings(D, Args); + + // Add the +hvx* features based on commandline flags. + StringRef HVXFeature, HVXLength; + StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); + + // Handle -mhvx, -mhvx=, -mno-hvx, -mno-hvx-double. + if (Arg *A = Args.getLastArg( + options::OPT_mno_hexagon_hvx, options::OPT_mno_hexagon_hvx_double, + options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ)) { + if (A->getOption().matches(options::OPT_mno_hexagon_hvx) || + A->getOption().matches(options::OPT_mno_hexagon_hvx_double)) { + return; + } else if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) { + HasHVX = true; + HVXFeature = Cpu = A->getValue(); + HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower()); + } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) { + HasHVX = true; + HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu); + } + Features.push_back(HVXFeature); + } + + // Handle -mhvx-length=, -mhvx-double. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ, + options::OPT_mhexagon_hvx_double)) { + // These falgs are valid only if HVX in enabled. + if (!HasHVX) + D.Diag(diag::err_drv_invalid_hvx_length); + else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ)) + HVXLength = A->getValue(); + else if (A->getOption().matches(options::OPT_mhexagon_hvx_double)) + HVXLength = "128b"; + } + // Default hvx-length based on Cpu. + else if (HasHVX) + HVXLength = getDefaultHvxLength(Cpu); + + if (!HVXLength.empty()) { + HVXFeature = + Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower()); + Features.push_back(HVXFeature); + } +} + +// Hexagon target features. +void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(Args, Features, + options::OPT_m_hexagon_Features_Group); + + bool UseLongCalls = false; + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mlong_calls)) + UseLongCalls = true; + } + + Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); + + bool HasHVX(false); + handleHVXTargetFeatures(D, Args, Features, HasHVX); +} + // Hexagon tools start. void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { @@ -248,7 +343,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, //---------------------------------------------------------------------------- if (IncStdLib && IncDefLibs) { if (D.CCCIsCXX()) { - HTC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (HTC.ShouldLinkCXXStdlib(Args)) + HTC.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h index 7f9a6b2f34b92..229a08c76dfbc 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h @@ -50,6 +50,10 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace hexagon. } // end namespace tools diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp index 08a27fa7fed10..1301cdf114ae1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp @@ -210,7 +210,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Distro Distro(D.getVFS()); - if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { + if (Distro.IsAlpineLinux()) { + ExtraOpts.push_back("-z"); + ExtraOpts.push_back("now"); + } + + if (Distro.IsOpenSUSE() || Distro.IsUbuntu() || Distro.IsAlpineLinux()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -232,7 +237,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Android loader does not support .gnu.hash. // Hexagon linker/loader does not support .gnu.hash if (!IsMips && !IsAndroid && !IsHexagon) { - if (Distro.IsRedhat() || Distro.IsOpenSUSE() || + if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() || (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -248,7 +253,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--build-id"); #endif - if (Distro.IsOpenSUSE()) + if (IsAndroid || Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -810,7 +815,10 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } -bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +bool Linux::isPIEDefault() const { + return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || + getTriple().isMusl() || getSanitizerArgs().requiresPIE(); +} SanitizerMask Linux::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; @@ -828,12 +836,13 @@ SanitizerMask Linux::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; @@ -841,9 +850,12 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; if (IsX86_64 || IsMIPS64) Res |= SanitizerKind::Efficiency; - if (IsX86 || IsX86_64) { + if (IsX86 || IsX86_64) Res |= SanitizerKind::Function; - } + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch) + Res |= SanitizerKind::Scudo; + if (IsAArch64) + Res |= SanitizerKind::HWAddress; return Res; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp index 7978a6941cb85..ae41ee9e22cf1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp @@ -375,7 +375,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs().needsSharedAsanRt() || + if (TC.getSanitizerArgs().needsSharedRt() || Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); @@ -1266,9 +1266,8 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, if (MSVT.empty() && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) { - // -fms-compatibility-version=18.00 is default. - // FIXME: Consider bumping this to 19 (MSVC2015) soon. - MSVT = VersionTuple(18); + // -fms-compatibility-version=19.11 is default, aka 2017 + MSVT = VersionTuple(19, 11); } return MSVT; } @@ -1317,24 +1316,26 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, case '2': case 'x': case 'd': - if (&OptChar == ExpandChar) { - if (OptChar == 'd') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); - } else { - if (OptChar == '1') { - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - } else if (OptChar == '2' || OptChar == 'x') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); - } - if (SupportsForcingFramePointer && - !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_fomit_frame_pointer)); - if (OptChar == '1' || OptChar == '2') - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_ffunction_sections)); + // Ignore /O[12xd] flags that aren't the last one on the command line. + // Only the last one gets expanded. + if (&OptChar != ExpandChar) { + A->claim(); + break; + } + if (OptChar == 'd') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); } + if (SupportsForcingFramePointer && + !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); } break; case 'b': @@ -1430,9 +1431,7 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // First step is to search for the character we'd like to expand. const char *ExpandChar = nullptr; - for (Arg *A : Args) { - if (!A->getOption().matches(options::OPT__SLASH_O)) - continue; + for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { char OptChar = OptStr[I]; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp index 632b76d92bddf..572ea803f2dc7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp @@ -82,6 +82,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); + for (auto Lib : Args.getAllArgValues(options::OPT_l)) + if (StringRef(Lib).startswith("msvcr") || Lib == "ucrtbase") + return; CmdArgs.push_back("-lmsvcrt"); } @@ -104,14 +107,6 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); - StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld"); - if (LinkerName.equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - } else if (!LinkerName.equals_lower("ld")) { - D.Diag(diag::err_drv_unsupported_linker) << LinkerName; - } - if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -119,12 +114,24 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-s"); CmdArgs.push_back("-m"); - if (TC.getArch() == llvm::Triple::x86) + switch (TC.getArch()) { + case llvm::Triple::x86: CmdArgs.push_back("i386pe"); - if (TC.getArch() == llvm::Triple::x86_64) + break; + case llvm::Triple::x86_64: CmdArgs.push_back("i386pep"); - if (TC.getArch() == llvm::Triple::arm) + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); + break; + case llvm::Triple::aarch64: + CmdArgs.push_back("arm64pe"); + break; + default: + llvm_unreachable("Unsupported target architecture."); + } if (Args.hasArg(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); @@ -185,8 +192,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // TODO: Add profile stuff here - if (D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (TC.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) @@ -230,7 +236,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); - else if (!LinkerName.equals_lower("lld")) + else AddLibGCC(Args, CmdArgs); } @@ -241,7 +247,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } - const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); + const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -361,8 +367,11 @@ bool toolchains::MinGW::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } -bool toolchains::MinGW::UseSEHExceptions() const { - return getArch() == llvm::Triple::x86_64; +llvm::ExceptionHandling +toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { + if (getArch() == llvm::Triple::x86_64) + return llvm::ExceptionHandling::WinEH; + return llvm::ExceptionHandling::DwarfCFI; } void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h index 9b3d7c553f1d8..f8dbcae627565 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h @@ -64,7 +64,9 @@ public: bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; - bool UseSEHExceptions() const; + + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp index 2e8939c401502..39e6f90b6ef02 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp @@ -72,7 +72,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp index 5eb5c74f1310c..128478d638719 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp @@ -133,13 +133,15 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - bool OnlyLibstdcxxStatic = - Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bstatic"); - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + bool OnlyLibstdcxxStatic = + Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + } CmdArgs.push_back("-lm"); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp index a1a3108cb28d7..0db6578f7407b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -278,7 +278,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, getToolChain(), Args); if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) @@ -324,7 +325,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - if (getDriver().UseStdLib) { + if (!Args.hasArg(options::OPT_nostdlib)) { // When targeting a 32-bit platform, try the special directory used on // 64-bit hosts, and only fall back to the main library directory if that // doesn't work. @@ -415,11 +416,34 @@ void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, "", DriverArgs, CC1Args); } +llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const { + // NetBSD uses Dwarf exceptions on ARM. + llvm::Triple::ArchType TArch = getTriple().getArch(); + if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb || + TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb) + return llvm::ExceptionHandling::DwarfCFI; + return llvm::ExceptionHandling::None; +} + SanitizerMask NetBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86_64) { + if (IsX86 || IsX86_64) { Res |= SanitizerKind::Address; + Res |= SanitizerKind::Function; + Res |= SanitizerKind::Leak; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Scudo; + Res |= SanitizerKind::Vptr; + } + if (IsX86_64) { + Res |= SanitizerKind::Efficiency; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::Memory; + Res |= SanitizerKind::Thread; } return Res; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h index 5163ff72d81bb..e98df72ce65c2 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h @@ -69,6 +69,9 @@ public: return true; } + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; + SanitizerMask getSupportedSanitizers() const override; protected: diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp index 1d54a1e9cbb05..fbb84a62ca89e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -179,7 +179,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp index c1b8c3d660779..b37fe7d1f9b91 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -227,7 +227,8 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C, // libraries for both C and C++ compilations. CmdArgs.push_back("-lkernel"); if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp index de98d11b2dc7b..9fe6e9d520d09 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp @@ -100,7 +100,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX()) + if (getToolChain().ShouldLinkCXXStdlib(Args)) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("-lc"); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp index 058bc42323e2f..8ae1b6c2f55df 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -38,46 +38,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); ArgStringList CmdArgs; CmdArgs.push_back("-flavor"); CmdArgs.push_back("wasm"); - // Enable garbage collection of unused input sections by default, since code - // size is of particular importance. This is significantly facilitated by - // the enabling of -ffunction-sections and -fdata-sections in - // Clang::ConstructJob. - if (areOptimizationsEnabled(Args)) - CmdArgs.push_back("--gc-sections"); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-shared"); - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("-Bstatic"); Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o"))); - else if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) + if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pthread)) @@ -86,12 +65,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-allow-undefined-file"); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms"))); CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lcompiler_rt"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -123,9 +99,6 @@ bool WebAssembly::isPICDefaultForced() const { return false; } bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } -// TODO: Support Objective C stuff. -bool WebAssembly::SupportsObjCGC() const { return false; } - bool WebAssembly::hasBlocksRuntime() const { return false; } // TODO: Support profiling. @@ -163,6 +136,14 @@ void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, getDriver().SysRoot + "/include/c++/v1"); } +std::string WebAssembly::getThreadModel() const { + // The WebAssembly MVP does not yet support threads; for now, use the + // "single" threading model, which lowers atomics to non-atomic operations. + // When threading support is standardized and implemented in popular engines, + // this override should be removed. + return "single"; +} + Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h index 2999db477f799..8784e12dfb0ec 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h @@ -49,7 +49,6 @@ private: bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; - bool SupportsObjCGC() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, @@ -63,6 +62,7 @@ private: void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + std::string getThreadModel() const override; const char *getDefaultLinker() const override { return "lld"; diff --git a/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp index 8d68a8432d39d..232bacd5f0955 100644 --- a/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp @@ -27,8 +27,6 @@ namespace { constexpr char XRayInstrumentOption[] = "-fxray-instrument"; constexpr char XRayInstructionThresholdOption[] = "-fxray-instruction-threshold="; -constexpr char XRayAlwaysInstrumentOption[] = "-fxray-always-instrument="; -constexpr char XRayNeverInstrumentOption[] = "-fxray-never-instrument="; } // namespace XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { @@ -63,6 +61,14 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } + // By default, the back-end will not emit the lowering for XRay customevent + // calls if the function is not instrumented. In the future we will change + // this default to be the reverse, but in the meantime we're going to + // introduce the new functionality behind a flag. + if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, + options::OPT_fnoxray_always_emit_customevents, false)) + XRayAlwaysEmitCustomEvents = true; + // Validate the always/never attribute files. We also make sure that they // are treated as actual dependencies. for (const auto &Filename : @@ -91,17 +97,21 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, return; CmdArgs.push_back(XRayInstrumentOption); + + if (XRayAlwaysEmitCustomEvents) + CmdArgs.push_back("-fxray-always-emit-customevents"); + CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + Twine(InstructionThreshold))); for (const auto &Always : AlwaysInstrumentFiles) { - SmallString<64> AlwaysInstrumentOpt(XRayAlwaysInstrumentOption); + SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); AlwaysInstrumentOpt += Always; CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); } for (const auto &Never : NeverInstrumentFiles) { - SmallString<64> NeverInstrumentOpt(XRayNeverInstrumentOption); + SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); NeverInstrumentOpt += Never; CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); } diff --git a/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp b/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp index 3c9df62f80dca..4735ab3564f0e 100644 --- a/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp +++ b/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp @@ -40,9 +40,15 @@ static bool IsBlank(char C) { } } -static StringRef getLineCommentIndentPrefix(StringRef Comment) { - static const char *const KnownPrefixes[] = { - "///<", "//!<", "///", "//", "//!"}; +static StringRef getLineCommentIndentPrefix(StringRef Comment, + const FormatStyle &Style) { + static const char *const KnownCStylePrefixes[] = {"///<", "//!<", "///", "//", + "//!"}; + static const char *const KnownTextProtoPrefixes[] = {"//", "#"}; + ArrayRef<const char *> KnownPrefixes(KnownCStylePrefixes); + if (Style.Language == FormatStyle::LK_TextProto) + KnownPrefixes = KnownTextProtoPrefixes; + StringRef LongestPrefix; for (StringRef KnownPrefix : KnownPrefixes) { if (Comment.startswith(KnownPrefix)) { @@ -61,6 +67,8 @@ static BreakableToken::Split getCommentSplit(StringRef Text, unsigned ColumnLimit, unsigned TabWidth, encoding::Encoding Encoding) { + DEBUG(llvm::dbgs() << "Comment split: \"" << Text << ", " << ColumnLimit + << "\", Content start: " << ContentStartColumn << "\n"); if (ColumnLimit <= ContentStartColumn + 1) return BreakableToken::Split(StringRef::npos, 0); @@ -165,7 +173,7 @@ bool switchesFormatting(const FormatToken &Token) { } unsigned -BreakableToken::getLineLengthAfterCompression(unsigned RemainingTokenColumns, +BreakableToken::getLengthAfterCompression(unsigned RemainingTokenColumns, Split Split) const { // Example: consider the content // lala lala @@ -175,58 +183,64 @@ BreakableToken::getLineLengthAfterCompression(unsigned RemainingTokenColumns, // We compute the number of columns when the split is compressed into a single // space, like: // lala lala + // + // FIXME: Correctly measure the length of whitespace in Split.second so it + // works with tabs. return RemainingTokenColumns + 1 - Split.second; } -unsigned BreakableSingleLineToken::getLineCount() const { return 1; } +unsigned BreakableStringLiteral::getLineCount() const { return 1; } + +unsigned BreakableStringLiteral::getRangeLength(unsigned LineIndex, + unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const { + llvm_unreachable("Getting the length of a part of the string literal " + "indicates that the code tries to reflow it."); +} + +unsigned +BreakableStringLiteral::getRemainingLength(unsigned LineIndex, unsigned Offset, + unsigned StartColumn) const { + return UnbreakableTailLength + Postfix.size() + + encoding::columnWidthWithTabs(Line.substr(Offset, StringRef::npos), + StartColumn, Style.TabWidth, Encoding); +} -unsigned BreakableSingleLineToken::getLineLengthAfterSplit( - unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const { - return StartColumn + Prefix.size() + Postfix.size() + - encoding::columnWidthWithTabs(Line.substr(TailOffset, Length), - StartColumn + Prefix.size(), - Style.TabWidth, Encoding); +unsigned BreakableStringLiteral::getContentStartColumn(unsigned LineIndex, + bool Break) const { + return StartColumn + Prefix.size(); } -BreakableSingleLineToken::BreakableSingleLineToken( +BreakableStringLiteral::BreakableStringLiteral( const FormatToken &Tok, unsigned StartColumn, StringRef Prefix, StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style) : BreakableToken(Tok, InPPDirective, Encoding, Style), - StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) { + StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix), + UnbreakableTailLength(Tok.UnbreakableTailLength) { assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix)); Line = Tok.TokenText.substr( Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size()); } -BreakableStringLiteral::BreakableStringLiteral( - const FormatToken &Tok, unsigned StartColumn, StringRef Prefix, - StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding, - const FormatStyle &Style) - : BreakableSingleLineToken(Tok, StartColumn, Prefix, Postfix, InPPDirective, - Encoding, Style) {} - -BreakableToken::Split -BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset, - unsigned ColumnLimit, - llvm::Regex &CommentPragmasRegex) const { - return getStringSplit(Line.substr(TailOffset), - StartColumn + Prefix.size() + Postfix.size(), - ColumnLimit, Style.TabWidth, Encoding); +BreakableToken::Split BreakableStringLiteral::getSplit( + unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, + unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { + return getStringSplit(Line.substr(TailOffset), ContentStartColumn, + ColumnLimit - Postfix.size(), Style.TabWidth, Encoding); } void BreakableStringLiteral::insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) { + WhitespaceManager &Whitespaces) const { Whitespaces.replaceWhitespaceInToken( Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix, Prefix, InPPDirective, 1, StartColumn); } BreakableComment::BreakableComment(const FormatToken &Token, - unsigned StartColumn, - bool InPPDirective, + unsigned StartColumn, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style) : BreakableToken(Token, InPPDirective, Encoding, Style), @@ -236,19 +250,19 @@ unsigned BreakableComment::getLineCount() const { return Lines.size(); } BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset, - unsigned ColumnLimit, + unsigned ColumnLimit, unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); return getCommentSplit(Content[LineIndex].substr(TailOffset), - getContentStartColumn(LineIndex, TailOffset), - ColumnLimit, Style.TabWidth, Encoding); + ContentStartColumn, ColumnLimit, Style.TabWidth, + Encoding); } -void BreakableComment::compressWhitespace(unsigned LineIndex, - unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) { +void BreakableComment::compressWhitespace( + unsigned LineIndex, unsigned TailOffset, Split Split, + WhitespaceManager &Whitespaces) const { StringRef Text = Content[LineIndex].substr(TailOffset); // Text is relative to the content line, but Whitespaces operates relative to // the start of the corresponding token, so compute the start of the Split @@ -262,44 +276,6 @@ void BreakableComment::compressWhitespace(unsigned LineIndex, /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1); } -BreakableToken::Split -BreakableComment::getReflowSplit(StringRef Text, StringRef ReflowPrefix, - unsigned PreviousEndColumn, - unsigned ColumnLimit) const { - unsigned ReflowStartColumn = PreviousEndColumn + ReflowPrefix.size(); - StringRef TrimmedText = Text.rtrim(Blanks); - // This is the width of the resulting line in case the full line of Text gets - // reflown up starting at ReflowStartColumn. - unsigned FullWidth = ReflowStartColumn + encoding::columnWidthWithTabs( - TrimmedText, ReflowStartColumn, - Style.TabWidth, Encoding); - // If the full line fits up, we return a reflow split after it, - // otherwise we compute the largest piece of text that fits after - // ReflowStartColumn. - Split ReflowSplit = - FullWidth <= ColumnLimit - ? Split(TrimmedText.size(), Text.size() - TrimmedText.size()) - : getCommentSplit(Text, ReflowStartColumn, ColumnLimit, - Style.TabWidth, Encoding); - - // We need to be extra careful here, because while it's OK to keep a long line - // if it can't be broken into smaller pieces (like when the first word of a - // long line is longer than the column limit), it's not OK to reflow that long - // word up. So we recompute the size of the previous line after reflowing and - // only return the reflow split if that's under the line limit. - if (ReflowSplit.first != StringRef::npos && - // Check if the width of the newly reflown line is under the limit. - PreviousEndColumn + ReflowPrefix.size() + - encoding::columnWidthWithTabs(Text.substr(0, ReflowSplit.first), - PreviousEndColumn + - ReflowPrefix.size(), - Style.TabWidth, Encoding) <= - ColumnLimit) { - return ReflowSplit; - } - return Split(StringRef::npos, 0); -} - const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const { return Tokens[LineIndex] ? *Tokens[LineIndex] : Tok; } @@ -309,7 +285,7 @@ static bool mayReflowContent(StringRef Content) { // Lines starting with '@' commonly have special meaning. // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists. static const SmallVector<StringRef, 8> kSpecialMeaningPrefixes = { - "@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* " }; + "@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}; bool hasSpecialMeaningPrefix = false; for (StringRef Prefix : kSpecialMeaningPrefixes) { if (Content.startswith(Prefix)) { @@ -322,8 +298,8 @@ static bool mayReflowContent(StringRef Content) { // To avoid issues if a line starts with a number which is actually the end // of a previous line, we only consider numbers with up to 2 digits. static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. "); - hasSpecialMeaningPrefix = hasSpecialMeaningPrefix || - kNumberedListRegexp.match(Content); + hasSpecialMeaningPrefix = + hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content); // Simple heuristic for what to reflow: content should contain at least two // characters and either the first or second character must be @@ -339,7 +315,9 @@ BreakableBlockComment::BreakableBlockComment( const FormatToken &Token, unsigned StartColumn, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style) - : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) { + : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style), + DelimitersOnNewline(false), + UnbreakableTailLength(Token.UnbreakableTailLength) { assert(Tok.is(TT_BlockComment) && "block comment section must start with a block comment"); @@ -384,8 +362,7 @@ BreakableBlockComment::BreakableBlockComment( // If the last line is empty, the closing "*/" will have a star. if (i + 1 == e && Content[i].empty()) break; - if (!Content[i].empty() && i + 1 != e && - Decoration.startswith(Content[i])) + if (!Content[i].empty() && i + 1 != e && Decoration.startswith(Content[i])) continue; while (!Content[i].startswith(Decoration)) Decoration = Decoration.substr(0, Decoration.size() - 1); @@ -427,11 +404,30 @@ BreakableBlockComment::BreakableBlockComment( IndentAtLineBreak = std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i])); } - IndentAtLineBreak = - std::max<unsigned>(IndentAtLineBreak, Decoration.size()); + IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size()); + + // Detect a multiline jsdoc comment and set DelimitersOnNewline in that case. + if (Style.Language == FormatStyle::LK_JavaScript || + Style.Language == FormatStyle::LK_Java) { + if ((Lines[0] == "*" || Lines[0].startswith("* ")) && Lines.size() > 1) { + // This is a multiline jsdoc comment. + DelimitersOnNewline = true; + } else if (Lines[0].startswith("* ") && Lines.size() == 1) { + // Detect a long single-line comment, like: + // /** long long long */ + // Below, '2' is the width of '*/'. + unsigned EndColumn = + ContentColumn[0] + + encoding::columnWidthWithTabs(Lines[0], ContentColumn[0], + Style.TabWidth, Encoding) + + 2; + DelimitersOnNewline = EndColumn > Style.ColumnLimit; + } + } DEBUG({ llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n"; + llvm::dbgs() << "DelimitersOnNewline " << DelimitersOnNewline << "\n"; for (size_t i = 0; i < Lines.size(); ++i) { llvm::dbgs() << i << " |" << Content[i] << "| " << "CC=" << ContentColumn[i] << "| " @@ -477,30 +473,45 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex, IndentDelta; } -unsigned BreakableBlockComment::getLineLengthAfterSplit( - unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const { - unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset); +unsigned BreakableBlockComment::getRangeLength(unsigned LineIndex, + unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const { unsigned LineLength = - ContentStartColumn + encoding::columnWidthWithTabs( - Content[LineIndex].substr(TailOffset, Length), - ContentStartColumn, Style.TabWidth, Encoding); + encoding::columnWidthWithTabs(Content[LineIndex].substr(Offset, Length), + StartColumn, Style.TabWidth, Encoding); + // FIXME: This should go into getRemainingLength instead, but we currently + // break tests when putting it there. Investigate how to fix those tests. // The last line gets a "*/" postfix. if (LineIndex + 1 == Lines.size()) { LineLength += 2; // We never need a decoration when breaking just the trailing "*/" postfix. // Note that checking that Length == 0 is not enough, since Length could // also be StringRef::npos. - if (Content[LineIndex].substr(TailOffset, Length).empty()) { + if (Content[LineIndex].substr(Offset, StringRef::npos).empty()) { LineLength -= Decoration.size(); } } return LineLength; } +unsigned BreakableBlockComment::getRemainingLength(unsigned LineIndex, + unsigned Offset, + unsigned StartColumn) const { + return UnbreakableTailLength + + getRangeLength(LineIndex, Offset, StringRef::npos, StartColumn); +} + +unsigned BreakableBlockComment::getContentStartColumn(unsigned LineIndex, + bool Break) const { + if (Break) + return IndentAtLineBreak; + return std::max(0, ContentColumn[LineIndex]); +} + void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) { + WhitespaceManager &Whitespaces) const { StringRef Text = Content[LineIndex].substr(TailOffset); StringRef Prefix = Decoration; // We need this to account for the case when we have a decoration "* " for all @@ -526,97 +537,55 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset, /*Spaces=*/LocalIndentAtLineBreak - Prefix.size()); } -BreakableToken::Split BreakableBlockComment::getSplitBefore( - unsigned LineIndex, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - llvm::Regex &CommentPragmasRegex) const { +BreakableToken::Split +BreakableBlockComment::getReflowSplit(unsigned LineIndex, + llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); - StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks); - return getReflowSplit(TrimmedContent, ReflowPrefix, PreviousEndColumn, - ColumnLimit); -} -unsigned BreakableBlockComment::getReflownColumn( - StringRef Content, - unsigned LineIndex, - unsigned PreviousEndColumn) const { - unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size(); - // If this is the last line, it will carry around its '*/' postfix. - unsigned PostfixLength = (LineIndex + 1 == Lines.size() ? 2 : 0); - // The line is composed of previous text, reflow prefix, reflown text and - // postfix. - unsigned ReflownColumn = - StartColumn + encoding::columnWidthWithTabs(Content, StartColumn, - Style.TabWidth, Encoding) + - PostfixLength; - return ReflownColumn; + size_t Trimmed = Content[LineIndex].find_first_not_of(Blanks); + return Split(0, Trimmed != StringRef::npos ? Trimmed : 0); } -unsigned BreakableBlockComment::getLineLengthAfterSplitBefore( - unsigned LineIndex, unsigned TailOffset, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - Split SplitBefore) const { - if (SplitBefore.first == StringRef::npos || - // Block comment line contents contain the trailing whitespace after the - // decoration, so the need of left trim. Note that this behavior is - // consistent with the breaking of block comments where the indentation of - // a broken line is uniform across all the lines of the block comment. - SplitBefore.first + SplitBefore.second < - Content[LineIndex].ltrim().size()) { - // A piece of line, not the whole, gets reflown. - return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); - } else { - // The whole line gets reflown, need to check if we need to insert a break - // for the postfix or not. - StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks); - unsigned ReflownColumn = - getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn); - if (ReflownColumn <= ColumnLimit) { - return ReflownColumn; - } - return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); - } +bool BreakableBlockComment::introducesBreakBeforeToken() const { + // A break is introduced when we want delimiters on newline. + return DelimitersOnNewline && + Lines[0].substr(1).find_first_not_of(Blanks) != StringRef::npos; } -void BreakableBlockComment::replaceWhitespaceBefore( - unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, - Split SplitBefore, WhitespaceManager &Whitespaces) { - if (LineIndex == 0) return; + +void BreakableBlockComment::reflow(unsigned LineIndex, + WhitespaceManager &Whitespaces) const { StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks); - if (SplitBefore.first != StringRef::npos) { - // Here we need to reflow. - assert(Tokens[LineIndex - 1] == Tokens[LineIndex] && - "Reflowing whitespace within a token"); - // This is the offset of the end of the last line relative to the start of - // the token text in the token. - unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() + - Content[LineIndex - 1].size() - - tokenAt(LineIndex).TokenText.data(); - unsigned WhitespaceLength = TrimmedContent.data() - - tokenAt(LineIndex).TokenText.data() - - WhitespaceOffsetInToken; - Whitespaces.replaceWhitespaceInToken( - tokenAt(LineIndex), WhitespaceOffsetInToken, - /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"", - /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0, - /*Spaces=*/0); - // Check if we need to also insert a break at the whitespace range. - // For this we first adapt the reflow split relative to the beginning of the - // content. - // Note that we don't need a penalty for this break, since it doesn't change - // the total number of lines. - Split BreakSplit = SplitBefore; - BreakSplit.first += TrimmedContent.data() - Content[LineIndex].data(); - unsigned ReflownColumn = - getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn); - if (ReflownColumn > ColumnLimit) { - insertBreak(LineIndex, 0, BreakSplit, Whitespaces); + // Here we need to reflow. + assert(Tokens[LineIndex - 1] == Tokens[LineIndex] && + "Reflowing whitespace within a token"); + // This is the offset of the end of the last line relative to the start of + // the token text in the token. + unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() + + Content[LineIndex - 1].size() - + tokenAt(LineIndex).TokenText.data(); + unsigned WhitespaceLength = TrimmedContent.data() - + tokenAt(LineIndex).TokenText.data() - + WhitespaceOffsetInToken; + Whitespaces.replaceWhitespaceInToken( + tokenAt(LineIndex), WhitespaceOffsetInToken, + /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"", + /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0, + /*Spaces=*/0); +} + +void BreakableBlockComment::adaptStartOfLine( + unsigned LineIndex, WhitespaceManager &Whitespaces) const { + if (LineIndex == 0) { + if (DelimitersOnNewline) { + // Since we're breaking at index 1 below, the break position and the + // break length are the same. + size_t BreakLength = Lines[0].substr(1).find_first_not_of(Blanks); + if (BreakLength != StringRef::npos) + insertBreak(LineIndex, 0, Split(1, BreakLength), Whitespaces); } return; } - // Here no reflow with the previous line will happen. // Fix the decoration of the line at LineIndex. StringRef Prefix = Decoration; @@ -651,6 +620,20 @@ void BreakableBlockComment::replaceWhitespaceBefore( InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size()); } +BreakableToken::Split +BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset) const { + if (DelimitersOnNewline) { + // Replace the trailing whitespace of the last line with a newline. + // In case the last line is empty, the ending '*/' is already on its own + // line. + StringRef Line = Content.back().substr(TailOffset); + StringRef TrimmedLine = Line.rtrim(Blanks); + if (!TrimmedLine.empty()) + return Split(TrimmedLine.size(), Line.size() - TrimmedLine.size()); + } + return Split(StringRef::npos, 0); +} + bool BreakableBlockComment::mayReflow(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { // Content[LineIndex] may exclude the indent after the '*' decoration. In that @@ -664,15 +647,6 @@ bool BreakableBlockComment::mayReflow(unsigned LineIndex, !switchesFormatting(tokenAt(LineIndex)); } -unsigned -BreakableBlockComment::getContentStartColumn(unsigned LineIndex, - unsigned TailOffset) const { - // If we break, we always break at the predefined indent. - if (TailOffset != 0) - return IndentAtLineBreak; - return std::max(0, ContentColumn[LineIndex]); -} - BreakableLineCommentSection::BreakableLineCommentSection( const FormatToken &Token, unsigned StartColumn, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, @@ -686,7 +660,8 @@ BreakableLineCommentSection::BreakableLineCommentSection( CurrentTok = CurrentTok->Next) { LastLineTok = LineTok; StringRef TokenText(CurrentTok->TokenText); - assert(TokenText.startswith("//")); + assert((TokenText.startswith("//") || TokenText.startswith("#")) && + "unsupported line comment prefix, '//' and '#' are supported"); size_t FirstLineIndex = Lines.size(); TokenText.split(Lines, "\n"); Content.resize(Lines.size()); @@ -696,11 +671,13 @@ BreakableLineCommentSection::BreakableLineCommentSection( Prefix.resize(Lines.size()); OriginalPrefix.resize(Lines.size()); for (size_t i = FirstLineIndex, e = Lines.size(); i < e; ++i) { + Lines[i] = Lines[i].ltrim(Blanks); // We need to trim the blanks in case this is not the first line in a // multiline comment. Then the indent is included in Lines[i]. StringRef IndentPrefix = - getLineCommentIndentPrefix(Lines[i].ltrim(Blanks)); - assert(IndentPrefix.startswith("//")); + getLineCommentIndentPrefix(Lines[i].ltrim(Blanks), Style); + assert((TokenText.startswith("//") || TokenText.startswith("#")) && + "unsupported line comment prefix, '//' and '#' are supported"); OriginalPrefix[i] = Prefix[i] = IndentPrefix; if (Lines[i].size() > Prefix[i].size() && isAlphanumeric(Lines[i][Prefix[i].size()])) { @@ -714,22 +691,20 @@ BreakableLineCommentSection::BreakableLineCommentSection( Prefix[i] = "///< "; else if (Prefix[i] == "//!<") Prefix[i] = "//!< "; + else if (Prefix[i] == "#" && + Style.Language == FormatStyle::LK_TextProto) + Prefix[i] = "# "; } Tokens[i] = LineTok; Content[i] = Lines[i].substr(IndentPrefix.size()); OriginalContentColumn[i] = - StartColumn + - encoding::columnWidthWithTabs(OriginalPrefix[i], - StartColumn, - Style.TabWidth, - Encoding); + StartColumn + encoding::columnWidthWithTabs(OriginalPrefix[i], + StartColumn, + Style.TabWidth, Encoding); ContentColumn[i] = - StartColumn + - encoding::columnWidthWithTabs(Prefix[i], - StartColumn, - Style.TabWidth, - Encoding); + StartColumn + encoding::columnWidthWithTabs(Prefix[i], StartColumn, + Style.TabWidth, Encoding); // Calculate the end of the non-whitespace text in this line. size_t EndOfLine = Content[i].find_last_not_of(Blanks); @@ -760,20 +735,25 @@ BreakableLineCommentSection::BreakableLineCommentSection( } } -unsigned BreakableLineCommentSection::getLineLengthAfterSplit( - unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const { - unsigned ContentStartColumn = - (TailOffset == 0 ? ContentColumn[LineIndex] - : OriginalContentColumn[LineIndex]); - return ContentStartColumn + encoding::columnWidthWithTabs( - Content[LineIndex].substr(TailOffset, Length), - ContentStartColumn, Style.TabWidth, Encoding); +unsigned +BreakableLineCommentSection::getRangeLength(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const { + return encoding::columnWidthWithTabs( + Content[LineIndex].substr(Offset, Length), StartColumn, Style.TabWidth, + Encoding); +} + +unsigned BreakableLineCommentSection::getContentStartColumn(unsigned LineIndex, + bool Break) const { + if (Break) + return OriginalContentColumn[LineIndex]; + return ContentColumn[LineIndex]; } -void BreakableLineCommentSection::insertBreak(unsigned LineIndex, - unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) { +void BreakableLineCommentSection::insertBreak( + unsigned LineIndex, unsigned TailOffset, Split Split, + WhitespaceManager &Whitespaces) const { StringRef Text = Content[LineIndex].substr(TailOffset); // Compute the offset of the split relative to the beginning of the token // text. @@ -792,37 +772,42 @@ void BreakableLineCommentSection::insertBreak(unsigned LineIndex, /*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size()); } -BreakableComment::Split BreakableLineCommentSection::getSplitBefore( - unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, - llvm::Regex &CommentPragmasRegex) const { +BreakableComment::Split BreakableLineCommentSection::getReflowSplit( + unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); - return getReflowSplit(Content[LineIndex], ReflowPrefix, PreviousEndColumn, - ColumnLimit); + + size_t Trimmed = Content[LineIndex].find_first_not_of(Blanks); + + // In a line comment section each line is a separate token; thus, after a + // split we replace all whitespace before the current line comment token + // (which does not need to be included in the split), plus the start of the + // line up to where the content starts. + return Split(0, Trimmed != StringRef::npos ? Trimmed : 0); } -unsigned BreakableLineCommentSection::getLineLengthAfterSplitBefore( - unsigned LineIndex, unsigned TailOffset, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - Split SplitBefore) const { - if (SplitBefore.first == StringRef::npos || - SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) { - // A piece of line, not the whole line, gets reflown. - return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); - } else { - // The whole line gets reflown. - unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size(); - return StartColumn + encoding::columnWidthWithTabs(Content[LineIndex], - StartColumn, - Style.TabWidth, - Encoding); - } +void BreakableLineCommentSection::reflow(unsigned LineIndex, + WhitespaceManager &Whitespaces) const { + // Reflow happens between tokens. Replace the whitespace between the + // tokens by the empty string. + Whitespaces.replaceWhitespace( + *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0, + /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false); + // Replace the indent and prefix of the token with the reflow prefix. + unsigned WhitespaceLength = + Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data(); + Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex], + /*Offset=*/0, + /*ReplaceChars=*/WhitespaceLength, + /*PreviousPostfix=*/"", + /*CurrentPrefix=*/ReflowPrefix, + /*InPPDirective=*/false, + /*Newlines=*/0, + /*Spaces=*/0); } -void BreakableLineCommentSection::replaceWhitespaceBefore( - unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, - Split SplitBefore, WhitespaceManager &Whitespaces) { +void BreakableLineCommentSection::adaptStartOfLine( + unsigned LineIndex, WhitespaceManager &Whitespaces) const { // If this is the first line of a token, we need to inform Whitespace Manager // about it: either adapt the whitespace range preceding it, or mark it as an // untouchable token. @@ -830,44 +815,25 @@ void BreakableLineCommentSection::replaceWhitespaceBefore( // // line 1 \ // // line 2 if (LineIndex > 0 && Tokens[LineIndex] != Tokens[LineIndex - 1]) { - if (SplitBefore.first != StringRef::npos) { - // Reflow happens between tokens. Replace the whitespace between the - // tokens by the empty string. - Whitespaces.replaceWhitespace( - *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0, - /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false); - // Replace the indent and prefix of the token with the reflow prefix. - unsigned WhitespaceLength = - Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data(); - Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex], - /*Offset=*/0, - /*ReplaceChars=*/WhitespaceLength, - /*PreviousPostfix=*/"", - /*CurrentPrefix=*/ReflowPrefix, - /*InPPDirective=*/false, - /*Newlines=*/0, - /*Spaces=*/0); - } else { - // This is the first line for the current token, but no reflow with the - // previous token is necessary. However, we still may need to adjust the - // start column. Note that ContentColumn[LineIndex] is the expected - // content column after a possible update to the prefix, hence the prefix - // length change is included. - unsigned LineColumn = - ContentColumn[LineIndex] - - (Content[LineIndex].data() - Lines[LineIndex].data()) + - (OriginalPrefix[LineIndex].size() - Prefix[LineIndex].size()); + // This is the first line for the current token, but no reflow with the + // previous token is necessary. However, we still may need to adjust the + // start column. Note that ContentColumn[LineIndex] is the expected + // content column after a possible update to the prefix, hence the prefix + // length change is included. + unsigned LineColumn = + ContentColumn[LineIndex] - + (Content[LineIndex].data() - Lines[LineIndex].data()) + + (OriginalPrefix[LineIndex].size() - Prefix[LineIndex].size()); - // We always want to create a replacement instead of adding an untouchable - // token, even if LineColumn is the same as the original column of the - // token. This is because WhitespaceManager doesn't align trailing - // comments if they are untouchable. - Whitespaces.replaceWhitespace(*Tokens[LineIndex], - /*Newlines=*/1, - /*Spaces=*/LineColumn, - /*StartOfTokenColumn=*/LineColumn, - /*InPPDirective=*/false); - } + // We always want to create a replacement instead of adding an untouchable + // token, even if LineColumn is the same as the original column of the + // token. This is because WhitespaceManager doesn't align trailing + // comments if they are untouchable. + Whitespaces.replaceWhitespace(*Tokens[LineIndex], + /*Newlines=*/1, + /*Spaces=*/LineColumn, + /*StartOfTokenColumn=*/LineColumn, + /*InPPDirective=*/false); } if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) { // Adjust the prefix if necessary. @@ -880,16 +846,9 @@ void BreakableLineCommentSection::replaceWhitespaceBefore( tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "", /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1); } - // Add a break after a reflow split has been introduced, if necessary. - // Note that this break doesn't need to be penalized, since it doesn't change - // the number of lines. - if (SplitBefore.first != StringRef::npos && - SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) { - insertBreak(LineIndex, 0, SplitBefore, Whitespaces); - } } -void BreakableLineCommentSection::updateNextToken(LineState& State) const { +void BreakableLineCommentSection::updateNextToken(LineState &State) const { if (LastLineTok) { State.NextToken = LastLineTok->Next; } @@ -903,20 +862,17 @@ bool BreakableLineCommentSection::mayReflow( if (Lines[LineIndex].startswith("//")) { IndentContent = Lines[LineIndex].substr(2); } + // FIXME: Decide whether we want to reflow non-regular indents: + // Currently, we only reflow when the OriginalPrefix[LineIndex] matches the + // OriginalPrefix[LineIndex-1]. That means we don't reflow + // // text that protrudes + // // into text with different indent + // We do reflow in that case in block comments. return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) && mayReflowContent(Content[LineIndex]) && !Tok.Finalized && !switchesFormatting(tokenAt(LineIndex)) && OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1]; } -unsigned -BreakableLineCommentSection::getContentStartColumn(unsigned LineIndex, - unsigned TailOffset) const { - if (TailOffset != 0) { - return OriginalContentColumn[LineIndex]; - } - return ContentColumn[LineIndex]; -} - } // namespace format } // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Format/BreakableToken.h b/contrib/llvm/tools/clang/lib/Format/BreakableToken.h index e642a538e21c3..8ef26ef464da9 100644 --- a/contrib/llvm/tools/clang/lib/Format/BreakableToken.h +++ b/contrib/llvm/tools/clang/lib/Format/BreakableToken.h @@ -33,19 +33,32 @@ bool switchesFormatting(const FormatToken &Token); struct FormatStyle; -/// \brief Base class for strategies on how to break tokens. +/// \brief Base class for tokens / ranges of tokens that can allow breaking +/// within the tokens - for example, to avoid whitespace beyond the column +/// limit, or to reflow text. /// -/// This is organised around the concept of a \c Split, which is a whitespace -/// range that signifies a position of the content of a token where a -/// reformatting might be done. Operating with splits is divided into 3 -/// operations: +/// Generally, a breakable token consists of logical lines, addressed by a line +/// index. For example, in a sequence of line comments, each line comment is its +/// own logical line; similarly, for a block comment, each line in the block +/// comment is on its own logical line. +/// +/// There are two methods to compute the layout of the token: +/// - getRangeLength measures the number of columns needed for a range of text +/// within a logical line, and +/// - getContentStartColumn returns the start column at which we want the +/// content of a logical line to start (potentially after introducing a line +/// break). +/// +/// The mechanism to adapt the layout of the breakable token is organised +/// around the concept of a \c Split, which is a whitespace range that signifies +/// a position of the content of a token where a reformatting might be done. +/// +/// Operating with splits is divided into two operations: /// - getSplit, for finding a split starting at a position, -/// - getLineLengthAfterSplit, for calculating the size in columns of the rest -/// of the content after a split has been used for breaking, and /// - insertBreak, for executing the split using a whitespace manager. /// /// There is a pair of operations that are used to compress a long whitespace -/// range with a single space if that will bring the line lenght under the +/// range with a single space if that will bring the line length under the /// column limit: /// - getLineLengthAfterCompression, for calculating the size in columns of the /// line after a whitespace range has been compressed, and @@ -56,16 +69,23 @@ struct FormatStyle; /// For tokens where the whitespace before each line needs to be also /// reformatted, for example for tokens supporting reflow, there are analogous /// operations that might be executed before the main line breaking occurs: -/// - getSplitBefore, for finding a split such that the content preceding it +/// - getReflowSplit, for finding a split such that the content preceding it /// needs to be specially reflown, -/// - getLineLengthAfterSplitBefore, for calculating the line length in columns -/// of the remainder of the content after the beginning of the content has -/// been reformatted, and -/// - replaceWhitespaceBefore, for executing the reflow using a whitespace +/// - reflow, for executing the split using a whitespace manager, +/// - introducesBreakBefore, for checking if reformatting the beginning +/// of the content introduces a line break before it, +/// - adaptStartOfLine, for executing the reflow using a whitespace /// manager. /// -/// FIXME: The interface seems set in stone, so we might want to just pull the -/// strategy into the class, instead of controlling it from the outside. +/// For tokens that require the whitespace after the last line to be +/// reformatted, for example in multiline jsdoc comments that require the +/// trailing '*/' to be on a line of itself, there are analogous operations +/// that might be executed after the last line has been reformatted: +/// - getSplitAfterLastLine, for finding a split after the last line that needs +/// to be reflown, +/// - replaceWhitespaceAfterLastLine, for executing the reflow using a +/// whitespace manager. +/// class BreakableToken { public: /// \brief Contains starting character index and length of split. @@ -76,73 +96,122 @@ public: /// \brief Returns the number of lines in this token in the original code. virtual unsigned getLineCount() const = 0; - /// \brief Returns the number of columns required to format the piece of line - /// at \p LineIndex, from byte offset \p TailOffset with length \p Length. + /// \brief Returns the number of columns required to format the text in the + /// byte range [\p Offset, \p Offset \c + \p Length). + /// + /// \p Offset is the byte offset from the start of the content of the line + /// at \p LineIndex. + /// + /// \p StartColumn is the column at which the text starts in the formatted + /// file, needed to compute tab stops correctly. + virtual unsigned getRangeLength(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const = 0; + + /// \brief Returns the number of columns required to format the text following + /// the byte \p Offset in the line \p LineIndex, including potentially + /// unbreakable sequences of tokens following after the end of the token. + /// + /// \p Offset is the byte offset from the start of the content of the line + /// at \p LineIndex. + /// + /// \p StartColumn is the column at which the text starts in the formatted + /// file, needed to compute tab stops correctly. + /// + /// For breakable tokens that never use extra space at the end of a line, this + /// is equivalent to getRangeLength with a Length of StringRef::npos. + virtual unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, + unsigned StartColumn) const { + return getRangeLength(LineIndex, Offset, StringRef::npos, StartColumn); + } + + /// \brief Returns the column at which content in line \p LineIndex starts, + /// assuming no reflow. /// - /// Note that previous breaks are not taken into account. \p TailOffset is - /// always specified from the start of the (original) line. - /// \p Length can be set to StringRef::npos, which means "to the end of line". - virtual unsigned - getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const = 0; + /// If \p Break is true, returns the column at which the line should start + /// after the line break. + /// If \p Break is false, returns the column at which the line itself will + /// start. + virtual unsigned getContentStartColumn(unsigned LineIndex, + bool Break) const = 0; /// \brief Returns a range (offset, length) at which to break the line at /// \p LineIndex, if previously broken at \p TailOffset. If possible, do not - /// violate \p ColumnLimit. + /// violate \p ColumnLimit, assuming the text starting at \p TailOffset in + /// the token is formatted starting at ContentStartColumn in the reformatted + /// file. virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, - unsigned ColumnLimit, + unsigned ColumnLimit, unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const = 0; /// \brief Emits the previously retrieved \p Split via \p Whitespaces. virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) = 0; + WhitespaceManager &Whitespaces) const = 0; - /// \brief Returns the number of columns required to format the piece of line - /// at \p LineIndex, from byte offset \p TailOffset after the whitespace range - /// \p Split has been compressed into a single space. - unsigned getLineLengthAfterCompression(unsigned RemainingTokenColumns, - Split Split) const; + /// \brief Returns the number of columns needed to format + /// \p RemainingTokenColumns, assuming that Split is within the range measured + /// by \p RemainingTokenColumns, and that the whitespace in Split is reduced + /// to a single space. + unsigned getLengthAfterCompression(unsigned RemainingTokenColumns, + Split Split) const; /// \brief Replaces the whitespace range described by \p Split with a single /// space. virtual void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) = 0; + WhitespaceManager &Whitespaces) const = 0; - /// \brief Returns a whitespace range (offset, length) of the content at - /// \p LineIndex such that the content preceding this range needs to be - /// reformatted before any breaks are made to this line. + /// \brief Returns whether the token supports reflowing text. + virtual bool supportsReflow() const { return false; } + + /// \brief Returns a whitespace range (offset, length) of the content at \p + /// LineIndex such that the content of that line is reflown to the end of the + /// previous one. /// - /// \p PreviousEndColumn is the end column of the previous line after - /// formatting. + /// Returning (StringRef::npos, 0) indicates reflowing is not possible. /// - /// A result having offset == StringRef::npos means that no piece of the line - /// needs to be reformatted before any breaks are made. - virtual Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn, - unsigned ColumnLimit, + /// The range will include any whitespace preceding the specified line's + /// content. + /// + /// If the split is not contained within one token, for example when reflowing + /// line comments, returns (0, <length>). + virtual Split getReflowSplit(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { return Split(StringRef::npos, 0); } - /// \brief Returns the number of columns required to format the piece of line - /// at \p LineIndex after the content preceding the whitespace range specified - /// \p SplitBefore has been reformatted, but before any breaks are made to - /// this line. - virtual unsigned getLineLengthAfterSplitBefore(unsigned LineIndex, - unsigned TailOffset, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - Split SplitBefore) const { - return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); + /// \brief Reflows the current line into the end of the previous one. + virtual void reflow(unsigned LineIndex, + WhitespaceManager &Whitespaces) const {} + + /// \brief Returns whether there will be a line break at the start of the + /// token. + virtual bool introducesBreakBeforeToken() const { + return false; } /// \brief Replaces the whitespace between \p LineIndex-1 and \p LineIndex. - /// Performs a reformatting of the content at \p LineIndex preceding the - /// whitespace range \p SplitBefore. - virtual void replaceWhitespaceBefore(unsigned LineIndex, - unsigned PreviousEndColumn, - unsigned ColumnLimit, Split SplitBefore, - WhitespaceManager &Whitespaces) {} + virtual void adaptStartOfLine(unsigned LineIndex, + WhitespaceManager &Whitespaces) const {} + + /// \brief Returns a whitespace range (offset, length) of the content at + /// the last line that needs to be reformatted after the last line has been + /// reformatted. + /// + /// A result having offset == StringRef::npos means that no reformat is + /// necessary. + virtual Split getSplitAfterLastLine(unsigned TailOffset) const { + return Split(StringRef::npos, 0); + } + + /// \brief Replaces the whitespace from \p SplitAfterLastLine on the last line + /// after the last line has been formatted by performing a reformatting. + void replaceWhitespaceAfterLastLine(unsigned TailOffset, + Split SplitAfterLastLine, + WhitespaceManager &Whitespaces) const { + insertBreak(getLineCount() - 1, TailOffset, SplitAfterLastLine, + Whitespaces); + } /// \brief Updates the next token of \p State to the next token after this /// one. This can be used when this token manages a set of underlying tokens @@ -161,32 +230,7 @@ protected: const FormatStyle &Style; }; -/// \brief Base class for single line tokens that can be broken. -/// -/// \c getSplit() needs to be implemented by child classes. -class BreakableSingleLineToken : public BreakableToken { -public: - unsigned getLineCount() const override; - unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const override; - -protected: - BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn, - StringRef Prefix, StringRef Postfix, - bool InPPDirective, encoding::Encoding Encoding, - const FormatStyle &Style); - - // The column in which the token starts. - unsigned StartColumn; - // The prefix a line needs after a break in the token. - StringRef Prefix; - // The postfix a line needs before introducing a break. - StringRef Postfix; - // The token text excluding the prefix and postfix. - StringRef Line; -}; - -class BreakableStringLiteral : public BreakableSingleLineToken { +class BreakableStringLiteral : public BreakableToken { public: /// \brief Creates a breakable token for a single line string literal. /// @@ -198,11 +242,32 @@ public: const FormatStyle &Style); Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, + unsigned ReflowColumn, llvm::Regex &CommentPragmasRegex) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) override; + WhitespaceManager &Whitespaces) const override; void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) override {} + WhitespaceManager &Whitespaces) const override {} + unsigned getLineCount() const override; + unsigned getRangeLength(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const override; + unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, + unsigned StartColumn) const override; + unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; + +protected: + // The column in which the token starts. + unsigned StartColumn; + // The prefix a line needs after a break in the token. + StringRef Prefix; + // The postfix a line needs before introducing a break. + StringRef Postfix; + // The token text excluding the prefix and postfix. + StringRef Line; + // Length of the sequence of tokens after this string literal that cannot + // contain line breaks. + unsigned UnbreakableTailLength; }; class BreakableComment : public BreakableToken { @@ -216,21 +281,15 @@ protected: const FormatStyle &Style); public: + bool supportsReflow() const override { return true; } unsigned getLineCount() const override; Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, + unsigned ReflowColumn, llvm::Regex &CommentPragmasRegex) const override; void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) override; + WhitespaceManager &Whitespaces) const override; protected: - virtual unsigned getContentStartColumn(unsigned LineIndex, - unsigned TailOffset) const = 0; - - // Returns a split that divides Text into a left and right parts, such that - // the left part is suitable for reflowing after PreviousEndColumn. - Split getReflowSplit(StringRef Text, StringRef ReflowPrefix, - unsigned PreviousEndColumn, unsigned ColumnLimit) const; - // Returns the token containing the line at LineIndex. const FormatToken &tokenAt(unsigned LineIndex) const; @@ -289,21 +348,23 @@ public: bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style); - unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const override; + unsigned getRangeLength(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const override; + unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, + unsigned StartColumn) const override; + unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) override; - Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn, - unsigned ColumnLimit, + WhitespaceManager &Whitespaces) const override; + Split getReflowSplit(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override; - unsigned getLineLengthAfterSplitBefore(unsigned LineIndex, - unsigned TailOffset, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - Split SplitBefore) const override; - void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn, - unsigned ColumnLimit, Split SplitBefore, - WhitespaceManager &Whitespaces) override; + void reflow(unsigned LineIndex, + WhitespaceManager &Whitespaces) const override; + bool introducesBreakBeforeToken() const override; + void adaptStartOfLine(unsigned LineIndex, + WhitespaceManager &Whitespaces) const override; + Split getSplitAfterLastLine(unsigned TailOffset) const override; + bool mayReflow(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override; @@ -318,14 +379,6 @@ private: // considered part of the text). void adjustWhitespace(unsigned LineIndex, int IndentDelta); - // Computes the end column if the full Content from LineIndex gets reflown - // after PreviousEndColumn. - unsigned getReflownColumn(StringRef Content, unsigned LineIndex, - unsigned PreviousEndColumn) const; - - unsigned getContentStartColumn(unsigned LineIndex, - unsigned TailOffset) const override; - // The column at which the text of a broken line should start. // Note that an optional decoration would go before that column. // IndentAtLineBreak is a uniform position for all lines in a block comment, @@ -348,6 +401,14 @@ private: // If this block comment has decorations, this is the column of the start of // the decorations. unsigned DecorationColumn; + + // If true, make sure that the opening '/**' and the closing '*/' ends on a + // line of itself. Styles like jsdoc require this for multiline comments. + bool DelimitersOnNewline; + + // Length of the sequence of tokens after this string literal that cannot + // contain line breaks. + unsigned UnbreakableTailLength; }; class BreakableLineCommentSection : public BreakableComment { @@ -357,29 +418,23 @@ public: bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style); - unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, - StringRef::size_type Length) const override; + unsigned getRangeLength(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length, + unsigned StartColumn) const override; + unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - WhitespaceManager &Whitespaces) override; - Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn, - unsigned ColumnLimit, + WhitespaceManager &Whitespaces) const override; + Split getReflowSplit(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override; - unsigned getLineLengthAfterSplitBefore(unsigned LineIndex, - unsigned TailOffset, - unsigned PreviousEndColumn, - unsigned ColumnLimit, - Split SplitBefore) const override; - void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn, - unsigned ColumnLimit, Split SplitBefore, - WhitespaceManager &Whitespaces) override; + void reflow(unsigned LineIndex, + WhitespaceManager &Whitespaces) const override; + void adaptStartOfLine(unsigned LineIndex, + WhitespaceManager &Whitespaces) const override; void updateNextToken(LineState &State) const override; bool mayReflow(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override; private: - unsigned getContentStartColumn(unsigned LineIndex, - unsigned TailOffset) const override; - // OriginalPrefix[i] contains the original prefix of line i, including // trailing whitespace before the start of the content. The indentation // preceding the prefix is not included. diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp index 3bf1cd8f7c131..a3d38b244c5c1 100644 --- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp @@ -12,8 +12,9 @@ /// //===----------------------------------------------------------------------===// -#include "BreakableToken.h" #include "ContinuationIndenter.h" +#include "BreakableToken.h" +#include "FormatInternal.h" #include "WhitespaceManager.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" @@ -76,6 +77,53 @@ static bool opensProtoMessageField(const FormatToken &LessTok, (LessTok.Previous && LessTok.Previous->is(tok::equal)))); } +// Returns the delimiter of a raw string literal, or None if TokenText is not +// the text of a raw string literal. The delimiter could be the empty string. +// For example, the delimiter of R"deli(cont)deli" is deli. +static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) { + if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'. + || !TokenText.startswith("R\"") || !TokenText.endswith("\"")) + return None; + + // A raw string starts with 'R"<delimiter>(' and delimiter is ascii and has + // size at most 16 by the standard, so the first '(' must be among the first + // 19 bytes. + size_t LParenPos = TokenText.substr(0, 19).find_first_of('('); + if (LParenPos == StringRef::npos) + return None; + StringRef Delimiter = TokenText.substr(2, LParenPos - 2); + + // Check that the string ends in ')Delimiter"'. + size_t RParenPos = TokenText.size() - Delimiter.size() - 2; + if (TokenText[RParenPos] != ')') + return None; + if (!TokenText.substr(RParenPos + 1).startswith(Delimiter)) + return None; + return Delimiter; +} + +RawStringFormatStyleManager::RawStringFormatStyleManager( + const FormatStyle &CodeStyle) { + for (const auto &RawStringFormat : CodeStyle.RawStringFormats) { + FormatStyle Style; + if (!getPredefinedStyle(RawStringFormat.BasedOnStyle, + RawStringFormat.Language, &Style)) { + Style = getLLVMStyle(); + Style.Language = RawStringFormat.Language; + } + Style.ColumnLimit = CodeStyle.ColumnLimit; + DelimiterStyle.insert({RawStringFormat.Delimiter, Style}); + } +} + +llvm::Optional<FormatStyle> +RawStringFormatStyleManager::get(StringRef Delimiter) const { + auto It = DelimiterStyle.find(Delimiter); + if (It == DelimiterStyle.end()) + return None; + return It->second; +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -85,20 +133,32 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr), Whitespaces(Whitespaces), Encoding(Encoding), BinPackInconclusiveFunctions(BinPackInconclusiveFunctions), - CommentPragmasRegex(Style.CommentPragmas) {} + CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style) {} LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, + unsigned FirstStartColumn, const AnnotatedLine *Line, bool DryRun) { LineState State; State.FirstIndent = FirstIndent; - State.Column = FirstIndent; + if (FirstStartColumn && Line->First->NewlinesBefore == 0) + State.Column = FirstStartColumn; + else + State.Column = FirstIndent; + // With preprocessor directive indentation, the line starts on column 0 + // since it's indented after the hash, but FirstIndent is set to the + // preprocessor indent. + if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash && + (Line->Type == LT_PreprocessorDirective || + Line->Type == LT_ImportStatement)) + State.Column = 0; State.Line = Line; State.NextToken = Line->First; State.Stack.push_back(ParenState(FirstIndent, FirstIndent, /*AvoidBinPacking=*/false, /*NoLineBreak=*/false)); State.LineContainsContinuedForLoopSection = false; + State.NoContinuation = false; State.StartOfStringLiteral = 0; State.StartOfLineLevel = 0; State.LowestLevelOnLine = 0; @@ -120,9 +180,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) { const FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; assert(&Previous == Current.Previous); - if (!Current.CanBreakBefore && - !(State.Stack.back().BreakBeforeClosingBrace && - Current.closesBlockOrBlockTypeList(Style))) + if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace && + Current.closesBlockOrBlockTypeList(Style))) return false; // The opening "{" of a braced list has to be on the same line as the first // element if it is nested in another braced init list or function call. @@ -264,7 +323,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // We need special cases for ">>" which we have split into two ">" while // lexing in order to make template parsing easier. bool IsComparison = (Previous.getPrecedence() == prec::Relational || - Previous.getPrecedence() == prec::Equality) && + Previous.getPrecedence() == prec::Equality || + Previous.getPrecedence() == prec::Spaceship) && Previous.Previous && Previous.Previous->isNot(TT_BinaryOperator); // For >>. bool LHSIsBinaryExpr = @@ -316,6 +376,12 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { Previous.TokenText == "\'\\n\'")))) return true; + if (Previous.is(TT_BlockComment) && Previous.IsMultiline) + return true; + + if (State.NoContinuation) + return true; + return false; } @@ -325,6 +391,8 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, const FormatToken &Current = *State.NextToken; assert(!State.Stack.empty()); + State.NoContinuation = false; + if ((Current.is(TT_ImplicitStringLiteral) && (Current.Previous->Tok.getIdentifierInfo() == nullptr || Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() == @@ -376,9 +444,25 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces; + // Indent preprocessor directives after the hash if required. + int PPColumnCorrection = 0; + if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash && + Previous.is(tok::hash) && State.FirstIndent > 0 && + (State.Line->Type == LT_PreprocessorDirective || + State.Line->Type == LT_ImportStatement)) { + Spaces += State.FirstIndent; + + // For preprocessor indent with tabs, State.Column will be 1 because of the + // hash. This causes second-level indents onward to have an extra space + // after the tabs. We avoid this misalignment by subtracting 1 from the + // column value passed to replaceWhitespace(). + if (Style.UseTab != FormatStyle::UT_Never) + PPColumnCorrection = -1; + } + if (!DryRun) Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces, - State.Column + Spaces); + State.Column + Spaces + PPColumnCorrection); // If "BreakBeforeInheritanceComma" mode, don't break within the inheritance // declaration unless there is multiple inheritance. @@ -405,9 +489,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak && Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) && State.Column > getNewLineColumn(State) && - (!Previous.Previous || - !Previous.Previous->isOneOf(tok::kw_for, tok::kw_while, - tok::kw_switch)) && + (!Previous.Previous || !Previous.Previous->isOneOf( + tok::kw_for, tok::kw_while, tok::kw_switch)) && // Don't do this for simple (no expressions) one-argument function calls // as that feels like needlessly wasting whitespace, e.g.: // @@ -454,7 +537,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, (P->is(TT_ConditionalExpr) && P->is(tok::colon))) && !P->isOneOf(TT_OverloadedOperator, TT_CtorInitializerComma) && P->getPrecedence() != prec::Assignment && - P->getPrecedence() != prec::Relational) { + P->getPrecedence() != prec::Relational && + P->getPrecedence() != prec::Spaceship) { bool BreakBeforeOperator = P->MustBreakBefore || P->is(tok::lessless) || (P->is(TT_BinaryOperator) && @@ -619,8 +703,18 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { + unsigned MaxEmptyLinesToKeep = Style.MaxEmptyLinesToKeep + 1; + if (Current.is(tok::r_brace) && Current.MatchingParen && + // Only strip trailing empty lines for l_braces that have children, i.e. + // for function expressions (lambdas, arrows, etc). + !Current.MatchingParen->Children.empty()) { + // lambdas and arrow functions are expressions, thus their r_brace is not + // on its own line, and thus not covered by UnwrappedLineFormatter's logic + // about removing empty lines on closing blocks. Special case them here. + MaxEmptyLinesToKeep = 1; + } unsigned Newlines = std::max( - 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); + 1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep)); bool ContinuePPDirective = State.Line->InPPDirective && State.Line->Type != LT_ImportStatement; Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, @@ -661,9 +755,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - opensProtoMessageField(*PreviousNonComment, Style) || - (PreviousNonComment->is(TT_TemplateString) && - PreviousNonComment->opensScope()))) + opensProtoMessageField(*PreviousNonComment, Style))) State.Stack.back().BreakBeforeClosingBrace = true; if (State.Stack.back().AvoidBinPacking) { @@ -731,7 +823,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; if (Current.is(tok::identifier) && Current.Next && - Current.Next->is(TT_DictLiteral)) + (Current.Next->is(TT_DictLiteral) || + ((Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && + Current.Next->isOneOf(TT_TemplateOpener, tok::l_brace)))) return State.Stack.back().Indent; if (NextNonComment->is(TT_ObjCStringLiteral) && State.StartOfStringLiteral != 0) @@ -871,8 +966,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, // Next(...) // ^ line up here. State.Stack.back().Indent = - State.Column + (Style.BreakConstructorInitializers == - FormatStyle::BCIS_BeforeComma ? 0 : 2); + State.Column + + (Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma + ? 0 + : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; @@ -884,7 +981,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.FirstIndent + Style.ConstructorInitializerIndentWidth; State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) - State.Stack.back().AvoidBinPacking = true; + State.Stack.back().AvoidBinPacking = true; } if (Current.is(TT_InheritanceColon)) State.Stack.back().Indent = @@ -912,8 +1009,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Stack[i].NoLineBreak = true; State.Stack[State.Stack.size() - 2].NestedBlockInlined = false; } - if (Previous && (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) || - Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) && + if (Previous && + (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) || + Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) && !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { State.Stack.back().NestedBlockInlined = !Newline && @@ -922,13 +1020,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, moveStatePastFakeLParens(State, Newline); moveStatePastScopeCloser(State); - if (Current.is(TT_TemplateString) && Current.opensScope()) - State.Stack.back().LastSpace = - (Current.IsMultiline ? Current.LastLineColumnWidth - : State.Column + Current.ColumnWidth) - - strlen("${"); - bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak && - !State.Stack.back().NoLineBreakInOperand; + bool AllowBreak = !State.Stack.back().NoLineBreak && + !State.Stack.back().NoLineBreakInOperand; moveStatePastScopeOpener(State, Newline); moveStatePastFakeRParens(State); @@ -942,13 +1035,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Column += Current.ColumnWidth; State.NextToken = State.NextToken->Next; - unsigned Penalty = 0; - if (CanBreakProtrudingToken) - Penalty = breakProtrudingToken(Current, State, DryRun); - if (State.Column > getColumnLimit(State)) { - unsigned ExcessCharacters = State.Column - getColumnLimit(State); - Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; - } + + unsigned Penalty = + handleEndOfLine(Current, State, DryRun, AllowBreak); if (Current.Role) Current.Role->formatFromToken(State, this, DryRun); @@ -1072,14 +1161,13 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, bool EndsInComma = Current.MatchingParen && Current.MatchingParen->Previous && Current.MatchingParen->Previous->is(tok::comma); - AvoidBinPacking = - EndsInComma || Current.is(TT_DictLiteral) || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto || - !Style.BinPackArguments || - (NextNoComment && - NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, - TT_DesignatedInitializerLSquare)); + AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto || + !Style.BinPackArguments || + (NextNoComment && + NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, + TT_DesignatedInitializerLSquare)); BreakBeforeParameter = EndsInComma; if (Current.ParameterCount > 1) NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); @@ -1098,18 +1186,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, LastSpace = std::max(LastSpace, State.Stack.back().Indent); } - // JavaScript template strings are special as we always want to indent - // nested expressions relative to the ${}. Otherwise, this can create quite - // a mess. - if (Current.is(TT_TemplateString)) { - unsigned Column = Current.IsMultiline - ? Current.LastLineColumnWidth - : State.Column + Current.ColumnWidth; - NewIndent = Column; - LastSpace = Column; - NestedBlockIndent = Column; - } - bool EndsInComma = Current.MatchingParen && Current.MatchingParen->getPreviousNonComment() && @@ -1200,11 +1276,93 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) { State.Stack.back().BreakBeforeParameter = true; } -unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, - LineState &State) { - if (!Current.IsMultiline) +static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn, + unsigned TabWidth, + encoding::Encoding Encoding) { + size_t LastNewlinePos = Text.find_last_of("\n"); + if (LastNewlinePos == StringRef::npos) { + return StartColumn + + encoding::columnWidthWithTabs(Text, StartColumn, TabWidth, Encoding); + } else { + return encoding::columnWidthWithTabs(Text.substr(LastNewlinePos), + /*StartColumn=*/0, TabWidth, Encoding); + } +} + +unsigned ContinuationIndenter::reformatRawStringLiteral( + const FormatToken &Current, LineState &State, + const FormatStyle &RawStringStyle, bool DryRun) { + unsigned StartColumn = State.Column - Current.ColumnWidth; + auto Delimiter = *getRawStringDelimiter(Current.TokenText); + // The text of a raw string is between the leading 'R"delimiter(' and the + // trailing 'delimiter)"'. + unsigned PrefixSize = 3 + Delimiter.size(); + unsigned SuffixSize = 2 + Delimiter.size(); + + // The first start column is the column the raw text starts. + unsigned FirstStartColumn = StartColumn + PrefixSize; + + // The next start column is the intended indentation a line break inside + // the raw string at level 0. It is determined by the following rules: + // - if the content starts on newline, it is one level more than the current + // indent, and + // - if the content does not start on a newline, it is the first start + // column. + // These rules have the advantage that the formatted content both does not + // violate the rectangle rule and visually flows within the surrounding + // source. + bool ContentStartsOnNewline = Current.TokenText[PrefixSize] == '\n'; + unsigned NextStartColumn = ContentStartsOnNewline + ? State.Stack.back().Indent + Style.IndentWidth + : FirstStartColumn; + + // The last start column is the column the raw string suffix starts if it is + // put on a newline. + // The last start column is the intended indentation of the raw string postfix + // if it is put on a newline. It is determined by the following rules: + // - if the raw string prefix starts on a newline, it is the column where + // that raw string prefix starts, and + // - if the raw string prefix does not start on a newline, it is the current + // indent. + unsigned LastStartColumn = Current.NewlinesBefore + ? FirstStartColumn - PrefixSize + : State.Stack.back().Indent; + + std::string RawText = + Current.TokenText.substr(PrefixSize).drop_back(SuffixSize); + + std::pair<tooling::Replacements, unsigned> Fixes = internal::reformat( + RawStringStyle, RawText, {tooling::Range(0, RawText.size())}, + FirstStartColumn, NextStartColumn, LastStartColumn, "<stdin>", + /*Status=*/nullptr); + + auto NewCode = applyAllReplacements(RawText, Fixes.first); + tooling::Replacements NoFixes; + if (!NewCode) { + State.Column += Current.ColumnWidth; return 0; + } + if (!DryRun) { + SourceLocation OriginLoc = + Current.Tok.getLocation().getLocWithOffset(PrefixSize); + for (const tooling::Replacement &Fix : Fixes.first) { + auto Err = Whitespaces.addReplacement(tooling::Replacement( + SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()), + Fix.getLength(), Fix.getReplacementText())); + if (Err) { + llvm::errs() << "Failed to reformat raw string: " + << llvm::toString(std::move(Err)) << "\n"; + } + } + } + unsigned RawLastLineEndColumn = getLastLineEndColumn( + *NewCode, FirstStartColumn, Style.TabWidth, Encoding); + State.Column = RawLastLineEndColumn + SuffixSize; + return Fixes.second; +} +unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, + LineState &State) { // Break before further function parameters on all levels. for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; @@ -1219,33 +1377,85 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, return 0; } -unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, - LineState &State, - bool DryRun) { - // Don't break multi-line tokens other than block comments. Instead, just - // update the state. - if (Current.isNot(TT_BlockComment) && Current.IsMultiline) - return addMultilineToken(Current, State); +unsigned ContinuationIndenter::handleEndOfLine(const FormatToken &Current, + LineState &State, bool DryRun, + bool AllowBreak) { + unsigned Penalty = 0; + // Compute the raw string style to use in case this is a raw string literal + // that can be reformatted. + auto RawStringStyle = getRawStringStyle(Current, State); + if (RawStringStyle) { + Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun); + } else if (Current.IsMultiline && Current.isNot(TT_BlockComment)) { + // Don't break multi-line tokens other than block comments and raw string + // literals. Instead, just update the state. + Penalty = addMultilineToken(Current, State); + } else if (State.Line->Type != LT_ImportStatement) { + // We generally don't break import statements. + LineState OriginalState = State; - // Don't break implicit string literals or import statements. - if (Current.is(TT_ImplicitStringLiteral) || - State.Line->Type == LT_ImportStatement) - return 0; + // Whether we force the reflowing algorithm to stay strictly within the + // column limit. + bool Strict = false; + // Whether the first non-strict attempt at reflowing did intentionally + // exceed the column limit. + bool Exceeded = false; + std::tie(Penalty, Exceeded) = breakProtrudingToken( + Current, State, AllowBreak, /*DryRun=*/true, Strict); + if (Exceeded) { + // If non-strict reflowing exceeds the column limit, try whether strict + // reflowing leads to an overall lower penalty. + LineState StrictState = OriginalState; + unsigned StrictPenalty = + breakProtrudingToken(Current, StrictState, AllowBreak, + /*DryRun=*/true, /*Strict=*/true) + .first; + Strict = StrictPenalty <= Penalty; + if (Strict) { + Penalty = StrictPenalty; + State = StrictState; + } + } + if (!DryRun) { + // If we're not in dry-run mode, apply the changes with the decision on + // strictness made above. + breakProtrudingToken(Current, OriginalState, AllowBreak, /*DryRun=*/false, + Strict); + } + } + if (State.Column > getColumnLimit(State)) { + unsigned ExcessCharacters = State.Column - getColumnLimit(State); + Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; + } + return Penalty; +} - if (!Current.isStringLiteral() && !Current.is(tok::comment)) - return 0; +llvm::Optional<FormatStyle> +ContinuationIndenter::getRawStringStyle(const FormatToken &Current, + const LineState &State) { + if (!Current.isStringLiteral()) + return None; + auto Delimiter = getRawStringDelimiter(Current.TokenText); + if (!Delimiter) + return None; + auto RawStringStyle = RawStringFormats.get(*Delimiter); + if (!RawStringStyle) + return None; + RawStringStyle->ColumnLimit = getColumnLimit(State); + return RawStringStyle; +} - std::unique_ptr<BreakableToken> Token; +std::unique_ptr<BreakableToken> ContinuationIndenter::createBreakableToken( + const FormatToken &Current, LineState &State, bool AllowBreak) { unsigned StartColumn = State.Column - Current.ColumnWidth; - unsigned ColumnLimit = getColumnLimit(State); - if (Current.isStringLiteral()) { // FIXME: String literal breaking is currently disabled for Java and JS, as // it requires strings to be merged using "+" which we don't support. if (Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript || - !Style.BreakStringLiterals) - return 0; + !Style.BreakStringLiterals || + !AllowBreak) + return nullptr; // Don't break string literals inside preprocessor directives (except for // #define directives, as their contents are stored in separate lines and @@ -1253,11 +1463,11 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, // This way we avoid breaking code with line directives and unknown // preprocessor directives that contain long string literals. if (State.Line->Type == LT_PreprocessorDirective) - return 0; + return nullptr; // Exempts unterminated string literals from line breaking. The user will // likely want to terminate the string before any line breaking is done. if (Current.IsUnterminatedLiteral) - return 0; + return nullptr; StringRef Text = Current.TokenText; StringRef Prefix; @@ -1272,114 +1482,359 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, Text.startswith(Prefix = "u8\"") || Text.startswith(Prefix = "L\""))) || (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) { - Token.reset(new BreakableStringLiteral(Current, StartColumn, Prefix, - Postfix, State.Line->InPPDirective, - Encoding, Style)); - } else { - return 0; + return llvm::make_unique<BreakableStringLiteral>( + Current, StartColumn, Prefix, Postfix, State.Line->InPPDirective, + Encoding, Style); } } else if (Current.is(TT_BlockComment)) { - if (!Current.isTrailingComment() || !Style.ReflowComments || + if (!Style.ReflowComments || // If a comment token switches formatting, like // /* clang-format on */, we don't want to break it further, // but we may still want to adjust its indentation. - switchesFormatting(Current)) - return addMultilineToken(Current, State); - Token.reset(new BreakableBlockComment( + switchesFormatting(Current)) { + return nullptr; + } + return llvm::make_unique<BreakableBlockComment>( Current, StartColumn, Current.OriginalColumn, !Current.Previous, - State.Line->InPPDirective, Encoding, Style)); + State.Line->InPPDirective, Encoding, Style); } else if (Current.is(TT_LineComment) && (Current.Previous == nullptr || Current.Previous->isNot(TT_ImplicitStringLiteral))) { if (!Style.ReflowComments || CommentPragmasRegex.match(Current.TokenText.substr(2)) || switchesFormatting(Current)) - return 0; - Token.reset(new BreakableLineCommentSection( + return nullptr; + return llvm::make_unique<BreakableLineCommentSection>( Current, StartColumn, Current.OriginalColumn, !Current.Previous, - /*InPPDirective=*/false, Encoding, Style)); + /*InPPDirective=*/false, Encoding, Style); + } + return nullptr; +} + +std::pair<unsigned, bool> +ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, + LineState &State, bool AllowBreak, + bool DryRun, bool Strict) { + std::unique_ptr<const BreakableToken> Token = + createBreakableToken(Current, State, AllowBreak); + if (!Token) + return {0, false}; + assert(Token->getLineCount() > 0); + unsigned ColumnLimit = getColumnLimit(State); + if (Current.is(TT_LineComment)) { // We don't insert backslashes when breaking line comments. ColumnLimit = Style.ColumnLimit; - } else { - return 0; } if (Current.UnbreakableTailLength >= ColumnLimit) - return 0; - - unsigned RemainingSpace = ColumnLimit - Current.UnbreakableTailLength; - bool BreakInserted = false; + return {0, false}; + // ColumnWidth was already accounted into State.Column before calling + // breakProtrudingToken. + unsigned StartColumn = State.Column - Current.ColumnWidth; + unsigned NewBreakPenalty = Current.isStringLiteral() + ? Style.PenaltyBreakString + : Style.PenaltyBreakComment; + // Stores whether we intentionally decide to let a line exceed the column + // limit. + bool Exceeded = false; + // Stores whether we introduce a break anywhere in the token. + bool BreakInserted = Token->introducesBreakBeforeToken(); + // Store whether we inserted a new line break at the end of the previous + // logical line. + bool NewBreakBefore = false; // We use a conservative reflowing strategy. Reflow starts after a line is // broken or the corresponding whitespace compressed. Reflow ends as soon as a // line that doesn't get reflown with the previous line is reached. - bool ReflowInProgress = false; + bool Reflow = false; + // Keep track of where we are in the token: + // Where we are in the content of the current logical line. + unsigned TailOffset = 0; + // The column number we're currently at. + unsigned ContentStartColumn = + Token->getContentStartColumn(0, /*Break=*/false); + // The number of columns left in the current logical line after TailOffset. + unsigned RemainingTokenColumns = + Token->getRemainingLength(0, TailOffset, ContentStartColumn); + // Adapt the start of the token, for example indent. + if (!DryRun) + Token->adaptStartOfLine(0, Whitespaces); + unsigned Penalty = 0; - unsigned RemainingTokenColumns = 0; + DEBUG(llvm::dbgs() << "Breaking protruding token at column " << StartColumn + << ".\n"); for (unsigned LineIndex = 0, EndIndex = Token->getLineCount(); LineIndex != EndIndex; ++LineIndex) { - BreakableToken::Split SplitBefore(StringRef::npos, 0); - if (ReflowInProgress) { - SplitBefore = Token->getSplitBefore(LineIndex, RemainingTokenColumns, - RemainingSpace, CommentPragmasRegex); - } - ReflowInProgress = SplitBefore.first != StringRef::npos; - unsigned TailOffset = - ReflowInProgress ? (SplitBefore.first + SplitBefore.second) : 0; - if (!DryRun) - Token->replaceWhitespaceBefore(LineIndex, RemainingTokenColumns, - RemainingSpace, SplitBefore, Whitespaces); - RemainingTokenColumns = Token->getLineLengthAfterSplitBefore( - LineIndex, TailOffset, RemainingTokenColumns, ColumnLimit, SplitBefore); - while (RemainingTokenColumns > RemainingSpace) { - BreakableToken::Split Split = Token->getSplit( - LineIndex, TailOffset, ColumnLimit, CommentPragmasRegex); + DEBUG(llvm::dbgs() << " Line: " << LineIndex << " (Reflow: " << Reflow + << ")\n"); + NewBreakBefore = false; + // If we did reflow the previous line, we'll try reflowing again. Otherwise + // we'll start reflowing if the current line is broken or whitespace is + // compressed. + bool TryReflow = Reflow; + // Break the current token until we can fit the rest of the line. + while (ContentStartColumn + RemainingTokenColumns > ColumnLimit) { + DEBUG(llvm::dbgs() << " Over limit, need: " + << (ContentStartColumn + RemainingTokenColumns) + << ", space: " << ColumnLimit + << ", reflown prefix: " << ContentStartColumn + << ", offset in line: " << TailOffset << "\n"); + // If the current token doesn't fit, find the latest possible split in the + // current line so that breaking at it will be under the column limit. + // FIXME: Use the earliest possible split while reflowing to correctly + // compress whitespace within a line. + BreakableToken::Split Split = + Token->getSplit(LineIndex, TailOffset, ColumnLimit, + ContentStartColumn, CommentPragmasRegex); if (Split.first == StringRef::npos) { - // The last line's penalty is handled in addNextStateToQueue(). + // No break opportunity - update the penalty and continue with the next + // logical line. if (LineIndex < EndIndex - 1) + // The last line's penalty is handled in addNextStateToQueue(). Penalty += Style.PenaltyExcessCharacter * - (RemainingTokenColumns - RemainingSpace); + (ContentStartColumn + RemainingTokenColumns - ColumnLimit); + DEBUG(llvm::dbgs() << " No break opportunity.\n"); break; } assert(Split.first != 0); - // Check if compressing the whitespace range will bring the line length - // under the limit. If that is the case, we perform whitespace compression - // instead of inserting a line break. - unsigned RemainingTokenColumnsAfterCompression = - Token->getLineLengthAfterCompression(RemainingTokenColumns, Split); - if (RemainingTokenColumnsAfterCompression <= RemainingSpace) { - RemainingTokenColumns = RemainingTokenColumnsAfterCompression; - ReflowInProgress = true; - if (!DryRun) - Token->compressWhitespace(LineIndex, TailOffset, Split, Whitespaces); - break; - } + if (Token->supportsReflow()) { + // Check whether the next natural split point after the current one can + // still fit the line, either because we can compress away whitespace, + // or because the penalty the excess characters introduce is lower than + // the break penalty. + // We only do this for tokens that support reflowing, and thus allow us + // to change the whitespace arbitrarily (e.g. comments). + // Other tokens, like string literals, can be broken on arbitrary + // positions. - unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit( - LineIndex, TailOffset + Split.first + Split.second, StringRef::npos); + // First, compute the columns from TailOffset to the next possible split + // position. + // For example: + // ColumnLimit: | + // // Some text that breaks + // ^ tail offset + // ^-- split + // ^-------- to split columns + // ^--- next split + // ^--------------- to next split columns + unsigned ToSplitColumns = Token->getRangeLength( + LineIndex, TailOffset, Split.first, ContentStartColumn); + DEBUG(llvm::dbgs() << " ToSplit: " << ToSplitColumns << "\n"); + + BreakableToken::Split NextSplit = Token->getSplit( + LineIndex, TailOffset + Split.first + Split.second, ColumnLimit, + ContentStartColumn + ToSplitColumns + 1, CommentPragmasRegex); + // Compute the columns necessary to fit the next non-breakable sequence + // into the current line. + unsigned ToNextSplitColumns = 0; + if (NextSplit.first == StringRef::npos) { + ToNextSplitColumns = Token->getRemainingLength(LineIndex, TailOffset, + ContentStartColumn); + } else { + ToNextSplitColumns = Token->getRangeLength( + LineIndex, TailOffset, + Split.first + Split.second + NextSplit.first, ContentStartColumn); + } + // Compress the whitespace between the break and the start of the next + // unbreakable sequence. + ToNextSplitColumns = + Token->getLengthAfterCompression(ToNextSplitColumns, Split); + DEBUG(llvm::dbgs() << " ContentStartColumn: " << ContentStartColumn + << "\n"); + DEBUG(llvm::dbgs() << " ToNextSplit: " << ToNextSplitColumns << "\n"); + // If the whitespace compression makes us fit, continue on the current + // line. + bool ContinueOnLine = + ContentStartColumn + ToNextSplitColumns <= ColumnLimit; + unsigned ExcessCharactersPenalty = 0; + if (!ContinueOnLine && !Strict) { + // Similarly, if the excess characters' penalty is lower than the + // penalty of introducing a new break, continue on the current line. + ExcessCharactersPenalty = + (ContentStartColumn + ToNextSplitColumns - ColumnLimit) * + Style.PenaltyExcessCharacter; + DEBUG(llvm::dbgs() + << " Penalty excess: " << ExcessCharactersPenalty + << "\n break : " << NewBreakPenalty << "\n"); + if (ExcessCharactersPenalty < NewBreakPenalty) { + Exceeded = true; + ContinueOnLine = true; + } + } + if (ContinueOnLine) { + DEBUG(llvm::dbgs() << " Continuing on line...\n"); + // The current line fits after compressing the whitespace - reflow + // the next line into it if possible. + TryReflow = true; + if (!DryRun) + Token->compressWhitespace(LineIndex, TailOffset, Split, + Whitespaces); + // When we continue on the same line, leave one space between content. + ContentStartColumn += ToSplitColumns + 1; + Penalty += ExcessCharactersPenalty; + TailOffset += Split.first + Split.second; + RemainingTokenColumns = Token->getRemainingLength( + LineIndex, TailOffset, ContentStartColumn); + continue; + } + } + DEBUG(llvm::dbgs() << " Breaking...\n"); + ContentStartColumn = + Token->getContentStartColumn(LineIndex, /*Break=*/true); + unsigned NewRemainingTokenColumns = Token->getRemainingLength( + LineIndex, TailOffset + Split.first + Split.second, + ContentStartColumn); // When breaking before a tab character, it may be moved by a few columns, // but will still be expanded to the next tab stop, so we don't save any // columns. - if (NewRemainingTokenColumns == RemainingTokenColumns) + if (NewRemainingTokenColumns == RemainingTokenColumns) { + // FIXME: Do we need to adjust the penalty? break; - + } assert(NewRemainingTokenColumns < RemainingTokenColumns); + + DEBUG(llvm::dbgs() << " Breaking at: " << TailOffset + Split.first + << ", " << Split.second << "\n"); if (!DryRun) Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); - Penalty += Current.SplitPenalty; - unsigned ColumnsUsed = - Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); - if (ColumnsUsed > ColumnLimit) { - Penalty += Style.PenaltyExcessCharacter * (ColumnsUsed - ColumnLimit); - } + + Penalty += NewBreakPenalty; TailOffset += Split.first + Split.second; RemainingTokenColumns = NewRemainingTokenColumns; - ReflowInProgress = true; BreakInserted = true; + NewBreakBefore = true; + } + // In case there's another line, prepare the state for the start of the next + // line. + if (LineIndex + 1 != EndIndex) { + unsigned NextLineIndex = LineIndex + 1; + if (NewBreakBefore) + // After breaking a line, try to reflow the next line into the current + // one once RemainingTokenColumns fits. + TryReflow = true; + if (TryReflow) { + // We decided that we want to try reflowing the next line into the + // current one. + // We will now adjust the state as if the reflow is successful (in + // preparation for the next line), and see whether that works. If we + // decide that we cannot reflow, we will later reset the state to the + // start of the next line. + Reflow = false; + // As we did not continue breaking the line, RemainingTokenColumns is + // known to fit after ContentStartColumn. Adapt ContentStartColumn to + // the position at which we want to format the next line if we do + // actually reflow. + // When we reflow, we need to add a space between the end of the current + // line and the next line's start column. + ContentStartColumn += RemainingTokenColumns + 1; + // Get the split that we need to reflow next logical line into the end + // of the current one; the split will include any leading whitespace of + // the next logical line. + BreakableToken::Split SplitBeforeNext = + Token->getReflowSplit(NextLineIndex, CommentPragmasRegex); + DEBUG(llvm::dbgs() << " Size of reflown text: " << ContentStartColumn + << "\n Potential reflow split: "); + if (SplitBeforeNext.first != StringRef::npos) { + DEBUG(llvm::dbgs() << SplitBeforeNext.first << ", " + << SplitBeforeNext.second << "\n"); + TailOffset = SplitBeforeNext.first + SplitBeforeNext.second; + // If the rest of the next line fits into the current line below the + // column limit, we can safely reflow. + RemainingTokenColumns = Token->getRemainingLength( + NextLineIndex, TailOffset, ContentStartColumn); + Reflow = true; + if (ContentStartColumn + RemainingTokenColumns > ColumnLimit) { + DEBUG(llvm::dbgs() << " Over limit after reflow, need: " + << (ContentStartColumn + RemainingTokenColumns) + << ", space: " << ColumnLimit + << ", reflown prefix: " << ContentStartColumn + << ", offset in line: " << TailOffset << "\n"); + // If the whole next line does not fit, try to find a point in + // the next line at which we can break so that attaching the part + // of the next line to that break point onto the current line is + // below the column limit. + BreakableToken::Split Split = + Token->getSplit(NextLineIndex, TailOffset, ColumnLimit, + ContentStartColumn, CommentPragmasRegex); + if (Split.first == StringRef::npos) { + DEBUG(llvm::dbgs() << " Did not find later break\n"); + Reflow = false; + } else { + // Check whether the first split point gets us below the column + // limit. Note that we will execute this split below as part of + // the normal token breaking and reflow logic within the line. + unsigned ToSplitColumns = Token->getRangeLength( + NextLineIndex, TailOffset, Split.first, ContentStartColumn); + if (ContentStartColumn + ToSplitColumns > ColumnLimit) { + DEBUG(llvm::dbgs() << " Next split protrudes, need: " + << (ContentStartColumn + ToSplitColumns) + << ", space: " << ColumnLimit); + unsigned ExcessCharactersPenalty = + (ContentStartColumn + ToSplitColumns - ColumnLimit) * + Style.PenaltyExcessCharacter; + if (NewBreakPenalty < ExcessCharactersPenalty) { + Reflow = false; + } + } + } + } + } else { + DEBUG(llvm::dbgs() << "not found.\n"); + } + } + if (!Reflow) { + // If we didn't reflow into the next line, the only space to consider is + // the next logical line. Reset our state to match the start of the next + // line. + TailOffset = 0; + ContentStartColumn = + Token->getContentStartColumn(NextLineIndex, /*Break=*/false); + RemainingTokenColumns = Token->getRemainingLength( + NextLineIndex, TailOffset, ContentStartColumn); + // Adapt the start of the token, for example indent. + if (!DryRun) + Token->adaptStartOfLine(NextLineIndex, Whitespaces); + } else { + // If we found a reflow split and have added a new break before the next + // line, we are going to remove the line break at the start of the next + // logical line. For example, here we'll add a new line break after + // 'text', and subsequently delete the line break between 'that' and + // 'reflows'. + // // some text that + // // reflows + // -> + // // some text + // // that reflows + // When adding the line break, we also added the penalty for it, so we + // need to subtract that penalty again when we remove the line break due + // to reflowing. + if (NewBreakBefore) { + assert(Penalty >= NewBreakPenalty); + Penalty -= NewBreakPenalty; + } + if (!DryRun) + Token->reflow(NextLineIndex, Whitespaces); + } } } - State.Column = RemainingTokenColumns; + BreakableToken::Split SplitAfterLastLine = + Token->getSplitAfterLastLine(TailOffset); + if (SplitAfterLastLine.first != StringRef::npos) { + DEBUG(llvm::dbgs() << "Replacing whitespace after last line.\n"); + if (!DryRun) + Token->replaceWhitespaceAfterLastLine(TailOffset, SplitAfterLastLine, + Whitespaces); + ContentStartColumn = + Token->getContentStartColumn(Token->getLineCount() - 1, /*Break=*/true); + RemainingTokenColumns = Token->getRemainingLength( + Token->getLineCount() - 1, + TailOffset + SplitAfterLastLine.first + SplitAfterLastLine.second, + ContentStartColumn); + } + + State.Column = ContentStartColumn + RemainingTokenColumns - + Current.UnbreakableTailLength; if (BreakInserted) { // If we break the token inside a parameter list, we need to break before @@ -1390,15 +1845,15 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, State.Stack[i].BreakBeforeParameter = true; } - Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString - : Style.PenaltyBreakComment; + if (Current.is(TT_BlockComment)) + State.NoContinuation = true; State.Stack.back().LastSpace = StartColumn; } Token->updateNextToken(State); - return Penalty; + return {Penalty, Exceeded}; } unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const { diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h index 9a06aa6f62672..ded7bfab4267c 100644 --- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h +++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h @@ -20,6 +20,8 @@ #include "FormatToken.h" #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include <map> +#include <tuple> namespace clang { class SourceManager; @@ -27,11 +29,21 @@ class SourceManager; namespace format { class AnnotatedLine; +class BreakableToken; struct FormatToken; struct LineState; struct ParenState; +struct RawStringFormatStyleManager; class WhitespaceManager; +struct RawStringFormatStyleManager { + llvm::StringMap<FormatStyle> DelimiterStyle; + + RawStringFormatStyleManager(const FormatStyle &CodeStyle); + + llvm::Optional<FormatStyle> get(StringRef Delimiter) const; +}; + class ContinuationIndenter { public: /// \brief Constructs a \c ContinuationIndenter to format \p Line starting in @@ -44,9 +56,11 @@ public: bool BinPackInconclusiveFunctions); /// \brief Get the initial state, i.e. the state after placing \p Line's - /// first token at \p FirstIndent. - LineState getInitialState(unsigned FirstIndent, const AnnotatedLine *Line, - bool DryRun); + /// first token at \p FirstIndent. When reformatting a fragment of code, as in + /// the case of formatting inside raw string literals, \p FirstStartColumn is + /// the column at which the state of the parent formatter is. + LineState getInitialState(unsigned FirstIndent, unsigned FirstStartColumn, + const AnnotatedLine *Line, bool DryRun); // FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a // better home. @@ -88,17 +102,52 @@ private: /// \brief Update 'State' with the next token opening a nested block. void moveStateToNewBlock(LineState &State); + /// \brief Reformats a raw string literal. + /// + /// \returns An extra penalty induced by reformatting the token. + unsigned reformatRawStringLiteral(const FormatToken &Current, + LineState &State, + const FormatStyle &RawStringStyle, + bool DryRun); + + /// \brief If the current token is at the end of the current line, handle + /// the transition to the next line. + unsigned handleEndOfLine(const FormatToken &Current, LineState &State, + bool DryRun, bool AllowBreak); + + /// \brief If \p Current is a raw string that is configured to be reformatted, + /// return the style to be used. + llvm::Optional<FormatStyle> getRawStringStyle(const FormatToken &Current, + const LineState &State); + /// \brief If the current token sticks out over the end of the line, break /// it if possible. /// - /// \returns An extra penalty if a token was broken, otherwise 0. + /// \returns A pair (penalty, exceeded), where penalty is the extra penalty + /// when tokens are broken or lines exceed the column limit, and exceeded + /// indicates whether the algorithm purposefully left lines exceeding the + /// column limit. + /// + /// The returned penalty will cover the cost of the additional line breaks + /// and column limit violation in all lines except for the last one. The + /// penalty for the column limit violation in the last line (and in single + /// line tokens) is handled in \c addNextStateToQueue. /// - /// The returned penalty will cover the cost of the additional line breaks and - /// column limit violation in all lines except for the last one. The penalty - /// for the column limit violation in the last line (and in single line - /// tokens) is handled in \c addNextStateToQueue. - unsigned breakProtrudingToken(const FormatToken &Current, LineState &State, - bool DryRun); + /// \p Strict indicates whether reflowing is allowed to leave characters + /// protruding the column limit; if true, lines will be split strictly within + /// the column limit where possible; if false, words are allowed to protrude + /// over the column limit as long as the penalty is less than the penalty + /// of a break. + std::pair<unsigned, bool> breakProtrudingToken(const FormatToken &Current, + LineState &State, + bool AllowBreak, bool DryRun, + bool Strict); + + /// \brief Returns the \c BreakableToken starting at \p Current, or nullptr + /// if the current token cannot be broken. + std::unique_ptr<BreakableToken> + createBreakableToken(const FormatToken &Current, LineState &State, + bool AllowBreak); /// \brief Appends the next token to \p State and updates information /// necessary for indentation. @@ -143,6 +192,7 @@ private: encoding::Encoding Encoding; bool BinPackInconclusiveFunctions; llvm::Regex CommentPragmasRegex; + const RawStringFormatStyleManager RawStringFormats; }; struct ParenState { @@ -318,6 +368,9 @@ struct LineState { /// \brief \c true if this line contains a continued for-loop section. bool LineContainsContinuedForLoopSection; + /// \brief \c true if \p NextToken should not continue this line. + bool NoContinuation; + /// \brief The \c NestingLevel at the start of this line. unsigned StartOfLineLevel; @@ -364,6 +417,8 @@ struct LineState { if (LineContainsContinuedForLoopSection != Other.LineContainsContinuedForLoopSection) return LineContainsContinuedForLoopSection; + if (NoContinuation != Other.NoContinuation) + return NoContinuation; if (StartOfLineLevel != Other.StartOfLineLevel) return StartOfLineLevel < Other.StartOfLineLevel; if (LowestLevelOnLine != Other.LowestLevelOnLine) diff --git a/contrib/llvm/tools/clang/lib/Format/Format.cpp b/contrib/llvm/tools/clang/lib/Format/Format.cpp index 6fe5be2c815d4..217c6729ee397 100644 --- a/contrib/llvm/tools/clang/lib/Format/Format.cpp +++ b/contrib/llvm/tools/clang/lib/Format/Format.cpp @@ -16,6 +16,7 @@ #include "clang/Format/Format.h" #include "AffectedRangeManager.h" #include "ContinuationIndenter.h" +#include "FormatInternal.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" #include "SortJavaScriptImports.h" @@ -45,6 +46,7 @@ using clang::format::FormatStyle; LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory) +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat) namespace llvm { namespace yaml { @@ -125,8 +127,10 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { } }; -template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> { - static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { +template <> +struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> { + static void + enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon); IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma); IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon); @@ -134,6 +138,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitiali }; template <> +struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { + static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::PPDIS_None); + IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { IO.enumCase(Value, "None", FormatStyle::RTBS_None); @@ -181,8 +193,10 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> { } }; -template <> struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> { - static void enumeration(IO &IO, FormatStyle::EscapedNewlineAlignmentStyle &Value) { +template <> +struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> { + static void enumeration(IO &IO, + FormatStyle::EscapedNewlineAlignmentStyle &Value) { IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign); IO.enumCase(Value, "Left", FormatStyle::ENAS_Left); IO.enumCase(Value, "Right", FormatStyle::ENAS_Right); @@ -347,9 +361,11 @@ template <> struct MappingTraits<FormatStyle> { Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); + IO.mapOptional("IncludeBlocks", Style.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); + IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); @@ -365,8 +381,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty); IO.mapOptional("ObjCSpaceBeforeProtocolList", Style.ObjCSpaceBeforeProtocolList); - IO.mapOptional("PenaltyBreakAssignment", - Style.PenaltyBreakAssignment); + IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment); IO.mapOptional("PenaltyBreakBeforeFirstCallParameter", Style.PenaltyBreakBeforeFirstCallParameter); IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment); @@ -377,11 +392,13 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); IO.mapOptional("PointerAlignment", Style.PointerAlignment); + IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("SortIncludes", Style.SortIncludes); IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); - IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword); + IO.mapOptional("SpaceAfterTemplateKeyword", + Style.SpaceAfterTemplateKeyword); IO.mapOptional("SpaceBeforeAssignmentOperators", Style.SpaceBeforeAssignmentOperators); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); @@ -411,6 +428,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration); IO.mapOptional("AfterStruct", Wrapping.AfterStruct); IO.mapOptional("AfterUnion", Wrapping.AfterUnion); + IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock); IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); IO.mapOptional("BeforeElse", Wrapping.BeforeElse); IO.mapOptional("IndentBraces", Wrapping.IndentBraces); @@ -427,6 +445,22 @@ template <> struct MappingTraits<FormatStyle::IncludeCategory> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::IncludeBlocksStyle> { + static void enumeration(IO &IO, FormatStyle::IncludeBlocksStyle &Value) { + IO.enumCase(Value, "Preserve", FormatStyle::IBS_Preserve); + IO.enumCase(Value, "Merge", FormatStyle::IBS_Merge); + IO.enumCase(Value, "Regroup", FormatStyle::IBS_Regroup); + } +}; + +template <> struct MappingTraits<FormatStyle::RawStringFormat> { + static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { + IO.mapOptional("Delimiter", Format.Delimiter); + IO.mapOptional("Language", Format.Language); + IO.mapOptional("BasedOnStyle", Format.BasedOnStyle); + } +}; + // Allows to read vector<FormatStyle> while keeping default values. // IO.getContext() should contain a pointer to the FormatStyle structure, that // will be used to get default values for missing keys. @@ -441,7 +475,7 @@ template <> struct DocumentListTraits<std::vector<FormatStyle>> { if (Index >= Seq.size()) { assert(Index == Seq.size()); FormatStyle Template; - if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) { + if (!Seq.empty() && Seq[0].Language == FormatStyle::LK_None) { Template = Seq[0]; } else { Template = *((const FormatStyle *)IO.getContext()); @@ -491,9 +525,9 @@ static FormatStyle expandPresets(const FormatStyle &Style) { if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) return Style; FormatStyle Expanded = Style; - Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, true, - true, true}; + Expanded.BraceWrapping = {false, false, false, false, false, + false, false, false, false, false, + false, false, true, true, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -506,6 +540,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.AfterExternBlock = true; Expanded.BraceWrapping.SplitEmptyFunction = true; Expanded.BraceWrapping.SplitEmptyRecord = false; break; @@ -522,13 +557,13 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.AfterNamespace = true; Expanded.BraceWrapping.AfterObjCDeclaration = true; Expanded.BraceWrapping.AfterStruct = true; + Expanded.BraceWrapping.AfterExternBlock = true; Expanded.BraceWrapping.BeforeCatch = true; Expanded.BraceWrapping.BeforeElse = true; break; case FormatStyle::BS_GNU: - Expanded.BraceWrapping = {true, true, true, true, true, true, - true, true, true, true, true, true, - true, true}; + Expanded.BraceWrapping = {true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -564,9 +599,9 @@ FormatStyle getLLVMStyle() { LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; - LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, true, - true, true}; + LLVMStyle.BraceWrapping = {false, false, false, false, false, + false, false, false, false, false, + false, false, true, true, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; @@ -588,7 +623,9 @@ FormatStyle getLLVMStyle() { {"^(<|\"(gtest|gmock|isl|json)/)", 3}, {".*", 1}}; LLVMStyle.IncludeIsMainRegex = "(Test)?$"; + LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve; LLVMStyle.IndentCaseLabels = false; + LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; @@ -604,6 +641,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Cpp11; LLVMStyle.UseTab = FormatStyle::UT_Never; + LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto, "google"}}; LLVMStyle.ReflowComments = true; LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpacesInSquareBrackets = false; @@ -649,7 +687,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AlwaysBreakTemplateDeclarations = true; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; GoogleStyle.DerivePointerAlignment = true; - GoogleStyle.IncludeCategories = {{"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}}; + GoogleStyle.IncludeCategories = { + {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}}; GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IndentCaseLabels = true; GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; @@ -725,8 +764,7 @@ FormatStyle getMozillaStyle() { FormatStyle MozillaStyle = getLLVMStyle(); MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false; MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; - MozillaStyle.AlwaysBreakAfterReturnType = - FormatStyle::RTBS_TopLevel; + MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel; MozillaStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel; MozillaStyle.AlwaysBreakTemplateDeclarations = true; @@ -879,7 +917,7 @@ public: JavaScriptRequoter(const Environment &Env, const FormatStyle &Style) : TokenAnalyzer(Env, Style) {} - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override { @@ -887,7 +925,7 @@ public: AnnotatedLines.end()); tooling::Replacements Result; requoteJSStringLiteral(AnnotatedLines, Result); - return Result; + return {Result, 0}; } private: @@ -968,7 +1006,7 @@ public: FormattingAttemptStatus *Status) : TokenAnalyzer(Env, Style), Status(Status) {} - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override { @@ -987,17 +1025,23 @@ public: ContinuationIndenter Indenter(Style, Tokens.getKeywords(), Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); - UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(), - Env.getSourceManager(), Status) - .format(AnnotatedLines); + unsigned Penalty = + UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, + Tokens.getKeywords(), Env.getSourceManager(), + Status) + .format(AnnotatedLines, /*DryRun=*/false, + /*AdditionalIndent=*/0, + /*FixBadIndentation=*/false, + /*FirstStartColumn=*/Env.getFirstStartColumn(), + /*NextStartColumn=*/Env.getNextStartColumn(), + /*LastStartColumn=*/Env.getLastStartColumn()); for (const auto &R : Whitespaces.generateReplacements()) if (Result.add(R)) - return Result; - return Result; + return std::make_pair(Result, 0); + return std::make_pair(Result, Penalty); } private: - static bool inputUsesCRLF(StringRef Text) { return Text.count('\r') * 2 > Text.count('\n'); } @@ -1082,7 +1126,7 @@ public: DeletedTokens(FormatTokenLess(Env.getSourceManager())) {} // FIXME: eliminate unused parameters. - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override { @@ -1110,7 +1154,7 @@ public: } } - return generateFixes(); + return {generateFixes(), 0}; } private: @@ -1386,19 +1430,27 @@ static void sortCppIncludes(const FormatStyle &Style, }), Indices.end()); + int CurrentCategory = Includes.front().Category; + // If the #includes are out of order, we generate a single replacement fixing // the entire block. Otherwise, no replacement is generated. if (Indices.size() == Includes.size() && - std::is_sorted(Indices.begin(), Indices.end())) + std::is_sorted(Indices.begin(), Indices.end()) && + Style.IncludeBlocks == FormatStyle::IBS_Preserve) return; std::string result; for (unsigned Index : Indices) { - if (!result.empty()) + if (!result.empty()) { result += "\n"; + if (Style.IncludeBlocks == FormatStyle::IBS_Regroup && + CurrentCategory != Includes[Index].Category) + result += "\n"; + } result += Includes[Index].Text; if (Cursor && CursorIndex == Index) *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset; + CurrentCategory = Includes[Index].Category; } auto Err = Replaces.add(tooling::Replacement( @@ -1506,6 +1558,10 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, else if (Trimmed == "// clang-format on") FormattingOff = false; + const bool EmptyLineSkipped = + Trimmed.empty() && (Style.IncludeBlocks == FormatStyle::IBS_Merge || + Style.IncludeBlocks == FormatStyle::IBS_Regroup); + if (!FormattingOff && !Line.endswith("\\")) { if (IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; @@ -1515,7 +1571,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, if (Category == 0) MainIncludeFound = true; IncludesInBlock.push_back({IncludeName, Line, Prev, Category}); - } else if (!IncludesInBlock.empty()) { + } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) { sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor); IncludesInBlock.clear(); @@ -1539,12 +1595,16 @@ bool isMpegTS(StringRef Code) { return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47; } +bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); } + tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, ArrayRef<tooling::Range> Ranges, StringRef FileName, unsigned *Cursor) { tooling::Replacements Replaces; if (!Style.SortIncludes) return Replaces; + if (isLikelyXml(Code)) + return Replaces; if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript && isMpegTS(Code)) return Replaces; @@ -1887,17 +1947,22 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, return processReplacements(Cleanup, Code, NewReplaces, Style); } -tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, - ArrayRef<tooling::Range> Ranges, - StringRef FileName, - FormattingAttemptStatus *Status) { +namespace internal { +std::pair<tooling::Replacements, unsigned> +reformat(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn, + unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName, + FormattingAttemptStatus *Status) { FormatStyle Expanded = expandPresets(Style); if (Expanded.DisableFormat) - return tooling::Replacements(); + return {tooling::Replacements(), 0}; + if (isLikelyXml(Code)) + return {tooling::Replacements(), 0}; if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code)) - return tooling::Replacements(); + return {tooling::Replacements(), 0}; - typedef std::function<tooling::Replacements(const Environment &)> + typedef std::function<std::pair<tooling::Replacements, unsigned>( + const Environment &)> AnalyzerPass; SmallVector<AnalyzerPass, 4> Passes; @@ -1923,26 +1988,42 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, return Formatter(Env, Expanded, Status).process(); }); - std::unique_ptr<Environment> Env = - Environment::CreateVirtualEnvironment(Code, FileName, Ranges); + std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment( + Code, FileName, Ranges, FirstStartColumn, NextStartColumn, + LastStartColumn); llvm::Optional<std::string> CurrentCode = None; tooling::Replacements Fixes; + unsigned Penalty = 0; for (size_t I = 0, E = Passes.size(); I < E; ++I) { - tooling::Replacements PassFixes = Passes[I](*Env); + std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env); auto NewCode = applyAllReplacements( - CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes); + CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first); if (NewCode) { - Fixes = Fixes.merge(PassFixes); + Fixes = Fixes.merge(PassFixes.first); + Penalty += PassFixes.second; if (I + 1 < E) { CurrentCode = std::move(*NewCode); Env = Environment::CreateVirtualEnvironment( *CurrentCode, FileName, - tooling::calculateRangesAfterReplacements(Fixes, Ranges)); + tooling::calculateRangesAfterReplacements(Fixes, Ranges), + FirstStartColumn, NextStartColumn, LastStartColumn); } } } - return Fixes; + return {Fixes, Penalty}; +} +} // namespace internal + +tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, + StringRef FileName, + FormattingAttemptStatus *Status) { + return internal::reformat(Style, Code, Ranges, + /*FirstStartColumn=*/0, + /*NextStartColumn=*/0, + /*LastStartColumn=*/0, FileName, Status) + .first; } tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, @@ -1954,7 +2035,7 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); Cleaner Clean(*Env, Style); - return Clean.process(); + return Clean.process().first; } tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, @@ -1974,7 +2055,7 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); NamespaceEndCommentsFixer Fix(*Env, Style); - return Fix.process(); + return Fix.process().first; } tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, @@ -1984,7 +2065,7 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); UsingDeclarationsSorter Sorter(*Env, Style); - return Sorter.process(); + return Sorter.process().first; } LangOptions getFormattingLangOpts(const FormatStyle &Style) { @@ -1992,7 +2073,8 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOpts.CPlusPlus = 1; LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; - LangOpts.CPlusPlus1z = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; + LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; + LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; LangOpts.LineComment = 1; bool AlternativeOperators = Style.isCpp(); LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0; @@ -2025,6 +2107,11 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { if (FileName.endswith_lower(".proto") || FileName.endswith_lower(".protodevel")) return FormatStyle::LK_Proto; + if (FileName.endswith_lower(".textpb") || + FileName.endswith_lower(".pb.txt") || + FileName.endswith_lower(".textproto") || + FileName.endswith_lower(".asciipb")) + return FormatStyle::LK_TextProto; if (FileName.endswith_lower(".td")) return FormatStyle::LK_TableGen; return FormatStyle::LK_Cpp; @@ -2043,7 +2130,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, // should be improved over time and probably be done on tokens, not one the // bare content of the file. if (Style.Language == FormatStyle::LK_Cpp && FileName.endswith(".h") && - (Code.contains("\n- (") || Code.contains("\n+ ("))) + (Code.contains("\n- (") || Code.contains("\n+ (") || + Code.contains("\n@end\n") || Code.contains("\n@end ") || + Code.endswith("@end"))) Style.Language = FormatStyle::LK_ObjC; FormatStyle FallbackStyle = getNoStyle(); diff --git a/contrib/llvm/tools/clang/lib/Format/FormatInternal.h b/contrib/llvm/tools/clang/lib/Format/FormatInternal.h new file mode 100644 index 0000000000000..3984158467b3b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Format/FormatInternal.h @@ -0,0 +1,83 @@ +//===--- FormatInternal.h - Format C++ code ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares Format APIs to be used internally by the +/// formatting library implementation. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H +#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H + +#include "BreakableToken.h" +#include "clang/Tooling/Core/Lookup.h" +#include <utility> + +namespace clang { +namespace format { +namespace internal { + +/// \brief Reformats the given \p Ranges in the code fragment \p Code. +/// +/// A fragment of code could conceptually be surrounded by other code that might +/// constrain how that fragment is laid out. +/// For example, consider the fragment of code between 'R"(' and ')"', +/// exclusive, in the following code: +/// +/// void outer(int x) { +/// string inner = R"(name: data +/// ^ FirstStartColumn +/// value: { +/// x: 1 +/// ^ NextStartColumn +/// } +/// )"; +/// ^ LastStartColumn +/// } +/// +/// The outer code can influence the inner fragment as follows: +/// * \p FirstStartColumn specifies the column at which \p Code starts. +/// * \p NextStartColumn specifies the additional indent dictated by the +/// surrounding code. It is applied to the rest of the lines of \p Code. +/// * \p LastStartColumn specifies the column at which the last line of +/// \p Code should end, in case the last line is an empty line. +/// +/// In the case where the last line of the fragment contains content, +/// the fragment ends at the end of that content and \p LastStartColumn is +/// not taken into account, for example in: +/// +/// void block() { +/// string inner = R"(name: value)"; +/// } +/// +/// Each range is extended on either end to its next bigger logic unit, i.e. +/// everything that might influence its formatting or might be influenced by its +/// formatting. +/// +/// Returns a pair P, where: +/// * P.first are the ``Replacements`` necessary to make all \p Ranges comply +/// with \p Style. +/// * P.second is the penalty induced by formatting the fragment \p Code. +/// If the formatting of the fragment doesn't have a notion of penalty, +/// returns 0. +/// +/// If ``Status`` is non-null, its value will be populated with the status of +/// this formatting attempt. See \c FormattingAttemptStatus. +std::pair<tooling::Replacements, unsigned> +reformat(const FormatStyle &Style, StringRef Code, + ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn, + unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName, + FormattingAttemptStatus *Status); + +} // namespace internal +} // namespace format +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Format/FormatToken.cpp b/contrib/llvm/tools/clang/lib/Format/FormatToken.cpp index ba5bf03a63464..10ac392abbf2f 100644 --- a/contrib/llvm/tools/clang/lib/Format/FormatToken.cpp +++ b/contrib/llvm/tools/clang/lib/Format/FormatToken.cpp @@ -25,10 +25,9 @@ namespace format { const char *getTokenTypeName(TokenType Type) { static const char *const TokNames[] = { #define TYPE(X) #X, -LIST_TOKEN_TYPES + LIST_TOKEN_TYPES #undef TYPE - nullptr - }; + nullptr}; if (Type < NUM_TOKEN_TYPES) return TokNames[Type]; @@ -52,6 +51,7 @@ bool FormatToken::isSimpleTypeSpecifier() const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: diff --git a/contrib/llvm/tools/clang/lib/Format/FormatToken.h b/contrib/llvm/tools/clang/lib/Format/FormatToken.h index a60361a8e5fa9..3dc0ab0e7cca2 100644 --- a/contrib/llvm/tools/clang/lib/Format/FormatToken.h +++ b/contrib/llvm/tools/clang/lib/Format/FormatToken.h @@ -26,78 +26,79 @@ namespace clang { namespace format { -#define LIST_TOKEN_TYPES \ - TYPE(ArrayInitializerLSquare) \ - TYPE(ArraySubscriptLSquare) \ - TYPE(AttributeParen) \ - TYPE(BinaryOperator) \ - TYPE(BitFieldColon) \ - TYPE(BlockComment) \ - TYPE(CastRParen) \ - TYPE(ConditionalExpr) \ - TYPE(ConflictAlternative) \ - TYPE(ConflictEnd) \ - TYPE(ConflictStart) \ - TYPE(CtorInitializerColon) \ - TYPE(CtorInitializerComma) \ - TYPE(DesignatedInitializerLSquare) \ - TYPE(DesignatedInitializerPeriod) \ - TYPE(DictLiteral) \ - TYPE(ForEachMacro) \ - TYPE(FunctionAnnotationRParen) \ - TYPE(FunctionDeclarationName) \ - TYPE(FunctionLBrace) \ - TYPE(FunctionTypeLParen) \ - TYPE(ImplicitStringLiteral) \ - TYPE(InheritanceColon) \ - TYPE(InheritanceComma) \ - TYPE(InlineASMBrace) \ - TYPE(InlineASMColon) \ - TYPE(JavaAnnotation) \ - TYPE(JsComputedPropertyName) \ - TYPE(JsExponentiation) \ - TYPE(JsExponentiationEqual) \ - TYPE(JsFatArrow) \ - TYPE(JsNonNullAssertion) \ - TYPE(JsTypeColon) \ - TYPE(JsTypeOperator) \ - TYPE(JsTypeOptionalQuestion) \ - TYPE(LambdaArrow) \ - TYPE(LambdaLSquare) \ - TYPE(LeadingJavaAnnotation) \ - TYPE(LineComment) \ - TYPE(MacroBlockBegin) \ - TYPE(MacroBlockEnd) \ - TYPE(ObjCBlockLBrace) \ - TYPE(ObjCBlockLParen) \ - TYPE(ObjCDecl) \ - TYPE(ObjCForIn) \ - TYPE(ObjCMethodExpr) \ - TYPE(ObjCMethodSpecifier) \ - TYPE(ObjCProperty) \ - TYPE(ObjCStringLiteral) \ - TYPE(OverloadedOperator) \ - TYPE(OverloadedOperatorLParen) \ - TYPE(PointerOrReference) \ - TYPE(PureVirtualSpecifier) \ - TYPE(RangeBasedForLoopColon) \ - TYPE(RegexLiteral) \ - TYPE(SelectorName) \ - TYPE(StartOfName) \ - TYPE(TemplateCloser) \ - TYPE(TemplateOpener) \ - TYPE(TemplateString) \ - TYPE(TrailingAnnotation) \ - TYPE(TrailingReturnArrow) \ - TYPE(TrailingUnaryOperator) \ - TYPE(UnaryOperator) \ +#define LIST_TOKEN_TYPES \ + TYPE(ArrayInitializerLSquare) \ + TYPE(ArraySubscriptLSquare) \ + TYPE(AttributeParen) \ + TYPE(BinaryOperator) \ + TYPE(BitFieldColon) \ + TYPE(BlockComment) \ + TYPE(CastRParen) \ + TYPE(ConditionalExpr) \ + TYPE(ConflictAlternative) \ + TYPE(ConflictEnd) \ + TYPE(ConflictStart) \ + TYPE(CtorInitializerColon) \ + TYPE(CtorInitializerComma) \ + TYPE(DesignatedInitializerLSquare) \ + TYPE(DesignatedInitializerPeriod) \ + TYPE(DictLiteral) \ + TYPE(ForEachMacro) \ + TYPE(FunctionAnnotationRParen) \ + TYPE(FunctionDeclarationName) \ + TYPE(FunctionLBrace) \ + TYPE(FunctionTypeLParen) \ + TYPE(ImplicitStringLiteral) \ + TYPE(InheritanceColon) \ + TYPE(InheritanceComma) \ + TYPE(InlineASMBrace) \ + TYPE(InlineASMColon) \ + TYPE(JavaAnnotation) \ + TYPE(JsComputedPropertyName) \ + TYPE(JsExponentiation) \ + TYPE(JsExponentiationEqual) \ + TYPE(JsFatArrow) \ + TYPE(JsNonNullAssertion) \ + TYPE(JsTypeColon) \ + TYPE(JsTypeOperator) \ + TYPE(JsTypeOptionalQuestion) \ + TYPE(LambdaArrow) \ + TYPE(LambdaLSquare) \ + TYPE(LeadingJavaAnnotation) \ + TYPE(LineComment) \ + TYPE(MacroBlockBegin) \ + TYPE(MacroBlockEnd) \ + TYPE(ObjCBlockLBrace) \ + TYPE(ObjCBlockLParen) \ + TYPE(ObjCDecl) \ + TYPE(ObjCForIn) \ + TYPE(ObjCMethodExpr) \ + TYPE(ObjCMethodSpecifier) \ + TYPE(ObjCProperty) \ + TYPE(ObjCStringLiteral) \ + TYPE(OverloadedOperator) \ + TYPE(OverloadedOperatorLParen) \ + TYPE(PointerOrReference) \ + TYPE(PureVirtualSpecifier) \ + TYPE(RangeBasedForLoopColon) \ + TYPE(RegexLiteral) \ + TYPE(SelectorName) \ + TYPE(StartOfName) \ + TYPE(StructuredBindingLSquare) \ + TYPE(TemplateCloser) \ + TYPE(TemplateOpener) \ + TYPE(TemplateString) \ + TYPE(TrailingAnnotation) \ + TYPE(TrailingReturnArrow) \ + TYPE(TrailingUnaryOperator) \ + TYPE(UnaryOperator) \ TYPE(Unknown) enum TokenType { #define TYPE(X) TT_##X, -LIST_TOKEN_TYPES + LIST_TOKEN_TYPES #undef TYPE - NUM_TOKEN_TYPES + NUM_TOKEN_TYPES }; /// \brief Determines the name of a token type. @@ -340,10 +341,11 @@ struct FormatToken { bool isSimpleTypeSpecifier() const; bool isObjCAccessSpecifier() const { - return is(tok::at) && Next && (Next->isObjCAtKeyword(tok::objc_public) || - Next->isObjCAtKeyword(tok::objc_protected) || - Next->isObjCAtKeyword(tok::objc_package) || - Next->isObjCAtKeyword(tok::objc_private)); + return is(tok::at) && Next && + (Next->isObjCAtKeyword(tok::objc_public) || + Next->isObjCAtKeyword(tok::objc_protected) || + Next->isObjCAtKeyword(tok::objc_package) || + Next->isObjCAtKeyword(tok::objc_private)); } /// \brief Returns whether \p Tok is ([{ or a template opening <. @@ -471,6 +473,19 @@ struct FormatToken { Style.Language == FormatStyle::LK_TextProto)); } + /// \brief Returns whether the token is the left square bracket of a C++ + /// structured binding declaration. + bool isCppStructuredBinding(const FormatStyle &Style) const { + if (!Style.isCpp() || isNot(tok::l_square)) + return false; + const FormatToken *T = this; + do { + T = T->getPreviousNonComment(); + } while (T && T->isOneOf(tok::kw_const, tok::kw_volatile, tok::amp, + tok::ampamp)); + return T && T->is(tok::kw_auto); + } + /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. bool closesBlockOrBlockTypeList(const FormatStyle &Style) const { if (is(TT_TemplateString) && closesScope()) @@ -503,15 +518,13 @@ private: return is(K1) && Next && Next->startsSequenceInternal(Tokens...); } - template <typename A> - bool startsSequenceInternal(A K1) const { + template <typename A> bool startsSequenceInternal(A K1) const { if (is(tok::comment) && Next) return Next->startsSequenceInternal(K1); return is(K1); } - template <typename A, typename... Ts> - bool endsSequenceInternal(A K1) const { + template <typename A, typename... Ts> bool endsSequenceInternal(A K1) const { if (is(tok::comment) && Previous) return Previous->endsSequenceInternal(K1); return is(K1); @@ -644,6 +657,7 @@ struct AdditionalKeywords { kw_readonly = &IdentTable.get("readonly"); kw_set = &IdentTable.get("set"); kw_type = &IdentTable.get("type"); + kw_typeof = &IdentTable.get("typeof"); kw_var = &IdentTable.get("var"); kw_yield = &IdentTable.get("yield"); @@ -680,7 +694,7 @@ struct AdditionalKeywords { JsExtraKeywords = std::unordered_set<IdentifierInfo *>( {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, - kw_set, kw_type, kw_var, kw_yield, + kw_set, kw_type, kw_typeof, kw_var, kw_yield, // Keywords from the Java section. kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); } @@ -714,6 +728,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_readonly; IdentifierInfo *kw_set; IdentifierInfo *kw_type; + IdentifierInfo *kw_typeof; IdentifierInfo *kw_var; IdentifierInfo *kw_yield; diff --git a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp index 45c3ae1afe5fe..199d2974c5c74 100644 --- a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp @@ -24,10 +24,10 @@ namespace clang { namespace format { FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, - const FormatStyle &Style, + unsigned Column, const FormatStyle &Style, encoding::Encoding Encoding) : FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}), - Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), + Column(Column), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), @@ -50,6 +50,8 @@ ArrayRef<FormatToken *> FormatTokenLexer::lex() { tryParseJSRegexLiteral(); handleTemplateStrings(); } + if (Style.Language == FormatStyle::LK_TextProto) + tryParsePythonComment(); tryMergePreviousTokens(); if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline) FirstInLineIndex = Tokens.size() - 1; @@ -96,14 +98,8 @@ void FormatTokenLexer::tryMergePreviousTokens() { } if (Style.Language == FormatStyle::LK_Java) { - static const tok::TokenKind JavaRightLogicalShift[] = {tok::greater, - tok::greater, - tok::greater}; - static const tok::TokenKind JavaRightLogicalShiftAssign[] = {tok::greater, - tok::greater, - tok::greaterequal}; - if (tryMergeTokens(JavaRightLogicalShift, TT_BinaryOperator)) - return; + static const tok::TokenKind JavaRightLogicalShiftAssign[] = { + tok::greater, tok::greater, tok::greaterequal}; if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator)) return; } @@ -162,9 +158,8 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, return false; unsigned AddLength = 0; for (unsigned i = 1; i < Kinds.size(); ++i) { - if (!First[i]->is(Kinds[i]) || - First[i]->WhitespaceRange.getBegin() != - First[i]->WhitespaceRange.getEnd()) + if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() != + First[i]->WhitespaceRange.getEnd()) return false; AddLength += First[i]->TokenText.size(); } @@ -337,6 +332,27 @@ void FormatTokenLexer::handleTemplateStrings() { resetLexer(SourceMgr.getFileOffset(loc)); } +void FormatTokenLexer::tryParsePythonComment() { + FormatToken *HashToken = Tokens.back(); + if (HashToken->isNot(tok::hash)) + return; + // Turn the remainder of this line into a comment. + const char *CommentBegin = + Lex->getBufferLocation() - HashToken->TokenText.size(); // at "#" + size_t From = CommentBegin - Lex->getBuffer().begin(); + size_t To = Lex->getBuffer().find_first_of('\n', From); + if (To == StringRef::npos) + To = Lex->getBuffer().size(); + size_t Len = To - From; + HashToken->Type = TT_LineComment; + HashToken->Tok.setKind(tok::comment); + HashToken->TokenText = Lex->getBuffer().substr(From, Len); + SourceLocation Loc = To < Lex->getBuffer().size() + ? Lex->getSourceLocation(CommentBegin + Len) + : SourceMgr.getLocForEndOfFile(ID); + resetLexer(SourceMgr.getFileOffset(Loc)); +} + bool FormatTokenLexer::tryMerge_TMacro() { if (Tokens.size() < 4) return false; @@ -529,17 +545,53 @@ FormatToken *FormatTokenLexer::getNextToken() { readRawToken(*FormatTok); } + // JavaScript and Java do not allow to escape the end of the line with a + // backslash. Backslashes are syntax errors in plain source, but can occur in + // comments. When a single line comment ends with a \, it'll cause the next + // line of code to be lexed as a comment, breaking formatting. The code below + // finds comments that contain a backslash followed by a line break, truncates + // the comment token at the backslash, and resets the lexer to restart behind + // the backslash. + if ((Style.Language == FormatStyle::LK_JavaScript || + Style.Language == FormatStyle::LK_Java) && + FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) { + size_t BackslashPos = FormatTok->TokenText.find('\\'); + while (BackslashPos != StringRef::npos) { + if (BackslashPos + 1 < FormatTok->TokenText.size() && + FormatTok->TokenText[BackslashPos + 1] == '\n') { + const char *Offset = Lex->getBufferLocation(); + Offset -= FormatTok->TokenText.size(); + Offset += BackslashPos + 1; + resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset))); + FormatTok->TokenText = FormatTok->TokenText.substr(0, BackslashPos + 1); + FormatTok->ColumnWidth = encoding::columnWidthWithTabs( + FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth, + Encoding); + break; + } + BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1); + } + } + // In case the token starts with escaped newlines, we want to // take them into account as whitespace - this pattern is quite frequent // in macro definitions. // FIXME: Add a more explicit test. - while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' && - FormatTok->TokenText[1] == '\n') { + while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\') { + unsigned SkippedWhitespace = 0; + if (FormatTok->TokenText.size() > 2 && + (FormatTok->TokenText[1] == '\r' && FormatTok->TokenText[2] == '\n')) + SkippedWhitespace = 3; + else if (FormatTok->TokenText[1] == '\n') + SkippedWhitespace = 2; + else + break; + ++FormatTok->NewlinesBefore; - WhitespaceLength += 2; - FormatTok->LastNewlineOffset = 2; + WhitespaceLength += SkippedWhitespace; + FormatTok->LastNewlineOffset = SkippedWhitespace; Column = 0; - FormatTok->TokenText = FormatTok->TokenText.substr(2); + FormatTok->TokenText = FormatTok->TokenText.substr(SkippedWhitespace); } FormatTok->WhitespaceRange = SourceRange( diff --git a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h index bf10f09cd11e1..59dc2a752f1f3 100644 --- a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h +++ b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h @@ -36,7 +36,7 @@ enum LexerState { class FormatTokenLexer { public: - FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, + FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned Column, const FormatStyle &Style, encoding::Encoding Encoding); ArrayRef<FormatToken *> lex(); @@ -73,6 +73,8 @@ private: // nested template parts by balancing curly braces. void handleTemplateStrings(); + void tryParsePythonComment(); + bool tryMerge_TMacro(); bool tryMergeConflictMarkers(); diff --git a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp index 85b70b8c0a768..df99bb2e13819 100644 --- a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp @@ -118,6 +118,12 @@ getNamespaceToken(const AnnotatedLine *line, return nullptr; assert(StartLineIndex < AnnotatedLines.size()); const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First; + if (NamespaceTok->is(tok::l_brace)) { + // "namespace" keyword can be on the line preceding '{', e.g. in styles + // where BraceWrapping.AfterNamespace is true. + if (StartLineIndex > 0) + NamespaceTok = AnnotatedLines[StartLineIndex - 1]->First; + } // Detect "(inline)? namespace" in the beginning of a line. if (NamespaceTok->is(tok::kw_inline)) NamespaceTok = NamespaceTok->getNextNonComment(); @@ -131,7 +137,7 @@ NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle &Style) : TokenAnalyzer(Env, Style) {} -tooling::Replacements NamespaceEndCommentsFixer::analyze( +std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) { const SourceManager &SourceMgr = Env.getSourceManager(); @@ -200,7 +206,7 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( } StartLineIndex = SIZE_MAX; } - return Fixes; + return {Fixes, 0}; } } // namespace format diff --git a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h index 7790668a2e829..4779f0d27c927 100644 --- a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h +++ b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h @@ -25,7 +25,7 @@ class NamespaceEndCommentsFixer : public TokenAnalyzer { public: NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle &Style); - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override; diff --git a/contrib/llvm/tools/clang/lib/Format/SortJavaScriptImports.cpp b/contrib/llvm/tools/clang/lib/Format/SortJavaScriptImports.cpp index e73695ca84770..d0b979e100d5d 100644 --- a/contrib/llvm/tools/clang/lib/Format/SortJavaScriptImports.cpp +++ b/contrib/llvm/tools/clang/lib/Format/SortJavaScriptImports.cpp @@ -123,7 +123,7 @@ public: : TokenAnalyzer(Env, Style), FileContents(Env.getSourceManager().getBufferData(Env.getFileID())) {} - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override { @@ -138,7 +138,7 @@ public: parseModuleReferences(Keywords, AnnotatedLines); if (References.empty()) - return Result; + return {Result, 0}; SmallVector<unsigned, 16> Indices; for (unsigned i = 0, e = References.size(); i != e; ++i) @@ -168,7 +168,7 @@ public: } if (ReferencesInOrder && SymbolsInOrder) - return Result; + return {Result, 0}; SourceRange InsertionPoint = References[0].Range; InsertionPoint.setEnd(References[References.size() - 1].Range.getEnd()); @@ -202,7 +202,7 @@ public: assert(false); } - return Result; + return {Result, 0}; } private: @@ -277,7 +277,7 @@ private: // Parses module references in the given lines. Returns the module references, // and a pointer to the first "main code" line if that is adjacent to the // affected lines of module references, nullptr otherwise. - std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine*> + std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine *> parseModuleReferences(const AdditionalKeywords &Keywords, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { SmallVector<JsModuleReference, 16> References; @@ -413,7 +413,7 @@ private: nextToken(); if (Current->is(tok::r_brace)) break; - if (Current->isNot(tok::identifier)) + if (!Current->isOneOf(tok::identifier, tok::kw_default)) return false; JsImportedSymbol Symbol; @@ -425,7 +425,7 @@ private: if (Current->is(Keywords.kw_as)) { nextToken(); - if (Current->isNot(tok::identifier)) + if (!Current->isOneOf(tok::identifier, tok::kw_default)) return false; Symbol.Alias = Current->TokenText; nextToken(); @@ -449,7 +449,7 @@ tooling::Replacements sortJavaScriptImports(const FormatStyle &Style, std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); JavaScriptImportSorter Sorter(*Env, Style); - return Sorter.process(); + return Sorter.process().first; } } // end namespace format diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.cpp b/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.cpp index f2e4e8ef08197..d1dfb1fea32b6 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.cpp +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.cpp @@ -38,7 +38,10 @@ namespace format { // Code. std::unique_ptr<Environment> Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName, - ArrayRef<tooling::Range> Ranges) { + ArrayRef<tooling::Range> Ranges, + unsigned FirstStartColumn, + unsigned NextStartColumn, + unsigned LastStartColumn) { // This is referenced by `FileMgr` and will be released by `FileMgr` when it // is deleted. IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( @@ -57,8 +60,9 @@ Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName, std::unique_ptr<SourceManager> VirtualSM( new SourceManager(*Diagnostics, *FileMgr)); InMemoryFileSystem->addFile( - FileName, 0, llvm::MemoryBuffer::getMemBuffer( - Code, FileName, /*RequiresNullTerminator=*/false)); + FileName, 0, + llvm::MemoryBuffer::getMemBuffer(Code, FileName, + /*RequiresNullTerminator=*/false)); FileID ID = VirtualSM->createFileID(FileMgr->getFile(FileName), SourceLocation(), clang::SrcMgr::C_User); assert(ID.isValid()); @@ -69,9 +73,9 @@ Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName, SourceLocation End = Start.getLocWithOffset(Range.getLength()); CharRanges.push_back(CharSourceRange::getCharRange(Start, End)); } - return llvm::make_unique<Environment>(ID, std::move(FileMgr), - std::move(VirtualSM), - std::move(Diagnostics), CharRanges); + return llvm::make_unique<Environment>( + ID, std::move(FileMgr), std::move(VirtualSM), std::move(Diagnostics), + CharRanges, FirstStartColumn, NextStartColumn, LastStartColumn); } TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) @@ -88,14 +92,16 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) << "\n"); } -tooling::Replacements TokenAnalyzer::process() { +std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() { tooling::Replacements Result; - FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(), Style, - Encoding); + FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(), + Env.getFirstStartColumn(), Style, Encoding); - UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(), *this); + UnwrappedLineParser Parser(Style, Tokens.getKeywords(), + Env.getFirstStartColumn(), Tokens.lex(), *this); Parser.parse(); assert(UnwrappedLines.rbegin()->empty()); + unsigned Penalty = 0; for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE; ++Run) { DEBUG(llvm::dbgs() << "Run " << Run << "...\n"); SmallVector<AnnotatedLine *, 16> AnnotatedLines; @@ -106,13 +112,13 @@ tooling::Replacements TokenAnalyzer::process() { Annotator.annotate(*AnnotatedLines.back()); } - tooling::Replacements RunResult = + std::pair<tooling::Replacements, unsigned> RunResult = analyze(Annotator, AnnotatedLines, Tokens); DEBUG({ llvm::dbgs() << "Replacements for run " << Run << ":\n"; - for (tooling::Replacements::const_iterator I = RunResult.begin(), - E = RunResult.end(); + for (tooling::Replacements::const_iterator I = RunResult.first.begin(), + E = RunResult.first.end(); I != E; ++I) { llvm::dbgs() << I->toString() << "\n"; } @@ -120,17 +126,19 @@ tooling::Replacements TokenAnalyzer::process() { for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { delete AnnotatedLines[i]; } - for (const auto &R : RunResult) { + + Penalty += RunResult.second; + for (const auto &R : RunResult.first) { auto Err = Result.add(R); // FIXME: better error handling here. For now, simply return an empty // Replacements to indicate failure. if (Err) { llvm::errs() << llvm::toString(std::move(Err)) << "\n"; - return tooling::Replacements(); + return {tooling::Replacements(), 0}; } } } - return Result; + return {Result, Penalty}; } void TokenAnalyzer::consumeUnwrappedLine(const UnwrappedLine &TheLine) { diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.h b/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.h index 78a3d1bc8d9e5..96ea00b25ba1b 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.h +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnalyzer.h @@ -37,21 +37,37 @@ namespace format { class Environment { public: Environment(SourceManager &SM, FileID ID, ArrayRef<CharSourceRange> Ranges) - : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM) {} + : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM), + FirstStartColumn(0), + NextStartColumn(0), + LastStartColumn(0) {} Environment(FileID ID, std::unique_ptr<FileManager> FileMgr, std::unique_ptr<SourceManager> VirtualSM, std::unique_ptr<DiagnosticsEngine> Diagnostics, - const std::vector<CharSourceRange> &CharRanges) + const std::vector<CharSourceRange> &CharRanges, + unsigned FirstStartColumn, + unsigned NextStartColumn, + unsigned LastStartColumn) : ID(ID), CharRanges(CharRanges.begin(), CharRanges.end()), - SM(*VirtualSM), FileMgr(std::move(FileMgr)), + SM(*VirtualSM), + FirstStartColumn(FirstStartColumn), + NextStartColumn(NextStartColumn), + LastStartColumn(LastStartColumn), + FileMgr(std::move(FileMgr)), VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics)) {} - // This sets up an virtual file system with file \p FileName containing \p - // Code. + // This sets up an virtual file system with file \p FileName containing the + // fragment \p Code. Assumes that \p Code starts at \p FirstStartColumn, + // that the next lines of \p Code should start at \p NextStartColumn, and + // that \p Code should end at \p LastStartColumn if it ends in newline. + // See also the documentation of clang::format::internal::reformat. static std::unique_ptr<Environment> CreateVirtualEnvironment(StringRef Code, StringRef FileName, - ArrayRef<tooling::Range> Ranges); + ArrayRef<tooling::Range> Ranges, + unsigned FirstStartColumn = 0, + unsigned NextStartColumn = 0, + unsigned LastStartColumn = 0); FileID getFileID() const { return ID; } @@ -59,10 +75,25 @@ public: const SourceManager &getSourceManager() const { return SM; } + // Returns the column at which the fragment of code managed by this + // environment starts. + unsigned getFirstStartColumn() const { return FirstStartColumn; } + + // Returns the column at which subsequent lines of the fragment of code + // managed by this environment should start. + unsigned getNextStartColumn() const { return NextStartColumn; } + + // Returns the column at which the fragment of code managed by this + // environment should end if it ends in a newline. + unsigned getLastStartColumn() const { return LastStartColumn; } + private: FileID ID; SmallVector<CharSourceRange, 8> CharRanges; SourceManager &SM; + unsigned FirstStartColumn; + unsigned NextStartColumn; + unsigned LastStartColumn; // The order of these fields are important - they should be in the same order // as they are created in `CreateVirtualEnvironment` so that they can be @@ -76,10 +107,10 @@ class TokenAnalyzer : public UnwrappedLineConsumer { public: TokenAnalyzer(const Environment &Env, const FormatStyle &Style); - tooling::Replacements process(); + std::pair<tooling::Replacements, unsigned> process(); protected: - virtual tooling::Replacements + virtual std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) = 0; diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp index 46ea06b880ed2..298c72b002f8b 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp @@ -47,7 +47,7 @@ private: if (NonTemplateLess.count(CurrentToken->Previous)) return false; - const FormatToken& Previous = *CurrentToken->Previous; + const FormatToken &Previous = *CurrentToken->Previous; // The '<'. if (Previous.Previous) { if (Previous.Previous->Tok.isLiteral()) return false; @@ -152,11 +152,11 @@ private: // export type X = (...); Contexts.back().IsExpression = false; } else if (Left->Previous && - (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, - tok::kw_if, tok::kw_while, tok::l_paren, - tok::comma) || - Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) || - Left->Previous->is(TT_BinaryOperator))) { + (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, + tok::kw_if, tok::kw_while, tok::l_paren, + tok::comma) || + Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) || + Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; } else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && @@ -325,8 +325,7 @@ private: // In C++, this can happen either in array of templates (foo<int>[10]) // or when array is a nested template type (unique_ptr<type1<type2>[]>). bool CppArrayTemplates = - Style.isCpp() && Parent && - Parent->is(TT_TemplateCloser) && + Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) && (Contexts.back().CanBeExpression || Contexts.back().IsExpression || Contexts.back().InTemplateArgument); @@ -343,7 +342,9 @@ private: bool ColonFound = false; unsigned BindingIncrease = 1; - if (Left->is(TT_Unknown)) { + if (Left->isCppStructuredBinding(Style)) { + Left->Type = TT_StructuredBindingLSquare; + } else if (Left->is(TT_Unknown)) { if (StartsObjCMethodExpr) { Left->Type = TT_ObjCMethodExpr; } else if (Style.Language == FormatStyle::LK_JavaScript && Parent && @@ -372,6 +373,10 @@ private: ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease); Contexts.back().IsExpression = true; + if (Style.Language == FormatStyle::LK_JavaScript && Parent && + Parent->is(TT_JsTypeColon)) + Contexts.back().IsExpression = false; + Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr; while (CurrentToken) { @@ -439,6 +444,9 @@ private: Contexts.back().ColonIsDictLiteral = true; if (Left->BlockKind == BK_BracedInit) Contexts.back().IsExpression = true; + if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && + Left->Previous->is(TT_JsTypeColon)) + Contexts.back().IsExpression = false; while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { @@ -452,6 +460,8 @@ private: updateParameterCount(Left, CurrentToken); if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) { FormatToken *Previous = CurrentToken->getPreviousNonComment(); + if (Previous->is(TT_JsTypeOptionalQuestion)) + Previous = Previous->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || Style.Language == FormatStyle::LK_Proto || @@ -531,8 +541,11 @@ private: !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) || Contexts.back().ContextKind == tok::l_paren || // function params Contexts.back().ContextKind == tok::l_square || // array type + (!Contexts.back().IsExpression && + Contexts.back().ContextKind == tok::l_brace) || // object type (Contexts.size() == 1 && Line.MustBeDeclaration)) { // method/property declaration + Contexts.back().IsExpression = false; Tok->Type = TT_JsTypeColon; break; } @@ -593,7 +606,8 @@ private: break; case tok::kw_if: case tok::kw_while: - if (Tok->is(tok::kw_if) && CurrentToken && CurrentToken->is(tok::kw_constexpr)) + if (Tok->is(tok::kw_if) && CurrentToken && + CurrentToken->is(tok::kw_constexpr)) next(); if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); @@ -603,7 +617,9 @@ private: break; case tok::kw_for: if (Style.Language == FormatStyle::LK_JavaScript) { - if (Tok->Previous && Tok->Previous->is(tok::period)) + // x.for and {for: ...} + if ((Tok->Previous && Tok->Previous->is(tok::period)) || + (Tok->Next && Tok->Next->is(tok::colon))) break; // JS' for await ( ... if (CurrentToken && CurrentToken->is(Keywords.kw_await)) @@ -619,8 +635,7 @@ private: // marks the first l_paren as a OverloadedOperatorLParen. Here, we make // the first two parens OverloadedOperators and the second l_paren an // OverloadedOperatorLParen. - if (Tok->Previous && - Tok->Previous->is(tok::r_paren) && + if (Tok->Previous && Tok->Previous->is(tok::r_paren) && Tok->Previous->MatchingParen && Tok->Previous->MatchingParen->is(TT_OverloadedOperatorLParen)) { Tok->Previous->Type = TT_OverloadedOperator; @@ -643,7 +658,7 @@ private: break; case tok::l_brace: if (Style.Language == FormatStyle::LK_TextProto) { - FormatToken *Previous =Tok->getPreviousNonComment(); + FormatToken *Previous = Tok->getPreviousNonComment(); if (Previous && Previous->Type != TT_DictLiteral) Previous->Type = TT_SelectorName; } @@ -683,7 +698,8 @@ private: CurrentToken->Type = TT_PointerOrReference; consumeToken(); if (CurrentToken && - CurrentToken->Previous->isOneOf(TT_BinaryOperator, tok::comma)) + CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, + tok::comma)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { @@ -740,8 +756,8 @@ private: void parseIncludeDirective() { if (CurrentToken && CurrentToken->is(tok::less)) { - next(); - while (CurrentToken) { + next(); + while (CurrentToken) { // Mark tokens up to the trailing line comments as implicit string // literals. if (CurrentToken->isNot(tok::comment) && @@ -781,9 +797,9 @@ private: void parseHasInclude() { if (!CurrentToken || !CurrentToken->is(tok::l_paren)) return; - next(); // '(' + next(); // '(' parseIncludeDirective(); - next(); // ')' + next(); // ')' } LineType parsePreprocessorDirective() { @@ -842,7 +858,7 @@ private: if (Tok->is(tok::l_paren)) parseParens(); else if (Tok->isOneOf(Keywords.kw___has_include, - Keywords.kw___has_include_next)) + Keywords.kw___has_include_next)) parseHasInclude(); } return Type; @@ -855,7 +871,7 @@ public: return parsePreprocessorDirective(); // Directly allow to 'import <string-literal>' to support protocol buffer - // definitions (code.google.com/p/protobuf) or missing "#" (either way we + // definitions (github.com/google/protobuf) or missing "#" (either way we // should not break the line). IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo(); if ((Style.Language == FormatStyle::LK_Java && @@ -933,11 +949,11 @@ private: // FIXME: Closure-library specific stuff should not be hard-coded but be // configurable. return Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) && - Tok.Next->Next && (Tok.Next->Next->TokenText == "module" || - Tok.Next->Next->TokenText == "provide" || - Tok.Next->Next->TokenText == "require" || - Tok.Next->Next->TokenText == "setTestOnly" || - Tok.Next->Next->TokenText == "forwardDeclare") && + Tok.Next->Next && + (Tok.Next->Next->TokenText == "module" || + Tok.Next->Next->TokenText == "provide" || + Tok.Next->Next->TokenText == "require" || + Tok.Next->Next->TokenText == "forwardDeclare") && Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren); } @@ -1054,8 +1070,7 @@ private: Current.Previous->is(TT_CtorInitializerColon)) { Contexts.back().IsExpression = true; Contexts.back().InCtorInitializer = true; - } else if (Current.Previous && - Current.Previous->is(TT_InheritanceColon)) { + } else if (Current.Previous && Current.Previous->is(TT_InheritanceColon)) { Contexts.back().InInheritanceList = true; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { for (FormatToken *Previous = Current.Previous; @@ -1104,6 +1119,11 @@ private: (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; + } else if (Current.is(tok::semi)) { + // Reset FirstStartOfName after finding a semicolon so that a for loop + // with multiple increment statements is not confused with a for loop + // having multiple variable declarations. + Contexts.back().FirstStartOfName = nullptr; } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) { AutoFound = true; } else if (Current.is(tok::arrow) && @@ -1113,10 +1133,10 @@ private: Current.NestingLevel == 0) { Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { - Current.Type = - determineStarAmpUsage(Current, Contexts.back().CanBeExpression && - Contexts.back().IsExpression, - Contexts.back().InTemplateArgument); + Current.Type = determineStarAmpUsage(Current, + Contexts.back().CanBeExpression && + Contexts.back().IsExpression, + Contexts.back().InTemplateArgument); } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { Current.Type = determinePlusMinusCaretUsage(Current); if (Current.is(TT_UnaryOperator) && Current.is(tok::caret)) @@ -1396,11 +1416,13 @@ private: if (NextToken->isOneOf(tok::comma, tok::semi)) return TT_PointerOrReference; - if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && - PrevToken->MatchingParen->Previous && - PrevToken->MatchingParen->Previous->isOneOf(tok::kw_typeof, - tok::kw_decltype)) - return TT_PointerOrReference; + if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen) { + FormatToken *TokenBeforeMatchingParen = + PrevToken->MatchingParen->getPreviousNonComment(); + if (TokenBeforeMatchingParen && + TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype)) + return TT_PointerOrReference; + } if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, @@ -1589,7 +1611,7 @@ private: if (Current->is(TT_ConditionalExpr)) return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && - (NextNonComment->is(TT_DictLiteral) || + (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) || ((Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) && NextNonComment->is(tok::less)))) @@ -1643,17 +1665,15 @@ private: /// \brief Parse unary operator expressions and surround them with fake /// parentheses if appropriate. void parseUnaryOperator() { - if (!Current || Current->isNot(TT_UnaryOperator)) { - parse(PrecedenceArrowAndPeriod); - return; + llvm::SmallVector<FormatToken *, 2> Tokens; + while (Current && Current->is(TT_UnaryOperator)) { + Tokens.push_back(Current); + next(); } - - FormatToken *Start = Current; - next(); - parseUnaryOperator(); - - // The actual precedence doesn't matter. - addFakeParenthesis(Start, prec::Unknown); + parse(PrecedenceArrowAndPeriod); + for (FormatToken *Token : llvm::reverse(Tokens)) + // The actual precedence doesn't matter. + addFakeParenthesis(Token, prec::Unknown); } void parseConditionalExpr() { @@ -1722,7 +1742,7 @@ void TokenAnnotator::setCommentLineLevels( static unsigned maxNestingDepth(const AnnotatedLine &Line) { unsigned Result = 0; - for (const auto* Tok = Line.First; Tok != nullptr; Tok = Tok->Next) + for (const auto *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) Result = std::max(Result, Tok->NestingLevel); return Result; } @@ -1764,7 +1784,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { // function declaration. static bool isFunctionDeclarationName(const FormatToken &Current, const AnnotatedLine &Line) { - auto skipOperatorName = [](const FormatToken* Next) -> const FormatToken* { + auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * { for (; Next; Next = Next->Next) { if (Next->is(TT_OverloadedOperatorLParen)) return Next; @@ -1772,8 +1792,8 @@ static bool isFunctionDeclarationName(const FormatToken &Current, continue; if (Next->isOneOf(tok::kw_new, tok::kw_delete)) { // For 'new[]' and 'delete[]'. - if (Next->Next && Next->Next->is(tok::l_square) && - Next->Next->Next && Next->Next->Next->is(tok::r_square)) + if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next && + Next->Next->Next->is(tok::r_square)) Next = Next->Next->Next; continue; } @@ -1872,7 +1892,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { } Line.First->TotalLength = - Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; + Line.First->IsMultiline ? Style.ColumnLimit + : Line.FirstStartColumn + Line.First->ColumnWidth; FormatToken *Current = Line.First->Next; bool InFunctionDecl = Line.MightBeFunctionDecl; while (Current) { @@ -2005,6 +2026,9 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return 100; + // Prefer breaking call chains (".foo") over empty "{}", "[]" or "()". + if (Left.opensScope() && Right.closesScope()) + return 200; } if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) @@ -2049,7 +2073,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::comment)) return 1000; - if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon)) + if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, + TT_CtorInitializerColon)) return 2; if (Right.isMemberAccess()) { @@ -2107,8 +2132,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; if (Left.is(tok::l_paren) && Left.Previous && - (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) - || Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) + (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) || + Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -2128,7 +2153,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous && Left.Previous->isLabelString() && (Left.NextOperator || Left.OperatorIndex != 0)) - return 45; + return 50; if (Right.is(tok::plus) && Left.isLabelString() && (Right.NextOperator || Right.OperatorIndex != 0)) return 25; @@ -2162,6 +2187,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Right) { if (Left.is(tok::kw_return) && Right.isNot(tok::semi)) return true; + if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java) + return true; if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty && Left.Tok.getObjCKeywordID() == tok::objc_property) return true; @@ -2178,8 +2205,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, : Style.SpacesInParentheses; if (Right.isOneOf(tok::semi, tok::comma)) return false; - if (Right.is(tok::less) && - Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList) + if (Right.is(tok::less) && Line.Type == LT_ObjCDecl && + Style.ObjCSpaceBeforeProtocolList) return true; if (Right.is(tok::less) && Left.is(tok::kw_template)) return Style.SpaceAfterTemplateKeyword; @@ -2201,15 +2228,23 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, Left.Previous->is(tok::kw_case)); if (Left.is(tok::l_square) && Right.is(tok::amp)) return false; - if (Right.is(TT_PointerOrReference)) - return (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) || - (Left.Tok.isLiteral() || (Left.is(tok::kw_const) && Left.Previous && - Left.Previous->is(tok::r_paren)) || + if (Right.is(TT_PointerOrReference)) { + if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) { + if (!Left.MatchingParen) + return true; + FormatToken *TokenBeforeMatchingParen = + Left.MatchingParen->getPreviousNonComment(); + if (!TokenBeforeMatchingParen || + !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype)) + return true; + } + return (Left.Tok.isLiteral() || (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && (Style.PointerAlignment != FormatStyle::PAS_Left || (Line.IsMultiVariableDeclStmt && (Left.NestingLevel == 0 || (Left.NestingLevel == 1 && Line.First->is(tok::kw_for))))))); + } if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && (!Left.is(TT_PointerOrReference) || (Style.PointerAlignment != FormatStyle::PAS_Right && @@ -2231,17 +2266,20 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::l_square)) return (Left.is(TT_ArrayInitializerLSquare) && Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) || - (Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets && - Right.isNot(tok::r_square)); + (Left.isOneOf(TT_ArraySubscriptLSquare, + TT_StructuredBindingLSquare) && + Style.SpacesInSquareBrackets && Right.isNot(tok::r_square)); if (Right.is(tok::r_square)) return Right.MatchingParen && ((Style.SpacesInContainerLiterals && Right.MatchingParen->is(TT_ArrayInitializerLSquare)) || (Style.SpacesInSquareBrackets && - Right.MatchingParen->is(TT_ArraySubscriptLSquare))); + Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare, + TT_StructuredBindingLSquare))); if (Right.is(tok::l_square) && !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, - TT_DesignatedInitializerLSquare) && + TT_DesignatedInitializerLSquare, + TT_StructuredBindingLSquare) && !Left.isOneOf(tok::numeric_constant, TT_DictLiteral)) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) @@ -2287,7 +2325,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(TT_TemplateCloser) && Left.MatchingParen && Left.MatchingParen->Previous && Left.MatchingParen->Previous->is(tok::period)) - // A.<B>DoSomething(); + // A.<B<C<...>>>DoSomething(); return false; if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square)) return false; @@ -2317,8 +2355,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.is(TT_JsFatArrow)) return true; // for await ( ... - if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && - Left.Previous && Left.Previous->is(tok::kw_for)) + if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous && + Left.Previous->is(tok::kw_for)) return true; if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) && Right.MatchingParen) { @@ -2341,18 +2379,31 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; if (Right.isOneOf(tok::l_brace, tok::l_square) && - Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) + Left.isOneOf(Keywords.kw_function, Keywords.kw_yield, + Keywords.kw_extends, Keywords.kw_implements)) return true; - // JS methods can use some keywords as names (e.g. `delete()`). - if (Right.is(tok::l_paren) && Line.MustBeDeclaration && - Left.Tok.getIdentifierInfo()) - return false; + if (Right.is(tok::l_paren)) { + // JS methods can use some keywords as names (e.g. `delete()`). + if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo()) + return false; + // Valid JS method names can include keywords, e.g. `foo.delete()` or + // `bar.instanceof()`. Recognize call positions by preceding period. + if (Left.Previous && Left.Previous->is(tok::period) && + Left.Tok.getIdentifierInfo()) + return false; + // Additional unary JavaScript operators that need a space after. + if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof, + tok::kw_void)) + return true; + } if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, tok::kw_const) || // "of" is only a keyword if it appears after another identifier - // (e.g. as "const x of y" in a for loop). + // (e.g. as "const x of y" in a for loop), or after a destructuring + // operation (const [x, y] of z, const {a, b} of c). (Left.is(Keywords.kw_of) && Left.Previous && - Left.Previous->Tok.getIdentifierInfo())) && + (Left.Previous->Tok.getIdentifierInfo() || + Left.Previous->isOneOf(tok::r_square, tok::r_brace)))) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous && @@ -2384,8 +2435,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; if (Right.is(TT_JsNonNullAssertion)) return false; - if (Left.is(TT_JsNonNullAssertion) && Right.is(Keywords.kw_as)) - return true; // "x! as string" + if (Left.is(TT_JsNonNullAssertion) && + Right.isOneOf(Keywords.kw_as, Keywords.kw_in)) + return true; // "x! as string", "x! in y" } else if (Style.Language == FormatStyle::LK_Java) { if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; @@ -2464,9 +2516,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return (Left.is(TT_TemplateOpener) && Style.Standard == FormatStyle::LS_Cpp03) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, - tok::kw___super, TT_TemplateCloser, TT_TemplateOpener)); + tok::kw___super, TT_TemplateCloser, + TT_TemplateOpener)); if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser))) return Style.SpacesInAngles; + // Space before TT_StructuredBindingLSquare. + if (Right.is(TT_StructuredBindingLSquare)) + return !Left.isOneOf(tok::amp, tok::ampamp) || + Style.PointerAlignment != FormatStyle::PAS_Right; + // Space before & or && following a TT_StructuredBindingLSquare. + if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) && + Right.isOneOf(tok::amp, tok::ampamp)) + return Style.PointerAlignment != FormatStyle::PAS_Left; if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) || (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && !Right.is(tok::r_paren))) @@ -2516,7 +2577,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return true; if (Left.is(tok::l_brace) && Line.Level == 0 && (Line.startsWith(tok::kw_enum) || - Line.startsWith(tok::kw_export, tok::kw_enum))) + Line.startsWith(tok::kw_const, tok::kw_enum) || + Line.startsWith(tok::kw_export, tok::kw_enum) || + Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum))) // JavaScript top-level enum key/value pairs are put on separate lines // instead of bin-packing. return true; @@ -2587,19 +2650,16 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; // Break only if we have multiple inheritance. - if (Style.BreakBeforeInheritanceComma && - Right.is(TT_InheritanceComma)) - return true; + if (Style.BreakBeforeInheritanceComma && Right.is(TT_InheritanceComma)) + return true; if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) // Raw string literals are special wrt. line breaks. The author has made a // deliberate choice and might have aligned the contents of the string // literal accordingly. Thus, we try keep existing line breaks. return Right.NewlinesBefore > 0; if ((Right.Previous->is(tok::l_brace) || - (Right.Previous->is(tok::less) && - Right.Previous->Previous && - Right.Previous->Previous->is(tok::equal)) - ) && + (Right.Previous->is(tok::less) && Right.Previous->Previous && + Right.Previous->Previous->is(tok::equal))) && Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { // Don't put enums or option definitions onto single lines in protocol // buffers. @@ -2609,6 +2669,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || + (Line.startsWith(tok::kw_typedef, tok::kw_enum) && + Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || (Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct); if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine) @@ -2639,13 +2701,16 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && - NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break, - tok::kw_throw, Keywords.kw_interface, - Keywords.kw_type, tok::kw_static, tok::kw_public, - tok::kw_private, tok::kw_protected, - Keywords.kw_readonly, Keywords.kw_abstract, - Keywords.kw_get, Keywords.kw_set)) + NonComment->isOneOf( + tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, + tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, + tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected, + Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get, + Keywords.kw_set, Keywords.kw_async, Keywords.kw_await)) return false; // Otherwise automatic semicolon insertion would trigger. + if (Left.Tok.getIdentifierInfo() && + Right.startsSequence(tok::l_square, tok::r_square)) + return false; // breaking in "foo[]" creates illegal TS type syntax. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; if (Left.is(TT_JsTypeColon)) @@ -2702,8 +2767,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // list. return Left.BlockKind == BK_BracedInit || (Left.is(TT_CtorInitializerColon) && - Style.BreakConstructorInitializers == - FormatStyle::BCIS_AfterColon); + Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon); if (Left.is(tok::question) && Right.is(tok::colon)) return false; if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) @@ -2820,7 +2884,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { - llvm::errs() << "AnnotatedTokens:\n"; + llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n"; const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore @@ -2828,10 +2892,9 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { << " T=" << getTokenTypeName(Tok->Type) << " S=" << Tok->SpacesRequiredBefore << " B=" << Tok->BlockParameterCount - << " BK=" << Tok->BlockKind - << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() - << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind - << " FakeLParens="; + << " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty + << " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength + << " PPK=" << Tok->PackingKind << " FakeLParens="; for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) llvm::errs() << Tok->FakeLParens[i] << "/"; llvm::errs() << " FakeRParens=" << Tok->FakeRParens; diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h index 805509533bf93..04a18d45b82e5 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h @@ -43,7 +43,8 @@ public: InPPDirective(Line.InPPDirective), MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), IsMultiVariableDeclStmt(false), Affected(false), - LeadingEmptyLinesAffected(false), ChildrenAffected(false) { + LeadingEmptyLinesAffected(false), ChildrenAffected(false), + FirstStartColumn(Line.FirstStartColumn) { assert(!Line.Tokens.empty()); // Calculate Next and Previous for all tokens. Note that we must overwrite @@ -127,6 +128,8 @@ public: /// \c True if one of this line's children intersects with an input range. bool ChildrenAffected; + unsigned FirstStartColumn; + private: // Disallow copying. AnnotatedLine(const AnnotatedLine &) = delete; diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp index 2005a2822924f..60dc1a7169d12 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -164,8 +164,7 @@ public: return nullptr; const AnnotatedLine *Current = *Next; IndentTracker.nextLine(*Current); - unsigned MergedLines = - tryFitMultipleLinesInOne(IndentTracker, Next, End); + unsigned MergedLines = tryFitMultipleLinesInOne(IndentTracker, Next, End); if (MergedLines > 0 && Style.ColumnLimit == 0) // Disallow line merging if there is a break at the start of one of the // input lines. @@ -228,14 +227,16 @@ private: if (Tok && Tok->getNamespaceToken()) return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock - ? tryMergeSimpleBlock(I, E, Limit) : 0; + ? tryMergeSimpleBlock(I, E, Limit) + : 0; if (Tok && Tok->is(tok::kw_typedef)) Tok = Tok->getNextNonComment(); if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union, - Keywords.kw_interface)) + tok::kw_extern, Keywords.kw_interface)) return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock - ? tryMergeSimpleBlock(I, E, Limit) : 0; + ? tryMergeSimpleBlock(I, E, Limit) + : 0; } // FIXME: TheLine->Level != 0 might or might not be the right check to do. @@ -279,15 +280,43 @@ private: } } + // Try to merge a function block with left brace unwrapped if (TheLine->Last->is(TT_FunctionLBrace) && TheLine->First != TheLine->Last) { return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0; } + // Try to merge a control statement block with left brace unwrapped + if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last && + TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { + return Style.AllowShortBlocksOnASingleLine + ? tryMergeSimpleBlock(I, E, Limit) + : 0; + } + // Try to merge a control statement block with left brace wrapped + if (I[1]->First->is(tok::l_brace) && + TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { + return Style.BraceWrapping.AfterControlStatement + ? tryMergeSimpleBlock(I, E, Limit) + : 0; + } + // Try to merge either empty or one-line block if is precedeed by control + // statement token + if (TheLine->First->is(tok::l_brace) && TheLine->First == TheLine->Last && + I != AnnotatedLines.begin() && + I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { + return Style.AllowShortBlocksOnASingleLine + ? tryMergeSimpleBlock(I - 1, E, Limit) + : 0; + } + // Try to merge a block with left brace wrapped that wasn't yet covered if (TheLine->Last->is(tok::l_brace)) { - return !Style.BraceWrapping.AfterFunction + return !Style.BraceWrapping.AfterFunction || + (I[1]->First->is(tok::r_brace) && + !Style.BraceWrapping.SplitEmptyRecord) ? tryMergeSimpleBlock(I, E, Limit) : 0; } + // Try to merge a function block with left brace wrapped if (I[1]->First->is(TT_FunctionLBrace) && Style.BraceWrapping.AfterFunction) { if (I[1]->Last->is(TT_LineComment)) @@ -382,7 +411,9 @@ private: return 0; unsigned NumStmts = 0; unsigned Length = 0; + bool EndsWithComment = false; bool InPPDirective = I[0]->InPPDirective; + const unsigned Level = I[0]->Level; for (; NumStmts < 3; ++NumStmts) { if (I + 1 + NumStmts == E) break; @@ -392,9 +423,26 @@ private: if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace)) break; if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch, - tok::kw_while, tok::comment) || - Line->Last->is(tok::comment)) + tok::kw_while) || + EndsWithComment) return 0; + if (Line->First->is(tok::comment)) { + if (Level != Line->Level) + return 0; + SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts; + for (; J != E; ++J) { + Line = *J; + if (Line->InPPDirective != InPPDirective) + break; + if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace)) + break; + if (Line->First->isNot(tok::comment) || Level != Line->Level) + return 0; + } + break; + } + if (Line->Last->is(tok::comment)) + EndsWithComment = true; Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space. } if (NumStmts == 0 || NumStmts == 3 || Length > Limit) @@ -425,11 +473,27 @@ private: tok::kw_for, tok::r_brace, Keywords.kw___except)) { if (!Style.AllowShortBlocksOnASingleLine) return 0; + // Don't merge when we can't except the case when + // the control statement block is empty if (!Style.AllowShortIfStatementsOnASingleLine && - Line.startsWith(tok::kw_if)) + Line.startsWith(tok::kw_if) && + !Style.BraceWrapping.AfterControlStatement && + !I[1]->First->is(tok::r_brace)) + return 0; + if (!Style.AllowShortIfStatementsOnASingleLine && + Line.startsWith(tok::kw_if) && + Style.BraceWrapping.AfterControlStatement && I + 2 != E && + !I[2]->First->is(tok::r_brace)) + return 0; + if (!Style.AllowShortLoopsOnASingleLine && + Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && + !Style.BraceWrapping.AfterControlStatement && + !I[1]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortLoopsOnASingleLine && - Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for)) + Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && + Style.BraceWrapping.AfterControlStatement && I + 2 != E && + !I[2]->First->is(tok::r_brace)) return 0; // FIXME: Consider an option to allow short exception handling clauses on // a single line. @@ -441,52 +505,78 @@ private: return 0; } - FormatToken *Tok = I[1]->First; - if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore && - (Tok->getNextNonComment() == nullptr || - Tok->getNextNonComment()->is(tok::semi))) { - // We merge empty blocks even if the line exceeds the column limit. - Tok->SpacesRequiredBefore = 0; - Tok->CanBreakBefore = true; - return 1; - } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) && - !startsExternCBlock(Line)) { - // We don't merge short records. - FormatToken *RecordTok = - Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First; - if (RecordTok && - RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, - Keywords.kw_interface)) - return 0; + if (Line.Last->is(tok::l_brace)) { + FormatToken *Tok = I[1]->First; + if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore && + (Tok->getNextNonComment() == nullptr || + Tok->getNextNonComment()->is(tok::semi))) { + // We merge empty blocks even if the line exceeds the column limit. + Tok->SpacesRequiredBefore = 0; + Tok->CanBreakBefore = true; + return 1; + } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) && + !startsExternCBlock(Line)) { + // We don't merge short records. + FormatToken *RecordTok = Line.First; + // Skip record modifiers. + while (RecordTok->Next && + RecordTok->isOneOf(tok::kw_typedef, tok::kw_export, + Keywords.kw_declare, Keywords.kw_abstract, + tok::kw_default)) + RecordTok = RecordTok->Next; + if (RecordTok && + RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, + Keywords.kw_interface)) + return 0; - // Check that we still have three lines and they fit into the limit. - if (I + 2 == E || I[2]->Type == LT_Invalid) - return 0; - Limit = limitConsideringMacros(I + 2, E, Limit); + // Check that we still have three lines and they fit into the limit. + if (I + 2 == E || I[2]->Type == LT_Invalid) + return 0; + Limit = limitConsideringMacros(I + 2, E, Limit); - if (!nextTwoLinesFitInto(I, Limit)) - return 0; + if (!nextTwoLinesFitInto(I, Limit)) + return 0; - // Second, check that the next line does not contain any braces - if it - // does, readability declines when putting it into a single line. - if (I[1]->Last->is(TT_LineComment)) - return 0; - do { - if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit) + // Second, check that the next line does not contain any braces - if it + // does, readability declines when putting it into a single line. + if (I[1]->Last->is(TT_LineComment)) return 0; - Tok = Tok->Next; - } while (Tok); + do { + if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit) + return 0; + Tok = Tok->Next; + } while (Tok); - // Last, check that the third line starts with a closing brace. - Tok = I[2]->First; - if (Tok->isNot(tok::r_brace)) - return 0; + // Last, check that the third line starts with a closing brace. + Tok = I[2]->First; + if (Tok->isNot(tok::r_brace)) + return 0; + + // Don't merge "if (a) { .. } else {". + if (Tok->Next && Tok->Next->is(tok::kw_else)) + return 0; - // Don't merge "if (a) { .. } else {". - if (Tok->Next && Tok->Next->is(tok::kw_else)) + return 2; + } + } else if (I[1]->First->is(tok::l_brace)) { + if (I[1]->Last->is(TT_LineComment)) return 0; - return 2; + // Check for Limit <= 2 to account for the " {". + if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I))) + return 0; + Limit -= 2; + unsigned MergedLines = 0; + if (Style.AllowShortBlocksOnASingleLine || + (I[1]->First == I[1]->Last && I + 2 != E && + I[2]->First->is(tok::r_brace))) { + MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); + // If we managed to merge the block, count the statement header, which + // is on a separate line. + if (MergedLines > 0) + ++MergedLines; + } + return MergedLines; } return 0; } @@ -574,7 +664,9 @@ public: /// \brief Formats an \c AnnotatedLine and returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. - virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + virtual unsigned formatLine(const AnnotatedLine &Line, + unsigned FirstIndent, + unsigned FirstStartColumn, bool DryRun) = 0; protected: @@ -645,7 +737,8 @@ protected: *Child->First, /*Newlines=*/0, /*Spaces=*/1, /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective); } - Penalty += formatLine(*Child, State.Column + 1, DryRun); + Penalty += + formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun); State.Column += 1 + Child->Last->TotalLength; return true; @@ -671,10 +764,10 @@ public: /// \brief Formats the line, simply keeping all of the input's line breaking /// decisions. unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, - bool DryRun) override { + unsigned FirstStartColumn, bool DryRun) override { assert(!DryRun); - LineState State = - Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false); + LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn, + &Line, /*DryRun=*/false); while (State.NextToken) { bool Newline = Indenter->mustBreak(State) || @@ -697,9 +790,10 @@ public: /// \brief Puts all tokens into a single line. unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, - bool DryRun) override { + unsigned FirstStartColumn, bool DryRun) override { unsigned Penalty = 0; - LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun); + LineState State = + Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun); while (State.NextToken) { formatChildren(State, /*Newline=*/false, DryRun, Penalty); Indenter->addTokenToState( @@ -721,8 +815,9 @@ public: /// \brief Formats the line by finding the best line breaks with line lengths /// below the column limit. unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, - bool DryRun) override { - LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun); + unsigned FirstStartColumn, bool DryRun) override { + LineState State = + Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun); // If the ObjC method declaration does not fit on a line, we should format // it with one arg per line. @@ -763,7 +858,8 @@ private: /// \brief The BFS queue type. typedef std::priority_queue<QueueItem, std::vector<QueueItem>, - std::greater<QueueItem>> QueueType; + std::greater<QueueItem>> + QueueType; /// \brief Analyze the entire solution space starting from \p InitialState. /// @@ -888,7 +984,10 @@ private: unsigned UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun, int AdditionalIndent, - bool FixBadIndentation) { + bool FixBadIndentation, + unsigned FirstStartColumn, + unsigned NextStartColumn, + unsigned LastStartColumn) { LineJoiner Joiner(Style, Keywords, Lines); // Try to look up already computed penalty in DryRun-mode. @@ -908,9 +1007,10 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, // The minimum level of consecutive lines that have been formatted. unsigned RangeMinLevel = UINT_MAX; + bool FirstLine = true; for (const AnnotatedLine *Line = Joiner.getNextMergedLine(DryRun, IndentTracker); - Line; Line = NextLine) { + Line; Line = NextLine, FirstLine = false) { const AnnotatedLine &TheLine = *Line; unsigned Indent = IndentTracker.getIndent(); @@ -934,8 +1034,12 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, } if (ShouldFormat && TheLine.Type != LT_Invalid) { - if (!DryRun) - formatFirstToken(TheLine, PreviousLine, Indent); + if (!DryRun) { + bool LastLine = Line->First->is(tok::eof); + formatFirstToken(TheLine, PreviousLine, + Indent, + LastLine ? LastStartColumn : NextStartColumn + Indent); + } NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker); unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine); @@ -944,16 +1048,18 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, (TheLine.Type == LT_ImportStatement && (Style.Language != FormatStyle::LK_JavaScript || !Style.JavaScriptWrapImports)); - if (Style.ColumnLimit == 0) NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this) - .formatLine(TheLine, Indent, DryRun); + .formatLine(TheLine, NextStartColumn + Indent, + FirstLine ? FirstStartColumn : 0, DryRun); else if (FitsIntoOneLine) Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this) - .formatLine(TheLine, Indent, DryRun); + .formatLine(TheLine, NextStartColumn + Indent, + FirstLine ? FirstStartColumn : 0, DryRun); else Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this) - .formatLine(TheLine, Indent, DryRun); + .formatLine(TheLine, NextStartColumn + Indent, + FirstLine ? FirstStartColumn : 0, DryRun); RangeMinLevel = std::min(RangeMinLevel, TheLine.Level); } else { // If no token in the current line is affected, we still need to format @@ -976,6 +1082,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, // Format the first token. if (ReformatLeadingWhitespace) formatFirstToken(TheLine, PreviousLine, + TheLine.First->OriginalColumn, TheLine.First->OriginalColumn); else Whitespaces->addUntouchableToken(*TheLine.First, @@ -998,12 +1105,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines, void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line, const AnnotatedLine *PreviousLine, - unsigned Indent) { - FormatToken& RootToken = *Line.First; + unsigned Indent, + unsigned NewlineIndent) { + FormatToken &RootToken = *Line.First; if (RootToken.is(tok::eof)) { unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u); - Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0, - /*StartOfTokenColumn=*/0); + unsigned TokenIndent = Newlines ? NewlineIndent : 0; + Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent, + TokenIndent); return; } unsigned Newlines = @@ -1013,6 +1122,9 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line, (!RootToken.Next || (RootToken.Next->is(tok::semi) && !RootToken.Next->Next))) Newlines = std::min(Newlines, 1u); + // Remove empty lines at the start of nested blocks (lambdas/arrow functions) + if (PreviousLine == nullptr && Line.Level > 0) + Newlines = std::min(Newlines, 1u); if (Newlines == 0 && !RootToken.IsFirst) Newlines = 1; if (RootToken.IsFirst && !RootToken.HasUnescapedNewline) @@ -1035,6 +1147,13 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line, (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline)) Newlines = std::min(1u, Newlines); + if (Newlines) + Indent = NewlineIndent; + + // Preprocessor directives get indented after the hash, if indented. + if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement) + Indent = 0; + Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent, Line.InPPDirective && !RootToken.HasUnescapedNewline); diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h index 55f0d1cac689f..6432ca83a4c95 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h @@ -35,19 +35,22 @@ public: const SourceManager &SourceMgr, FormattingAttemptStatus *Status) : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style), - Keywords(Keywords), SourceMgr(SourceMgr), - Status(Status) {} + Keywords(Keywords), SourceMgr(SourceMgr), Status(Status) {} /// \brief Format the current block and return the penalty. unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun = false, int AdditionalIndent = 0, - bool FixBadIndentation = false); + bool FixBadIndentation = false, + unsigned FirstStartColumn = 0, + unsigned NextStartColumn = 0, + unsigned LastStartColumn = 0); private: /// \brief Add a new line and the required indent before the first Token /// of the \c UnwrappedLine if there was no structural parsing error. void formatFirstToken(const AnnotatedLine &Line, - const AnnotatedLine *PreviousLine, unsigned Indent); + const AnnotatedLine *PreviousLine, unsigned Indent, + unsigned NewlineIndent); /// \brief Returns the column limit for a line, taking into account whether we /// need an escaped newline due to a continued preprocessor directive. diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp index faac5a371c260..b8608dcac9c7e 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp @@ -18,6 +18,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> + #define DEBUG_TYPE "format-parser" namespace clang { @@ -56,8 +58,7 @@ private: }; static bool isLineComment(const FormatToken &FormatTok) { - return FormatTok.is(tok::comment) && - FormatTok.TokenText.startswith("//"); + return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*"); } // Checks if \p FormatTok is a line comment that continues the line comment @@ -226,15 +227,21 @@ private: UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style, const AdditionalKeywords &Keywords, + unsigned FirstStartColumn, ArrayRef<FormatToken *> Tokens, UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), CurrentLines(&Lines), Style(Style), Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr), - Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {} + Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1), + IfNdefCondition(nullptr), FoundIncludeGuardStart(false), + IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {} void UnwrappedLineParser::reset() { PPBranchLevel = -1; + IfNdefCondition = nullptr; + FoundIncludeGuardStart = false; + IncludeGuardRejected = false; Line.reset(new UnwrappedLine); CommentsBeforeNextToken.clear(); FormatTok = nullptr; @@ -243,10 +250,12 @@ void UnwrappedLineParser::reset() { CurrentLines = &Lines; DeclarationScopeStack.clear(); PPStack.clear(); + Line->FirstStartColumn = FirstStartColumn; } void UnwrappedLineParser::parse() { IndexedTokenSource TokenSource(AllTokens); + Line->FirstStartColumn = FirstStartColumn; do { DEBUG(llvm::dbgs() << "----\n"); reset(); @@ -326,6 +335,12 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { break; case tok::kw_default: case tok::kw_case: + if (Style.Language == FormatStyle::LK_JavaScript && + Line->MustBeDeclaration) { + // A 'case: string' style field declaration. + parseStructuralElement(); + break; + } if (!SwitchLabelEncountered && (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1))) ++Line->Level; @@ -346,7 +361,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // definitions, too. unsigned StoredPosition = Tokens->getPosition(); FormatToken *Tok = FormatTok; - const FormatToken *PrevTok = getPreviousToken(); + const FormatToken *PrevTok = Tok->Previous; // Keep a stack of positions of lbrace tokens. We will // update information about whether an lbrace starts a // braced init list or a different block during the loop. @@ -364,13 +379,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { switch (Tok->Tok.getKind()) { case tok::l_brace: if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) { - if (PrevTok->is(tok::colon)) - // A colon indicates this code is in a type, or a braced list - // following a label in an object literal ({a: {b: 1}}). The code - // below could be confused by semicolons between the individual - // members in a type member list, which would normally trigger - // BK_Block. In both cases, this must be parsed as an inline braced - // init. + if (PrevTok->isOneOf(tok::colon, tok::less)) + // A ':' indicates this code is in a type, or a braced list + // following a label in an object literal ({a: {b: 1}}). + // A '<' could be an object used in a comparison, but that is nonsense + // code (can never return true), so more likely it is a generic type + // argument (`X<{a: string; b: number}>`). + // The code below could be confused by semicolons between the + // individual members in a type member list, which would normally + // trigger BK_Block. In both cases, this must be parsed as an inline + // braced init. Tok->BlockKind = BK_BracedInit; else if (PrevTok->is(tok::r_paren)) // `) { }` can only occur in function or method declarations in JS. @@ -452,6 +470,21 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { FormatTok = Tokens->setPosition(StoredPosition); } +template <class T> +static inline void hash_combine(std::size_t &seed, const T &v) { + std::hash<T> hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +size_t UnwrappedLineParser::computePPHash() const { + size_t h = 0; + for (const auto &i : PPStack) { + hash_combine(h, size_t(i.Kind)); + hash_combine(h, i.Line); + } + return h; +} + void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, bool MunchSemi) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && @@ -459,16 +492,21 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); FormatTok->BlockKind = BK_Block; + size_t PPStartHash = computePPHash(); + unsigned InitialLevel = Line->Level; - nextToken(); + nextToken(/*LevelDifference=*/AddLevel ? 1 : 0); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); + size_t NbPreprocessorDirectives = + CurrentLines == &Lines ? PreprocessorDirectives.size() : 0; addUnwrappedLine(); - size_t OpeningLineIndex = CurrentLines->empty() - ? (UnwrappedLine::kInvalidIndex) - : (CurrentLines->size() - 1); + size_t OpeningLineIndex = + CurrentLines->empty() + ? (UnwrappedLine::kInvalidIndex) + : (CurrentLines->size() - 1 - NbPreprocessorDirectives); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); @@ -486,7 +524,10 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, return; } - nextToken(); // Munch the closing brace. + size_t PPEndHash = computePPHash(); + + // Munch the closing brace. + nextToken(/*LevelDifference=*/AddLevel ? -1 : 0); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); @@ -494,11 +535,14 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, if (MunchSemi && FormatTok->Tok.is(tok::semi)) nextToken(); Line->Level = InitialLevel; - Line->MatchingOpeningBlockLineIndex = OpeningLineIndex; - if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) { - // Update the opening line to add the forward reference as well - (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex = - CurrentLines->size() - 1; + + if (PPStartHash == PPEndHash) { + Line->MatchingOpeningBlockLineIndex = OpeningLineIndex; + if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) { + // Update the opening line to add the forward reference as well + (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex = + CurrentLines->size() - 1; + } } } @@ -555,9 +599,8 @@ void UnwrappedLineParser::parseChildBlock() { FormatTok->BlockKind = BK_Block; nextToken(); { - bool SkipIndent = - (Style.Language == FormatStyle::LK_JavaScript && - (isGoogScope(*Line) || isIIFE(*Line, Keywords))); + bool SkipIndent = (Style.Language == FormatStyle::LK_JavaScript && + (isGoogScope(*Line) || isIIFE(*Line, Keywords))); ScopedLineState LineState(*this); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, /*MustBeDeclaration=*/false); @@ -606,10 +649,15 @@ void UnwrappedLineParser::parsePPDirective() { } void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) { - if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable)) - PPStack.push_back(PP_Unreachable); + size_t Line = CurrentLines->size(); + if (CurrentLines == &PreprocessorDirectives) + Line += Lines.size(); + + if (Unreachable || + (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable)) + PPStack.push_back({PP_Unreachable, Line}); else - PPStack.push_back(PP_Conditional); + PPStack.push_back({PP_Conditional, Line}); } void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) { @@ -643,7 +691,7 @@ void UnwrappedLineParser::conditionalCompilationEnd() { } } // Guard against #endif's without #if. - if (PPBranchLevel > 0) + if (PPBranchLevel > -1) --PPBranchLevel; if (!PPChainBranchIndex.empty()) PPChainBranchIndex.pop(); @@ -660,12 +708,35 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) { if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG") Unreachable = true; conditionalCompilationStart(Unreachable); + FormatToken *IfCondition = FormatTok; + // If there's a #ifndef on the first line, and the only lines before it are + // comments, it could be an include guard. + bool MaybeIncludeGuard = IfNDef; + if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard) { + for (auto &Line : Lines) { + if (!Line.Tokens.front().Tok->is(tok::comment)) { + MaybeIncludeGuard = false; + IncludeGuardRejected = true; + break; + } + } + } + --PPBranchLevel; parsePPUnknown(); + ++PPBranchLevel; + if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard) + IfNdefCondition = IfCondition; } void UnwrappedLineParser::parsePPElse() { + // If a potential include guard has an #else, it's not an include guard. + if (FoundIncludeGuardStart && PPBranchLevel == 0) + FoundIncludeGuardStart = false; conditionalCompilationAlternative(); + if (PPBranchLevel > -1) + --PPBranchLevel; parsePPUnknown(); + ++PPBranchLevel; } void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } @@ -673,6 +744,16 @@ void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } void UnwrappedLineParser::parsePPEndIf() { conditionalCompilationEnd(); parsePPUnknown(); + // If the #endif of a potential include guard is the last thing in the file, + // then we count it as a real include guard and subtract one from every + // preprocessor indent. + unsigned TokenPosition = Tokens->getPosition(); + FormatToken *PeekNext = AllTokens[TokenPosition]; + if (FoundIncludeGuardStart && PPBranchLevel == -1 && PeekNext->is(tok::eof) && + Style.IndentPPDirectives != FormatStyle::PPDIS_None) + for (auto &Line : Lines) + if (Line.InPPDirective && Line.Level > 0) + --Line.Level; } void UnwrappedLineParser::parsePPDefine() { @@ -682,14 +763,26 @@ void UnwrappedLineParser::parsePPDefine() { parsePPUnknown(); return; } + if (IfNdefCondition && IfNdefCondition->TokenText == FormatTok->TokenText) { + FoundIncludeGuardStart = true; + for (auto &Line : Lines) { + if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) { + FoundIncludeGuardStart = false; + break; + } + } + } + IfNdefCondition = nullptr; nextToken(); if (FormatTok->Tok.getKind() == tok::l_paren && FormatTok->WhitespaceRange.getBegin() == FormatTok->WhitespaceRange.getEnd()) { parseParens(); } + if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + Line->Level += PPBranchLevel + 1; addUnwrappedLine(); - Line->Level = 1; + ++Line->Level; // Errors during a preprocessor directive can only affect the layout of the // preprocessor directive, and thus we ignore them. An alternative approach @@ -703,7 +796,10 @@ void UnwrappedLineParser::parsePPUnknown() { do { nextToken(); } while (!eof()); + if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + Line->Level += PPBranchLevel + 1; addUnwrappedLine(); + IfNdefCondition = nullptr; } // Here we blacklist certain tokens that are not usually the first token in an @@ -746,8 +842,8 @@ static bool mustBeJSIdent(const AdditionalKeywords &Keywords, Keywords.kw_function, Keywords.kw_import, Keywords.kw_is, Keywords.kw_let, Keywords.kw_var, tok::kw_const, Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements, - Keywords.kw_instanceof, Keywords.kw_interface, - Keywords.kw_throws, Keywords.kw_from)); + Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws, + Keywords.kw_from)); } static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, @@ -800,11 +896,14 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous); bool PreviousStartsTemplateExpr = Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${"); - if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) { - // If the token before the previous one is an '@', the previous token is an - // annotation and can precede another identifier/value. - const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok; - if (PrePrevious->is(tok::at)) + if (PreviousMustBeValue || Previous->is(tok::r_paren)) { + // If the line contains an '@' sign, the previous token might be an + // annotation, which can precede another identifier/value. + bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(), + [](UnwrappedLineNode &LineNode) { + return LineNode.Tok->is(tok::at); + }) != Line->Tokens.end(); + if (HasAt) return; } if (Next->is(tok::exclaim) && PreviousMustBeValue) @@ -817,7 +916,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, tok::minusminus))) return addUnwrappedLine(); - if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next)) + if ((PreviousMustBeValue || Previous->is(tok::r_paren)) && + isJSDeclOrStmt(Keywords, Next)) return addUnwrappedLine(); } @@ -922,13 +1022,22 @@ void UnwrappedLineParser::parseStructuralElement() { parseDoWhile(); return; case tok::kw_switch: + if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) + // 'switch: string' field declaration. + break; parseSwitch(); return; case tok::kw_default: + if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) + // 'default: string' field declaration. + break; nextToken(); parseLabel(); return; case tok::kw_case: + if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) + // 'case: string' field declaration. + break; parseCaseLabel(); return; case tok::kw_try: @@ -940,7 +1049,12 @@ void UnwrappedLineParser::parseStructuralElement() { if (FormatTok->Tok.is(tok::string_literal)) { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false); + if (Style.BraceWrapping.AfterExternBlock) { + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/true); + } else { + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false); + } addUnwrappedLine(); return; } @@ -996,7 +1110,7 @@ void UnwrappedLineParser::parseStructuralElement() { break; } do { - const FormatToken *Previous = getPreviousToken(); + const FormatToken *Previous = FormatTok->Previous; switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); @@ -1186,7 +1300,7 @@ void UnwrappedLineParser::parseStructuralElement() { nextToken(); parseBracedList(); } else if (Style.Language == FormatStyle::LK_Proto && - FormatTok->Tok.is(tok::less)) { + FormatTok->Tok.is(tok::less)) { nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*ClosingBraceKind=*/tok::greater); @@ -1210,14 +1324,6 @@ bool UnwrappedLineParser::tryToParseLambda() { nextToken(); return false; } - const FormatToken* Previous = getPreviousToken(); - if (Previous && - (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, - tok::kw_delete) || - Previous->closesScope() || Previous->isSimpleTypeSpecifier())) { - nextToken(); - return false; - } assert(FormatTok->is(tok::l_square)); FormatToken &LSquare = *FormatTok; if (!tryToParseLambdaIntroducer()) @@ -1260,49 +1366,18 @@ bool UnwrappedLineParser::tryToParseLambda() { } bool UnwrappedLineParser::tryToParseLambdaIntroducer() { - nextToken(); - if (FormatTok->is(tok::equal)) { - nextToken(); - if (FormatTok->is(tok::r_square)) { - nextToken(); - return true; - } - if (FormatTok->isNot(tok::comma)) - return false; - nextToken(); - } else if (FormatTok->is(tok::amp)) { - nextToken(); - if (FormatTok->is(tok::r_square)) { - nextToken(); - return true; - } - if (!FormatTok->isOneOf(tok::comma, tok::identifier)) { - return false; - } - if (FormatTok->is(tok::comma)) - nextToken(); - } else if (FormatTok->is(tok::r_square)) { + const FormatToken *Previous = FormatTok->Previous; + if (Previous && + (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, + tok::kw_delete) || + FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() || + Previous->isSimpleTypeSpecifier())) { nextToken(); - return true; + return false; } - do { - if (FormatTok->is(tok::amp)) - nextToken(); - if (!FormatTok->isOneOf(tok::identifier, tok::kw_this)) - return false; - nextToken(); - if (FormatTok->is(tok::ellipsis)) - nextToken(); - if (FormatTok->is(tok::comma)) { - nextToken(); - } else if (FormatTok->is(tok::r_square)) { - nextToken(); - return true; - } else { - return false; - } - } while (!eof()); - return false; + nextToken(); + parseSquare(/*LambdaIntroducer=*/true); + return true; } void UnwrappedLineParser::tryToParseJSFunction() { @@ -1419,6 +1494,15 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, nextToken(); parseBracedList(); break; + case tok::less: + if (Style.Language == FormatStyle::LK_Proto) { + nextToken(); + parseBracedList(/*ContinueOnSemicolons=*/false, + /*ClosingBraceKind=*/tok::greater); + } else { + nextToken(); + } + break; case tok::semi: // JavaScript (or more precisely TypeScript) can have semicolons in braced // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be @@ -1495,10 +1579,12 @@ void UnwrappedLineParser::parseParens() { } while (!eof()); } -void UnwrappedLineParser::parseSquare() { - assert(FormatTok->Tok.is(tok::l_square) && "'[' expected."); - if (tryToParseLambda()) - return; +void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) { + if (!LambdaIntroducer) { + assert(FormatTok->Tok.is(tok::l_square) && "'[' expected."); + if (tryToParseLambda()) + return; + } do { switch (FormatTok->Tok.getKind()) { case tok::l_paren: @@ -1939,6 +2025,17 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { ((Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) && FormatTok->isOneOf(tok::period, tok::comma))) { + if (Style.Language == FormatStyle::LK_JavaScript && + FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) { + // JavaScript/TypeScript supports inline object types in + // extends/implements positions: + // class Foo implements {bar: number} { } + nextToken(); + if (FormatTok->is(tok::l_brace)) { + tryToParseBracedList(); + continue; + } + } bool IsNonMacroIdentifier = FormatTok->is(tok::identifier) && FormatTok->TokenText != FormatTok->TokenText.upper(); @@ -2090,7 +2187,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { while (!eof()) { if (FormatTok->is(tok::semi)) return; - if (Line->Tokens.size() == 0) { + if (Line->Tokens.empty()) { // Common issue: Automatic Semicolon Insertion wrapped the line, so the // import statement should terminate. return; @@ -2107,14 +2204,15 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, StringRef Prefix = "") { - llvm::dbgs() << Prefix << "Line(" << Line.Level << ")" + llvm::dbgs() << Prefix << "Line(" << Line.Level + << ", FSC=" << Line.FirstStartColumn << ")" << (Line.InPPDirective ? " MACRO" : "") << ": "; for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(), E = Line.Tokens.end(); I != E; ++I) { llvm::dbgs() << I->Tok->Tok.getName() << "[" - << "T=" << I->Tok->Type - << ", OC=" << I->Tok->OriginalColumn << "] "; + << "T=" << I->Tok->Type << ", OC=" << I->Tok->OriginalColumn + << "] "; } for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(), E = Line.Tokens.end(); @@ -2140,12 +2238,15 @@ void UnwrappedLineParser::addUnwrappedLine() { CurrentLines->push_back(std::move(*Line)); Line->Tokens.clear(); Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex; + Line->FirstStartColumn = 0; if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) { CurrentLines->append( std::make_move_iterator(PreprocessorDirectives.begin()), std::make_move_iterator(PreprocessorDirectives.end())); PreprocessorDirectives.clear(); } + // Disconnect the current token from the last token on the previous line. + FormatTok->Previous = nullptr; } bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); } @@ -2287,23 +2388,17 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) { CommentsBeforeNextToken.clear(); } -void UnwrappedLineParser::nextToken() { +void UnwrappedLineParser::nextToken(int LevelDifference) { if (eof()) return; flushComments(isOnNewLine(*FormatTok)); pushToken(FormatTok); + FormatToken *Previous = FormatTok; if (Style.Language != FormatStyle::LK_JavaScript) - readToken(); + readToken(LevelDifference); else readTokenWithJavaScriptASI(); -} - -const FormatToken *UnwrappedLineParser::getPreviousToken() { - // FIXME: This is a dirty way to access the previous token. Find a better - // solution. - if (!Line || Line->Tokens.empty()) - return nullptr; - return Line->Tokens.back().Tok; + FormatTok->Previous = Previous; } void UnwrappedLineParser::distributeComments( @@ -2343,8 +2438,7 @@ void UnwrappedLineParser::distributeComments( } for (unsigned i = 0, e = Comments.size(); i < e; ++i) { FormatToken *FormatTok = Comments[i]; - if (HasTrailAlignedWithNextToken && - i == StartOfTrailAlignedWithNextToken) { + if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) { FormatTok->ContinuesLineCommentSection = false; } else { FormatTok->ContinuesLineCommentSection = @@ -2362,7 +2456,7 @@ void UnwrappedLineParser::distributeComments( } } -void UnwrappedLineParser::readToken() { +void UnwrappedLineParser::readToken(int LevelDifference) { SmallVector<FormatToken *, 1> Comments; do { FormatTok = Tokens->getNextToken(); @@ -2375,6 +2469,10 @@ void UnwrappedLineParser::readToken() { // directives only after that unwrapped line was finished later. bool SwitchToPreprocessorLines = !Line->Tokens.empty(); ScopedLineState BlockState(*this, SwitchToPreprocessorLines); + assert((LevelDifference >= 0 || + static_cast<unsigned>(-LevelDifference) <= Line->Level) && + "LevelDifference makes Line->Level negative"); + Line->Level += LevelDifference; // Comments stored before the preprocessor directive need to be output // before the preprocessor directive, at the same level as the // preprocessor directive, as we consider them to apply to the directive. @@ -2395,7 +2493,7 @@ void UnwrappedLineParser::readToken() { FormatTok->MustBreakBefore = true; } - if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) && + if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) && !Line->InPPDirective) { continue; } diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h index a2aa2f006728e..1d8ccabbd0f8e 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h @@ -56,6 +56,8 @@ struct UnwrappedLine { size_t MatchingOpeningBlockLineIndex; static const size_t kInvalidIndex = -1; + + unsigned FirstStartColumn = 0; }; class UnwrappedLineConsumer { @@ -71,6 +73,7 @@ class UnwrappedLineParser { public: UnwrappedLineParser(const FormatStyle &Style, const AdditionalKeywords &Keywords, + unsigned FirstStartColumn, ArrayRef<FormatToken *> Tokens, UnwrappedLineConsumer &Callback); @@ -96,7 +99,7 @@ private: bool parseBracedList(bool ContinueOnSemicolons = false, tok::TokenKind ClosingBraceKind = tok::r_brace); void parseParens(); - void parseSquare(); + void parseSquare(bool LambdaIntroducer = false); void parseIfThenElse(); void parseTryCatch(); void parseForOrWhileLoop(); @@ -123,9 +126,12 @@ private: void tryToParseJSFunction(); void addUnwrappedLine(); bool eof() const; - void nextToken(); - const FormatToken *getPreviousToken(); - void readToken(); + // LevelDifference is the difference of levels after and before the current + // token. For example: + // - if the token is '{' and opens a block, LevelDifference is 1. + // - if the token is '}' and closes a block, LevelDifference is -1. + void nextToken(int LevelDifference = 0); + void readToken(int LevelDifference = 0); // Decides which comment tokens should be added to the current line and which // should be added as comments before the next token. @@ -156,6 +162,11 @@ private: bool isOnNewLine(const FormatToken &FormatTok); + // Compute hash of the current preprocessor branch. + // This is used to identify the different branches, and thus track if block + // open and close in the same branch. + size_t computePPHash() const; + // FIXME: We are constantly running into bugs where Line.Level is incorrectly // subtracted from beyond 0. Introduce a method to subtract from Line.Level // and use that everywhere in the Parser. @@ -174,7 +185,7 @@ private: // Preprocessor directives are parsed out-of-order from other unwrapped lines. // Thus, we need to keep a list of preprocessor directives to be reported - // after an unwarpped line that has been started was finished. + // after an unwrapped line that has been started was finished. SmallVector<UnwrappedLine, 4> PreprocessorDirectives; // New unwrapped lines are added via CurrentLines. @@ -207,8 +218,14 @@ private: PP_Unreachable // #if 0 or a conditional preprocessor block inside #if 0 }; + struct PPBranch { + PPBranch(PPBranchKind Kind, size_t Line) : Kind(Kind), Line(Line) {} + PPBranchKind Kind; + size_t Line; + }; + // Keeps a stack of currently active preprocessor branching directives. - SmallVector<PPBranchKind, 16> PPStack; + SmallVector<PPBranch, 16> PPStack; // The \c UnwrappedLineParser re-parses the code for each combination // of preprocessor branches that can be taken. @@ -231,6 +248,15 @@ private: // sequence. std::stack<int> PPChainBranchIndex; + // Contains the #ifndef condition for a potential include guard. + FormatToken *IfNdefCondition; + bool FoundIncludeGuardStart; + bool IncludeGuardRejected; + // Contains the first start column where the source begins. This is zero for + // normal source code and may be nonzero when formatting a code fragment that + // does not start at the beginning of the file. + unsigned FirstStartColumn; + friend class ScopedLineState; friend class CompoundStatementIndenter; }; @@ -243,8 +269,9 @@ struct UnwrappedLineNode { SmallVector<UnwrappedLine, 0> Children; }; -inline UnwrappedLine::UnwrappedLine() : Level(0), InPPDirective(false), - MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {} +inline UnwrappedLine::UnwrappedLine() + : Level(0), InPPDirective(false), MustBeDeclaration(false), + MatchingOpeningBlockLineIndex(kInvalidIndex) {} } // end namespace format } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp index fb4f59fbc9bcf..ef0c7a7d5a45e 100644 --- a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp @@ -26,6 +26,45 @@ namespace format { namespace { +// The order of using declaration is defined as follows: +// Split the strings by "::" and discard any initial empty strings. The last +// element of each list is a non-namespace name; all others are namespace +// names. Sort the lists of names lexicographically, where the sort order of +// individual names is that all non-namespace names come before all namespace +// names, and within those groups, names are in case-insensitive lexicographic +// order. +int compareLabels(StringRef A, StringRef B) { + SmallVector<StringRef, 2> NamesA; + A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + SmallVector<StringRef, 2> NamesB; + B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + size_t SizeA = NamesA.size(); + size_t SizeB = NamesB.size(); + for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) { + if (I + 1 == SizeA) { + // I is the last index of NamesA and NamesA[I] is a non-namespace name. + + // Non-namespace names come before all namespace names. + if (SizeB > SizeA) + return -1; + + // Two names within a group compare case-insensitively. + return NamesA[I].compare_lower(NamesB[I]); + } + + // I is the last index of NamesB and NamesB[I] is a non-namespace name. + // Non-namespace names come before all namespace names. + if (I + 1 == SizeB) + return 1; + + // Two namespaces names within a group compare case-insensitively. + int C = NamesA[I].compare_lower(NamesB[I]); + if (C != 0) + return C; + } + return 0; +} + struct UsingDeclaration { const AnnotatedLine *Line; std::string Label; @@ -34,7 +73,7 @@ struct UsingDeclaration { : Line(Line), Label(Label) {} bool operator<(const UsingDeclaration &Other) const { - return Label < Other.Label; + return compareLabels(Label, Other.Label) < 0; } }; @@ -76,10 +115,42 @@ std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) { void endUsingDeclarationBlock( SmallVectorImpl<UsingDeclaration> *UsingDeclarations, const SourceManager &SourceMgr, tooling::Replacements *Fixes) { + bool BlockAffected = false; + for (const UsingDeclaration &Declaration : *UsingDeclarations) { + if (Declaration.Line->Affected) { + BlockAffected = true; + break; + } + } + if (!BlockAffected) { + UsingDeclarations->clear(); + return; + } SmallVector<UsingDeclaration, 4> SortedUsingDeclarations( UsingDeclarations->begin(), UsingDeclarations->end()); - std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end()); + std::stable_sort(SortedUsingDeclarations.begin(), + SortedUsingDeclarations.end()); + SortedUsingDeclarations.erase( + std::unique(SortedUsingDeclarations.begin(), + SortedUsingDeclarations.end(), + [](const UsingDeclaration &a, const UsingDeclaration &b) { + return a.Label == b.Label; + }), + SortedUsingDeclarations.end()); for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) { + if (I >= SortedUsingDeclarations.size()) { + // This using declaration has been deduplicated, delete it. + auto Begin = + (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin(); + auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc(); + auto Range = CharSourceRange::getCharRange(Begin, End); + auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, "")); + if (Err) { + llvm::errs() << "Error while sorting using declarations: " + << llvm::toString(std::move(Err)) << "\n"; + } + continue; + } if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line) continue; auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation(); @@ -112,7 +183,7 @@ UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style) : TokenAnalyzer(Env, Style) {} -tooling::Replacements UsingDeclarationsSorter::analyze( +std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze( TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) { const SourceManager &SourceMgr = Env.getSourceManager(); @@ -121,15 +192,17 @@ tooling::Replacements UsingDeclarationsSorter::analyze( tooling::Replacements Fixes; SmallVector<UsingDeclaration, 4> UsingDeclarations; for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { - if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective || - !AnnotatedLines[I]->startsWith(tok::kw_using) || - AnnotatedLines[I]->First->Finalized) { + const auto *FirstTok = AnnotatedLines[I]->First; + if (AnnotatedLines[I]->InPPDirective || + !AnnotatedLines[I]->startsWith(tok::kw_using) || FirstTok->Finalized) { endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); continue; } - if (AnnotatedLines[I]->First->NewlinesBefore > 1) + if (FirstTok->NewlinesBefore > 1) endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); - std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First); + const auto *UsingTok = + FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok; + std::string Label = computeUsingDeclarationLabel(UsingTok); if (Label.empty()) { endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); continue; @@ -137,7 +210,7 @@ tooling::Replacements UsingDeclarationsSorter::analyze( UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label)); } endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); - return Fixes; + return {Fixes, 0}; } } // namespace format diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h index f7d5f97e3a2af..6f137712d8416 100644 --- a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h +++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h @@ -25,7 +25,7 @@ class UsingDeclarationsSorter : public TokenAnalyzer { public: UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style); - tooling::Replacements + std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, FormatTokenLexer &Tokens) override; diff --git a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp index 377ec3a681b63..a5477a996327b 100644 --- a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp @@ -67,6 +67,11 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, /*IsInsideToken=*/false)); } +llvm::Error +WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) { + return Replaces.add(Replacement); +} + void WhitespaceManager::replaceWhitespaceInToken( const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, @@ -166,15 +171,15 @@ void WhitespaceManager::calculateLineBreakInformation() { // BreakableLineCommentSection does comment reflow changes and here is // the aligning of trailing comments. Consider the case where we reflow // the second line up in this example: - // + // // // line 1 // // line 2 - // + // // That amounts to 2 changes by BreakableLineCommentSection: // - the first, delimited by (), for the whitespace between the tokens, // - and second, delimited by [], for the whitespace at the beginning // of the second token: - // + // // // line 1( // )[// ]line 2 // @@ -608,8 +613,9 @@ void WhitespaceManager::generateChanges() { if (C.CreateReplacement) { std::string ReplacementText = C.PreviousLinePostfix; if (C.ContinuesPPDirective) - appendNewlineText(ReplacementText, C.NewlinesBefore, - C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn); + appendEscapedNewlineText(ReplacementText, C.NewlinesBefore, + C.PreviousEndOfTokenColumn, + C.EscapedNewlineColumn); else appendNewlineText(ReplacementText, C.NewlinesBefore); appendIndentText(ReplacementText, C.Tok->IndentLevel, @@ -621,8 +627,7 @@ void WhitespaceManager::generateChanges() { } } -void WhitespaceManager::storeReplacement(SourceRange Range, - StringRef Text) { +void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) { unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) - SourceMgr.getFileOffset(Range.getBegin()); // Don't create a replacement, if it does not change anything. @@ -645,16 +650,16 @@ void WhitespaceManager::appendNewlineText(std::string &Text, Text.append(UseCRLF ? "\r\n" : "\n"); } -void WhitespaceManager::appendNewlineText(std::string &Text, unsigned Newlines, - unsigned PreviousEndOfTokenColumn, - unsigned EscapedNewlineColumn) { +void WhitespaceManager::appendEscapedNewlineText( + std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn, + unsigned EscapedNewlineColumn) { if (Newlines > 0) { - unsigned Offset = - std::min<int>(EscapedNewlineColumn - 2, PreviousEndOfTokenColumn); + unsigned Spaces = + std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1); for (unsigned i = 0; i < Newlines; ++i) { - Text.append(EscapedNewlineColumn - Offset - 1, ' '); + Text.append(Spaces, ' '); Text.append(UseCRLF ? "\\\r\n" : "\\\n"); - Offset = 0; + Spaces = std::max<int>(0, EscapedNewlineColumn - 1); } } } diff --git a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h index 4e78ab43abaf7..af20dc5616a70 100644 --- a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h +++ b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h @@ -57,6 +57,8 @@ public: /// was not called. void addUntouchableToken(const FormatToken &Tok, bool InPPDirective); + llvm::Error addReplacement(const tooling::Replacement &Replacement); + /// \brief Inserts or replaces whitespace in the middle of a token. /// /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix @@ -194,9 +196,9 @@ private: /// \brief Stores \p Text as the replacement for the whitespace in \p Range. void storeReplacement(SourceRange Range, StringRef Text); void appendNewlineText(std::string &Text, unsigned Newlines); - void appendNewlineText(std::string &Text, unsigned Newlines, - unsigned PreviousEndOfTokenColumn, - unsigned EscapedNewlineColumn); + void appendEscapedNewlineText(std::string &Text, unsigned Newlines, + unsigned PreviousEndOfTokenColumn, + unsigned EscapedNewlineColumn); void appendIndentText(std::string &Text, unsigned IndentLevel, unsigned Spaces, unsigned WhitespaceStartColumn); diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 1094e6d089a65..1160df15a9201 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -243,7 +243,8 @@ static unsigned getDeclShowContexts(const NamedDecl *ND, uint64_t Contexts = 0; if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) || - isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) { + isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND) || + isa<TypeAliasTemplateDecl>(ND)) { // Types can appear in these contexts. if (LangOpts.CPlusPlus || !isa<TagDecl>(ND)) Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel) @@ -263,8 +264,12 @@ static unsigned getDeclShowContexts(const NamedDecl *ND, Contexts |= (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); // In Objective-C, you can only be a subclass of another Objective-C class - if (isa<ObjCInterfaceDecl>(ND)) + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) { + // Objective-C interfaces can be used in a class property expression. + if (ID->getDefinition()) + Contexts |= (1LL << CodeCompletionContext::CCC_Expression); Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName); + } // Deal with tag names. if (isa<EnumDecl>(ND)) { @@ -542,6 +547,9 @@ private: // Initialize the ASTContext Context->InitBuiltinTypes(*Target); + // Adjust printing policy based on language options. + Context->setPrintingPolicy(PrintingPolicy(LangOpt)); + // We didn't have access to the comment options when the ASTContext was // constructed, so register them now. Context->getCommentCommandTraits().registerCommentOptions( @@ -962,9 +970,8 @@ public: } } - void HandleMacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override { - AddDefinedMacroToHash(MacroNameTok, Hash); + std::unique_ptr<PPCallbacks> createPPCallbacks() override { + return llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(Hash); } private: @@ -1016,6 +1023,19 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, if (!Invocation) return true; + auto CCInvocation = std::make_shared<CompilerInvocation>(*Invocation); + if (OverrideMainBuffer) { + assert(Preamble && + "No preamble was built, but OverrideMainBuffer is not null"); + IntrusiveRefCntPtr<vfs::FileSystem> OldVFS = VFS; + Preamble->AddImplicitPreamble(*CCInvocation, VFS, OverrideMainBuffer.get()); + if (OldVFS != VFS && FileMgr) { + assert(OldVFS == FileMgr->getVirtualFileSystem() && + "VFS passed to Parse and VFS in FileMgr are different"); + FileMgr = new FileManager(FileMgr->getFileSystemOpts(), VFS); + } + } + // Create the compiler instance to use for building the AST. std::unique_ptr<CompilerInstance> Clang( new CompilerInstance(std::move(PCHContainerOps))); @@ -1030,7 +1050,7 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(Clang.get()); - Clang->setInvocation(std::make_shared<CompilerInvocation>(*Invocation)); + Clang->setInvocation(CCInvocation); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would @@ -1084,9 +1104,6 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. if (OverrideMainBuffer) { - assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); - Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); - // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've // been careful to make sure that the source manager's state @@ -1275,7 +1292,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build( PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, - PCHContainerOps, Callbacks); + PCHContainerOps, /*StoreInMemory=*/false, Callbacks); if (NewPreamble) { Preamble = std::move(*NewPreamble); PreambleRebuildCounter = 1; @@ -1658,7 +1675,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine( PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; - PPOpts.GeneratePreamble = PrecompilePreambleAfterNParses != 0; PPOpts.SingleFileParseMode = SingleFileParse; // Override the resources path. @@ -2152,8 +2168,16 @@ void ASTUnit::CodeComplete( // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. if (OverrideMainBuffer) { - assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); - Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); + assert(Preamble && + "No preamble was built, but OverrideMainBuffer is not null"); + + auto VFS = FileMgr.getVirtualFileSystem(); + Preamble->AddImplicitPreamble(Clang->getInvocation(), VFS, + OverrideMainBuffer.get()); + // FIXME: there is no way to update VFS if it was changed by + // AddImplicitPreamble as FileMgr is accepted as a parameter by this method. + // We use on-disk preambles instead and rely on FileMgr's VFS to ensure the + // PCH files are always readable. OwnedBuffers.push_back(OverrideMainBuffer.release()); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -2395,7 +2419,7 @@ SourceLocation ASTUnit::getLocation(const FileEntry *File, /// \brief If \arg Loc is a loaded location from the preamble, returns /// the corresponding local location of the main file, otherwise it returns /// \arg Loc. -SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { +SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) const { FileID PreambleID; if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); @@ -2416,7 +2440,7 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { /// \brief If \arg Loc is a local location of the main file but inside the /// preamble chunk, returns the corresponding loaded location from the /// preamble, otherwise it returns \arg Loc. -SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { +SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) const { FileID PreambleID; if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); @@ -2434,7 +2458,7 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { return Loc; } -bool ASTUnit::isInPreambleFileID(SourceLocation Loc) { +bool ASTUnit::isInPreambleFileID(SourceLocation Loc) const { FileID FID; if (SourceMgr) FID = SourceMgr->getPreambleFileID(); @@ -2445,7 +2469,7 @@ bool ASTUnit::isInPreambleFileID(SourceLocation Loc) { return SourceMgr->isInFileID(Loc, FID); } -bool ASTUnit::isInMainFileID(SourceLocation Loc) { +bool ASTUnit::isInMainFileID(SourceLocation Loc) const { FileID FID; if (SourceMgr) FID = SourceMgr->getMainFileID(); @@ -2456,7 +2480,7 @@ bool ASTUnit::isInMainFileID(SourceLocation Loc) { return SourceMgr->isInFileID(Loc, FID); } -SourceLocation ASTUnit::getEndOfPreambleFileID() { +SourceLocation ASTUnit::getEndOfPreambleFileID() const { FileID FID; if (SourceMgr) FID = SourceMgr->getPreambleFileID(); @@ -2467,7 +2491,7 @@ SourceLocation ASTUnit::getEndOfPreambleFileID() { return SourceMgr->getLocForEndOfFile(FID); } -SourceLocation ASTUnit::getStartOfMainFileID() { +SourceLocation ASTUnit::getStartOfMainFileID() const { FileID FID; if (SourceMgr) FID = SourceMgr->getMainFileID(); @@ -2543,7 +2567,7 @@ const FileEntry *ASTUnit::getPCHFile() { return nullptr; } -bool ASTUnit::isModuleFile() { +bool ASTUnit::isModuleFile() const { return isMainFileAST() && getLangOpts().isCompilingModule(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index bb6a665cb4565..32f1232bbe246 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -300,12 +300,16 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, // File Manager -void CompilerInstance::createFileManager() { +FileManager *CompilerInstance::createFileManager() { if (!hasVirtualFileSystem()) { - // TODO: choose the virtual file system based on the CompilerInvocation. - setVirtualFileSystem(vfs::getRealFileSystem()); + if (IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(getInvocation(), getDiagnostics())) + setVirtualFileSystem(VFS); + else + return nullptr; } FileMgr = new FileManager(getFileSystemOpts(), VirtualFileSystem); + return FileMgr.get(); } // Source Manager @@ -382,6 +386,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { Invocation->getPreprocessorOptsPtr(), getDiagnostics(), getLangOpts(), getSourceManager(), getPCMCache(), *HeaderInfo, *this, PTHMgr, /*OwnsHeaderSearch=*/true, TUKind); + getTarget().adjust(getLangOpts()); PP->Initialize(getTarget(), getAuxTarget()); // Note that this is different then passing PTHMgr to Preprocessor's ctor. @@ -759,9 +764,15 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile( if (UseTemporary) { // Create a temporary file. - SmallString<128> TempPath; - TempPath = OutFile; + // Insert -%%%%%%%% before the extension (if any), and because some tools + // (noticeable, clang's own GlobalModuleIndex.cpp) glob for build + // artifacts, also append .tmp. + StringRef OutputExtension = llvm::sys::path::extension(OutFile); + SmallString<128> TempPath = + StringRef(OutFile).drop_back(OutputExtension.size()); TempPath += "-%%%%%%%%"; + TempPath += OutputExtension; + TempPath += ".tmp"; int fd; std::error_code EC = llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath); @@ -832,8 +843,8 @@ bool CompilerInstance::InitializeSourceManager( : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { - SourceMgr.setMainFileID(SourceMgr.createFileID( - std::unique_ptr<llvm::MemoryBuffer>(Input.getBuffer()), Kind)); + SourceMgr.setMainFileID(SourceMgr.createFileID(SourceManager::Unowned, + Input.getBuffer(), Kind)); assert(SourceMgr.getMainFileID().isValid() && "Couldn't establish MainFileID!"); return true; @@ -997,8 +1008,17 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { OS << " and "; if (NumErrors) OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); - if (NumWarnings || NumErrors) - OS << " generated.\n"; + if (NumWarnings || NumErrors) { + OS << " generated"; + if (getLangOpts().CUDA) { + if (!getLangOpts().CUDAIsDevice) { + OS << " when compiling for host"; + } else { + OS << " when compiling for " << getTargetOpts().CPU; + } + } + OS << ".\n"; + } } if (getFrontendOpts().ShowStats) { @@ -1595,7 +1615,22 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) { // Determine what file we're searching from. - StringRef ModuleName = Path[0].first->getName(); + // FIXME: Should we be deciding whether this is a submodule (here and + // below) based on -fmodules-ts or should we pass a flag and make the + // caller decide? + std::string ModuleName; + if (getLangOpts().ModulesTS) { + // FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a + // better place/way to do this. + for (auto &Piece : Path) { + if (!ModuleName.empty()) + ModuleName += "."; + ModuleName += Piece.first->getName(); + } + } + else + ModuleName = Path[0].first->getName(); + SourceLocation ModuleNameLoc = Path[0].second; // If we've already handled this import, just return the cached result. @@ -1620,6 +1655,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); + /// FIXME: perhaps we should (a) look for a module using the module name + // to file map (PrebuiltModuleFiles) and (b) diagnose if still not found? + //if (Module == nullptr) { + // getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + // << ModuleName; + // ModuleBuildFailed = true; + // return ModuleLoadResult(); + //} Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; } else { // Search for a module with the given name. @@ -1641,16 +1684,17 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } // Try to load the module from the prebuilt module path. - if (Source == ModuleNotFound && !HSOpts.PrebuiltModulePaths.empty()) { - ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName( - ModuleName, "", /*UsePrebuiltPath*/ true); + if (Source == ModuleNotFound && (!HSOpts.PrebuiltModuleFiles.empty() || + !HSOpts.PrebuiltModulePaths.empty())) { + ModuleFileName = + PP->getHeaderSearchInfo().getPrebuiltModuleFileName(ModuleName); if (!ModuleFileName.empty()) Source = PrebuiltModulePath; } // Try to load the module from the module cache. if (Source == ModuleNotFound && Module) { - ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module); + ModuleFileName = PP->getHeaderSearchInfo().getCachedModuleFileName(Module); Source = ModuleCache; } @@ -1810,7 +1854,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Verify that the rest of the module path actually corresponds to // a submodule. - if (Path.size() > 1) { + if (!getLangOpts().ModulesTS && Path.size() > 1) { for (unsigned I = 1, N = Path.size(); I != N; ++I) { StringRef Name = Path[I].first->getName(); clang::Module *Sub = Module->findSubmodule(Name); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 0d0869c815d3b..2e8a737de4e42 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -527,7 +527,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining); Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); - Opts.DebugExplicitImport = Triple.isPS4CPU(); + Opts.DebugExplicitImport = Args.hasArg(OPT_dwarf_explicit_import); + Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params); for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); @@ -545,6 +546,11 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, OPT_fuse_register_sized_bitfield_access); Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); Opts.StructPathTBAA = !Args.hasArg(OPT_no_struct_path_tbaa); + Opts.NewStructPathTBAA = !Args.hasArg(OPT_no_struct_path_tbaa) && + Args.hasArg(OPT_new_struct_path_tbaa); + Opts.FineGrainedBitfieldAccesses = + Args.hasFlag(OPT_ffine_grained_bitfield_accesses, + OPT_fno_fine_grained_bitfield_accesses, false); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); @@ -564,6 +570,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ); Opts.DebugInfoForProfiling = Args.hasFlag( OPT_fdebug_info_for_profiling, OPT_fno_debug_info_for_profiling, false); + Opts.GnuPubnames = Args.hasArg(OPT_ggnu_pubnames); setPGOInstrumentor(Opts, Args, Diags); Opts.InstrProfileOutput = @@ -632,9 +639,11 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_no_signed_zeros) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math)); + Opts.Reassociate = Args.hasArg(OPT_mreassociate); Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero); Opts.CorrectlyRoundedDivSqrt = Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt); + Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ); Opts.ReciprocalMath = Args.hasArg(OPT_freciprocal_math); Opts.NoTrappingMath = Args.hasArg(OPT_fno_trapping_math); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); @@ -648,6 +657,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_mincremental_linker_compatible); Opts.PIECopyRelocations = Args.hasArg(OPT_mpie_copy_relocations); + Opts.NoPLT = Args.hasArg(OPT_fno_plt); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm); @@ -679,6 +689,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); + Opts.ProfileSampleAccurate = Args.hasArg(OPT_fprofile_sample_accurate); + Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); Opts.EmitSummaryIndex = false; if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { @@ -702,6 +714,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops); Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp); + Opts.PreferVectorWidth = Args.getLastArgValue(OPT_mprefer_vector_width_EQ); + Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); @@ -769,7 +783,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.InstrumentFunctionsAfterInlining = + Args.hasArg(OPT_finstrument_functions_after_inlining); + Opts.InstrumentFunctionEntryBare = + Args.hasArg(OPT_finstrument_function_entry_bare); Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + Opts.XRayAlwaysEmitCustomEvents = + Args.hasArg(OPT_fxray_always_emit_customevents); Opts.XRayInstructionThreshold = getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); @@ -821,11 +841,19 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune); Opts.SanitizeCoverageInline8bitCounters = Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters); + Opts.SanitizeCoveragePCTable = Args.hasArg(OPT_fsanitize_coverage_pc_table); + Opts.SanitizeCoverageStackDepth = + Args.hasArg(OPT_fsanitize_coverage_stack_depth); Opts.SanitizeMemoryTrackOrigins = getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags); Opts.SanitizeMemoryUseAfterDtor = - Args.hasArg(OPT_fsanitize_memory_use_after_dtor); + Args.hasFlag(OPT_fsanitize_memory_use_after_dtor, + OPT_fno_sanitize_memory_use_after_dtor, + false); + Opts.SanitizeMinimalRuntime = Args.hasArg(OPT_fsanitize_minimal_runtime); Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso); + Opts.SanitizeCfiICallGeneralizePointers = + Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers); Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats); if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope, OPT_fno_sanitize_address_use_after_scope)) { @@ -1003,9 +1031,12 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, // They won't be discovered by the regular preprocessor, so // we let make / ninja to know about this implicit dependency. Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry); - auto ModuleFiles = Args.getAllArgValues(OPT_fmodule_file); - Opts.ExtraDeps.insert(Opts.ExtraDeps.end(), ModuleFiles.begin(), - ModuleFiles.end()); + // Only the -fmodule-file=<file> form. + for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + StringRef Val = A->getValue(); + if (Val.find('=') == StringRef::npos) + Opts.ExtraDeps.push_back(Val); + } } static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { @@ -1041,6 +1072,26 @@ static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { llvm::sys::Process::StandardErrHasColors()); } +static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes, + DiagnosticsEngine *Diags) { + bool Success = true; + for (const auto &Prefix : VerifyPrefixes) { + // Every prefix must start with a letter and contain only alphanumeric + // characters, hyphens, and underscores. + auto BadChar = std::find_if(Prefix.begin(), Prefix.end(), + [](char C){return !isAlphanumeric(C) + && C != '-' && C != '_';}); + if (BadChar != Prefix.end() || !isLetter(Prefix[0])) { + Success = false; + if (Diags) { + Diags->Report(diag::err_drv_invalid_value) << "-verify=" << Prefix; + Diags->Report(diag::note_drv_verify_prefix_spelling); + } + } + } + return Success; +} + bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor, bool DefaultShowOpt) { @@ -1128,7 +1179,18 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location); - Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ); + Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ); + if (Args.hasArg(OPT_verify)) + Opts.VerifyPrefixes.push_back("expected"); + // Keep VerifyPrefixes in its original order for the sake of diagnostics, and + // then sort it to prepare for fast lookup using std::binary_search. + if (!checkVerifyPrefixes(Opts.VerifyPrefixes, Diags)) { + Opts.VerifyDiagnostics = false; + Success = false; + } + else + std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end()); DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None; Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=", Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), @@ -1334,7 +1396,12 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index); Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex; Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file); - Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file); + // Only the -fmodule-file=<file> form. + for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + StringRef Val = A->getValue(); + if (Val.find('=') == StringRef::npos) + Opts.ModuleFiles.push_back(Val); + } Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ); Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files); Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp); @@ -1345,6 +1412,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, = Args.hasArg(OPT_code_completion_patterns); Opts.CodeCompleteOpts.IncludeGlobals = !Args.hasArg(OPT_no_code_completion_globals); + Opts.CodeCompleteOpts.IncludeNamespaceLevelDecls + = !Args.hasArg(OPT_no_code_completion_ns_level_decls); Opts.CodeCompleteOpts.IncludeBriefComments = Args.hasArg(OPT_code_completion_brief_comments); @@ -1538,6 +1607,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.ModuleCachePath = P.str(); Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path); + // Only the -fmodule-file=<name>=<file> form. + for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + StringRef Val = A->getValue(); + if (Val.find('=') != StringRef::npos) + Opts.PrebuiltModuleFiles.insert(Val.split('=')); + } for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path)) Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); @@ -1690,11 +1765,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, break; case InputKind::CXX: case InputKind::ObjCXX: - // The PS4 uses C++11 as the default C++ standard. - if (T.isPS4()) - LangStd = LangStandard::lang_gnucxx11; - else - LangStd = LangStandard::lang_gnucxx98; + LangStd = LangStandard::lang_gnucxx14; break; case InputKind::RenderScript: LangStd = LangStandard::lang_c99; @@ -1706,10 +1777,11 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.LineComment = Std.hasLineComments(); Opts.C99 = Std.isC99(); Opts.C11 = Std.isC11(); + Opts.C17 = Std.isC17(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus11 = Std.isCPlusPlus11(); Opts.CPlusPlus14 = Std.isCPlusPlus14(); - Opts.CPlusPlus1z = Std.isCPlusPlus1z(); + Opts.CPlusPlus17 = Std.isCPlusPlus17(); Opts.CPlusPlus2a = Std.isCPlusPlus2a(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); @@ -1765,7 +1837,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.GNUKeywords = Opts.GNUMode; Opts.CXXOperatorNames = Opts.CPlusPlus; - Opts.AlignedAllocation = Opts.CPlusPlus1z; + Opts.AlignedAllocation = Opts.CPlusPlus17; Opts.DollarIdents = !Opts.AsmPreprocessor; } @@ -2084,7 +2156,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs // is specified, or -std is set to a conforming mode. // Trigraphs are disabled by default in c++1z onwards. - Opts.Trigraphs = !Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus1z; + Opts.Trigraphs = !Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus17; Opts.Trigraphs = Args.hasFlag(OPT_ftrigraphs, OPT_fno_trigraphs, Opts.Trigraphs); @@ -2104,7 +2176,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.Exceptions = Args.hasArg(OPT_fexceptions); Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); - Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); + + // Handle exception personalities + Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, + options::OPT_fseh_exceptions, + options::OPT_fdwarf_exceptions); + if (A) { + const Option &Opt = A->getOption(); + Opts.SjLjExceptions = Opt.matches(options::OPT_fsjlj_exceptions); + Opts.SEHExceptions = Opt.matches(options::OPT_fseh_exceptions); + Opts.DWARFExceptions = Opt.matches(options::OPT_fdwarf_exceptions); + } + Opts.ExternCNoUnwind = Args.hasArg(OPT_fexternc_nounwind); Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp); @@ -2114,6 +2197,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, && Opts.OpenCLVersion >= 200); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts); + + // Enable [[]] attributes in C++11 by default. + Opts.DoubleSquareBracketAttributes = + Args.hasFlag(OPT_fdouble_square_bracket_attributes, + OPT_fno_double_square_bracket_attributes, Opts.CPlusPlus11); + Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts); Opts.Modules = Args.hasArg(OPT_fmodules) || Opts.ModulesTS; Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse); @@ -2130,7 +2219,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ImplicitModules = !Args.hasArg(OPT_fno_implicit_modules); Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char); Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); - Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false); + if (const Arg *A = Args.getLastArg(OPT_fwchar_type_EQ)) { + Opts.WCharSize = llvm::StringSwitch<unsigned>(A->getValue()) + .Case("char", 1) + .Case("short", 2) + .Case("int", 4) + .Default(0); + if (Opts.WCharSize == 0) + Diags.Report(diag::err_fe_invalid_wchar_type) << A->getValue(); + } + Opts.WCharIsSigned = Args.hasFlag(OPT_fsigned_wchar, OPT_fno_signed_wchar, true); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; @@ -2266,12 +2364,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Check for MS default calling conventions being specified. if (Arg *A = Args.getLastArg(OPT_fdefault_calling_conv_EQ)) { LangOptions::DefaultCallingConvention DefaultCC = - llvm::StringSwitch<LangOptions::DefaultCallingConvention>( - A->getValue()) + llvm::StringSwitch<LangOptions::DefaultCallingConvention>(A->getValue()) .Case("cdecl", LangOptions::DCC_CDecl) .Case("fastcall", LangOptions::DCC_FastCall) .Case("stdcall", LangOptions::DCC_StdCall) .Case("vectorcall", LangOptions::DCC_VectorCall) + .Case("regcall", LangOptions::DCC_RegCall) .Default(LangOptions::DCC_None); if (DefaultCC == LangOptions::DCC_None) Diags.Report(diag::err_drv_invalid_value) @@ -2282,7 +2380,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, bool emitError = (DefaultCC == LangOptions::DCC_FastCall || DefaultCC == LangOptions::DCC_StdCall) && Arch != llvm::Triple::x86; - emitError |= DefaultCC == LangOptions::DCC_VectorCall && + emitError |= (DefaultCC == LangOptions::DCC_VectorCall || + DefaultCC == LangOptions::DCC_RegCall) && !(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64); if (emitError) Diags.Report(diag::err_drv_argument_not_allowed_with) @@ -2334,13 +2433,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } } + // Set the flag to prevent the implementation from emitting device exception + // handling code for those requiring so. + if (Opts.OpenMPIsDevice && T.isNVPTX()) { + Opts.Exceptions = 0; + Opts.CXXExceptions = 0; + } + // Get the OpenMP target triples if any. if (Arg *A = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) { for (unsigned i = 0; i < A->getNumValues(); ++i) { llvm::Triple TT(A->getValue(i)); - if (TT.getArch() == llvm::Triple::UnknownArch) + if (TT.getArch() == llvm::Triple::UnknownArch || + !(TT.getArch() == llvm::Triple::ppc || + TT.getArch() == llvm::Triple::ppc64 || + TT.getArch() == llvm::Triple::ppc64le || + TT.getArch() == llvm::Triple::nvptx || + TT.getArch() == llvm::Triple::nvptx64 || + TT.getArch() == llvm::Triple::x86 || + TT.getArch() == llvm::Triple::x86_64)) Diags.Report(clang::diag::err_drv_invalid_omp_target) << A->getValue(i); else Opts.OMPTargetTriples.push_back(TT); @@ -2425,6 +2538,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.XRayInstrument = Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false); + // -fxray-always-emit-customevents + Opts.XRayAlwaysEmitCustomEvents = + Args.hasFlag(OPT_fxray_always_emit_customevents, + OPT_fnoxray_always_emit_customevents, false); + // -fxray-{always,never}-instrument= filenames. Opts.XRayAlwaysInstrumentFiles = Args.getAllArgValues(OPT_fxray_always_instrument); @@ -2603,7 +2721,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); - Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ); // Use the default target triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getDefaultTargetTriple(); @@ -2710,6 +2827,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, if (Arch == llvm::Triple::spir || Arch == llvm::Triple::spir64) { Res.getDiagnosticOpts().Warnings.push_back("spir-compat"); } + + // If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses. + if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses && + !Res.getLangOpts()->Sanitize.empty()) { + Res.getCodeGenOpts().FineGrainedBitfieldAccesses = false; + Diags.Report(diag::warn_drv_fine_grained_bitfield_accesses_ignored); + } return Success; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 704d51509851f..12226b2314175 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -633,18 +633,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, return true; } - if (!CI.hasVirtualFileSystem()) { - if (IntrusiveRefCntPtr<vfs::FileSystem> VFS = - createVFSFromCompilerInvocation(CI.getInvocation(), - CI.getDiagnostics())) - CI.setVirtualFileSystem(VFS); - else + // Set up the file and source managers, if needed. + if (!CI.hasFileManager()) { + if (!CI.createFileManager()) { goto failure; + } } - - // Set up the file and source managers, if needed. - if (!CI.hasFileManager()) - CI.createFileManager(); if (!CI.hasSourceManager()) CI.createSourceManager(CI.getFileManager()); @@ -754,10 +748,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; // Reinitialize the main file entry to refer to the new input. - if (!CI.InitializeSourceManager(FrontendInputFile( - Buffer.release(), Input.getKind().withFormat(InputKind::Source), - CurrentModule->IsSystem))) - goto failure; + auto Kind = CurrentModule->IsSystem ? SrcMgr::C_System : SrcMgr::C_User; + auto &SourceMgr = CI.getSourceManager(); + auto BufferID = SourceMgr.createFileID(std::move(Buffer), Kind); + assert(BufferID.isValid() && "couldn't creaate module buffer ID"); + SourceMgr.setMainFileID(BufferID); } } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index d42400183a433..ffa5b410d2d8f 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -80,9 +80,12 @@ DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, std::unique_ptr<ASTConsumer> GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::string Sysroot; + if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot)) + return nullptr; + std::string OutputFile; std::unique_ptr<raw_pwrite_stream> OS = - ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile); + CreateOutputFile(CI, InFile, /*ref*/ OutputFile); if (!OS) return nullptr; @@ -103,17 +106,20 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } -std::unique_ptr<raw_pwrite_stream> -GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, - StringRef InFile, - std::string &Sysroot, - std::string &OutputFile) { +bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, + std::string &Sysroot) { Sysroot = CI.getHeaderSearchOpts().Sysroot; if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); - return nullptr; + return false; } + return true; +} + +std::unique_ptr<llvm::raw_pwrite_stream> +GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile, + std::string &OutputFile) { // We use createOutputFile here because this is exposed via libclang, and we // must disable the RemoveFileOnSignal behavior. // We use a temporary to avoid race conditions. @@ -185,8 +191,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); CI.getFrontendOpts().OutputFile = - HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile, - /*UsePrebuiltPath=*/false); + HS.getCachedModuleFileName(CI.getLangOpts().CurrentModule, + ModuleMapFile); } // We use createOutputFile here because this is exposed via libclang, and we @@ -591,7 +597,7 @@ void PrintPreambleAction::ExecuteAction() { auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { unsigned Preamble = - Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).first; + Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).Size; llvm::outs().write((*Buffer)->getBufferStart(), Preamble); } } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index 1d7c8a0c871bd..8c6faced76ac0 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -213,7 +213,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: - case llvm::Triple::Bitrig: case llvm::Triple::NaCl: case llvm::Triple::PS4: case llvm::Triple::ELFIAMCU: diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 92d61369b40f0..d39890494323d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SyncScope.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -109,9 +110,11 @@ static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP, /// PickFP - This is used to pick a value based on the FP semantics of the /// specified FP model. template <typename T> -static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, +static T PickFP(const llvm::fltSemantics *Sem, T IEEEHalfVal, T IEEESingleVal, T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal, T IEEEQuadVal) { + if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEhalf()) + return IEEEHalfVal; if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle()) return IEEESingleVal; if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEdouble()) @@ -127,26 +130,26 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix, const llvm::fltSemantics *Sem, StringRef Ext) { const char *DenormMin, *Epsilon, *Max, *Min; - DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324", - "3.64519953188247460253e-4951", + DenormMin = PickFP(Sem, "5.9604644775390625e-8", "1.40129846e-45", + "4.9406564584124654e-324", "3.64519953188247460253e-4951", "4.94065645841246544176568792868221e-324", "6.47517511943802511092443895822764655e-4966"); - int Digits = PickFP(Sem, 6, 15, 18, 31, 33); - int DecimalDigits = PickFP(Sem, 9, 17, 21, 33, 36); - Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16", - "1.08420217248550443401e-19", + int Digits = PickFP(Sem, 3, 6, 15, 18, 31, 33); + int DecimalDigits = PickFP(Sem, 5, 9, 17, 21, 33, 36); + Epsilon = PickFP(Sem, "9.765625e-4", "1.19209290e-7", + "2.2204460492503131e-16", "1.08420217248550443401e-19", "4.94065645841246544176568792868221e-324", "1.92592994438723585305597794258492732e-34"); - int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113); - int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931); - int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932); - int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381); - int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384); - Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308", + int MantissaDigits = PickFP(Sem, 11, 24, 53, 64, 106, 113); + int Min10Exp = PickFP(Sem, -13, -37, -307, -4931, -291, -4931); + int Max10Exp = PickFP(Sem, 4, 38, 308, 4932, 308, 4932); + int MinExp = PickFP(Sem, -14, -125, -1021, -16381, -968, -16381); + int MaxExp = PickFP(Sem, 15, 128, 1024, 16384, 1024, 16384); + Min = PickFP(Sem, "6.103515625e-5", "1.17549435e-38", "2.2250738585072014e-308", "3.36210314311209350626e-4932", "2.00416836000897277799610805135016e-292", "3.36210314311209350626267781732175260e-4932"); - Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308", + Max = PickFP(Sem, "6.5504e+4", "3.40282347e+38", "1.7976931348623157e+308", "1.18973149535723176502e+4932", "1.79769313486231580793728971405301e+308", "1.18973149535723176508575932662800702e+4932"); @@ -190,7 +193,7 @@ static void DefineTypeSize(const Twine &MacroName, unsigned TypeWidth, /// the width, suffix, and signedness of the given type static void DefineTypeSize(const Twine &MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { - DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), + DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), TI.isTypeSigned(Ty), Builder); } @@ -300,25 +303,25 @@ static const char *getLockFreeValue(unsigned TypeWidth, unsigned TypeAlign, /// \brief Add definitions required for a smooth interaction between /// Objective-C++ automated reference counting and libstdc++ (4.2). -static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, +static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, MacroBuilder &Builder) { Builder.defineMacro("_GLIBCXX_PREDEFINED_OBJC_ARC_IS_SCALAR"); - + std::string Result; { - // Provide specializations for the __is_scalar type trait so that + // Provide specializations for the __is_scalar type trait so that // lifetime-qualified objects are not considered "scalar" types, which // libstdc++ uses as an indicator of the presence of trivial copy, assign, // default-construct, and destruct semantics (none of which hold for // lifetime-qualified objects in ARC). llvm::raw_string_ostream Out(Result); - + Out << "namespace std {\n" << "\n" << "struct __true_type;\n" << "struct __false_type;\n" << "\n"; - + Out << "template<typename _Tp> struct __is_scalar;\n" << "\n"; @@ -330,7 +333,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "};\n" << "\n"; } - + if (LangOpts.ObjCWeak) { Out << "template<typename _Tp>\n" << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n" @@ -339,7 +342,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "};\n" << "\n"; } - + if (LangOpts.ObjCAutoRefCount) { Out << "template<typename _Tp>\n" << "struct __is_scalar<__attribute__((objc_ownership(autoreleasing)))" @@ -349,7 +352,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "};\n" << "\n"; } - + Out << "}\n"; } Builder.append(Result); @@ -367,7 +370,9 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__STDC_HOSTED__"); if (!LangOpts.CPlusPlus) { - if (LangOpts.C11) + if (LangOpts.C17) + Builder.defineMacro("__STDC_VERSION__", "201710L"); + else if (LangOpts.C11) Builder.defineMacro("__STDC_VERSION__", "201112L"); else if (LangOpts.C99) Builder.defineMacro("__STDC_VERSION__", "199901L"); @@ -380,7 +385,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // C++17 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201703L when compiling a // C++ translation unit. - else if (LangOpts.CPlusPlus1z) + else if (LangOpts.CPlusPlus17) Builder.defineMacro("__cplusplus", "201703L"); // C++1y [cpp.predefined]p1: // The name __cplusplus is defined to the value 201402L when compiling a @@ -480,12 +485,12 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_user_defined_literals", "200809"); Builder.defineMacro("__cpp_lambdas", "200907"); Builder.defineMacro("__cpp_constexpr", - LangOpts.CPlusPlus1z ? "201603" : + LangOpts.CPlusPlus17 ? "201603" : LangOpts.CPlusPlus14 ? "201304" : "200704"); Builder.defineMacro("__cpp_range_based_for", - LangOpts.CPlusPlus1z ? "201603" : "200907"); + LangOpts.CPlusPlus17 ? "201603" : "200907"); Builder.defineMacro("__cpp_static_assert", - LangOpts.CPlusPlus1z ? "201411" : "200410"); + LangOpts.CPlusPlus17 ? "201411" : "200410"); Builder.defineMacro("__cpp_decltype", "200707"); Builder.defineMacro("__cpp_attributes", "200809"); Builder.defineMacro("__cpp_rvalue_references", "200610"); @@ -515,7 +520,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_sized_deallocation", "201309"); // C++17 features. - if (LangOpts.CPlusPlus1z) { + if (LangOpts.CPlusPlus17) { Builder.defineMacro("__cpp_hex_float", "201603"); Builder.defineMacro("__cpp_inline_variables", "201606"); Builder.defineMacro("__cpp_noexcept_function_type", "201510"); @@ -556,7 +561,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL)); #undef TOSTR #undef TOSTR2 - Builder.defineMacro("__clang_version__", + Builder.defineMacro("__clang_version__", "\"" CLANG_VERSION_STRING " " + getClangFullRepositoryVersion() + "\""); if (!LangOpts.MSVCCompat) { @@ -576,13 +581,27 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__ATOMIC_ACQ_REL", "4"); Builder.defineMacro("__ATOMIC_SEQ_CST", "5"); + // Define macros for the OpenCL memory scope. + // The values should match AtomicScopeOpenCLModel::ID enum. + static_assert( + static_cast<unsigned>(AtomicScopeOpenCLModel::WorkGroup) == 1 && + static_cast<unsigned>(AtomicScopeOpenCLModel::Device) == 2 && + static_cast<unsigned>(AtomicScopeOpenCLModel::AllSVMDevices) == 3 && + static_cast<unsigned>(AtomicScopeOpenCLModel::SubGroup) == 4, + "Invalid OpenCL memory scope enum definition"); + Builder.defineMacro("__OPENCL_MEMORY_SCOPE_WORK_ITEM", "0"); + Builder.defineMacro("__OPENCL_MEMORY_SCOPE_WORK_GROUP", "1"); + Builder.defineMacro("__OPENCL_MEMORY_SCOPE_DEVICE", "2"); + Builder.defineMacro("__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES", "3"); + Builder.defineMacro("__OPENCL_MEMORY_SCOPE_SUB_GROUP", "4"); + // Support for #pragma redefine_extname (Sun compatibility) Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1"); // As sad as it is, enough software depends on the __VERSION__ for version // checks that it is necessary to report 4.2.1 (the base GCC version we claim // compatibility with) first. - Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " + + Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " + Twine(getClangFullCPPVersion()) + "\""); // Initialize language-specific preprocessor defines. @@ -597,7 +616,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.ObjC1) { if (LangOpts.ObjCRuntime.isNonFragile()) { Builder.defineMacro("__OBJC2__"); - + if (LangOpts.ObjCExceptions) Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); } @@ -660,8 +679,14 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__EXCEPTIONS"); if (!LangOpts.MSVCCompat && LangOpts.RTTI) Builder.defineMacro("__GXX_RTTI"); + if (LangOpts.SjLjExceptions) Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); + else if (LangOpts.SEHExceptions) + Builder.defineMacro("__SEH__"); + else if (LangOpts.DWARFExceptions && + (TI.getTriple().isThumb() || TI.getTriple().isARM())) + Builder.defineMacro("__ARM_DWARF_EH__"); if (LangOpts.Deprecated) Builder.defineMacro("__DEPRECATED"); @@ -728,6 +753,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder); DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); + DefineTypeSize("__WINT_MAX__", TI.getWIntType(), TI, Builder); DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder); @@ -787,9 +813,14 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder); DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder); + DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16"); DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F"); DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), ""); DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L"); + if (TI.hasFloat128Type()) + // FIXME: Switch away from the non-standard "Q" when we can + DefineFloatMacros(Builder, "FLT128", &TI.getFloat128Format(), "Q"); + // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", @@ -969,6 +1000,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__nullable", "_Nullable"); } + // Add a macro to differentiate between regular iOS/tvOS/watchOS targets and + // the corresponding simulator targets. + if (TI.getTriple().isOSDarwin() && TI.getTriple().isSimulatorEnvironment()) + Builder.defineMacro("__APPLE_EMBEDDED_SIMULATOR__", "1"); + // OpenMP definition // OpenMP 2.2: // In implementations that support a preprocessor, the _OPENMP @@ -1010,6 +1046,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI, LangOpts.OpenCLVersion)) \ Builder.defineMacro(#Ext); #include "clang/Basic/OpenCLExtensions.def" + + auto Arch = TI.getTriple().getArch(); + if (Arch == llvm::Triple::spir || Arch == llvm::Triple::spir64) + Builder.defineMacro("__IMAGE_SUPPORT__"); } if (TI.hasInt128Type() && LangOpts.CPlusPlus && LangOpts.GNUMode) { @@ -1068,7 +1108,7 @@ void clang::InitializePreprocessor( } } } - + // Even with predefines off, some macros are still predefined. // These should all be defined in the preprocessor according to the // current language configuration. @@ -1114,7 +1154,7 @@ void clang::InitializePreprocessor( // Instruct the preprocessor to skip the preamble. PP.setSkipMainFilePreamble(InitOpts.PrecompiledPreambleBytes.first, InitOpts.PrecompiledPreambleBytes.second); - + // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp index 8ef6df5e740da..04a8f6c1cdfbc 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp @@ -116,14 +116,16 @@ public: void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) override; + const FunctionDecl *Delete, + Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; - void StaticDataMemberInstantiated(const VarDecl *D) override; + void InstantiationRequested(const ValueDecl *D) override; + void VariableDefinitionInstantiated(const VarDecl *D) override; + void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; - void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void DeclarationMarkedOpenMPDeclareTarget(const Decl *D, @@ -183,19 +185,28 @@ void MultiplexASTMutationListener::DeducedReturnType(const FunctionDecl *FD, Listeners[i]->DeducedReturnType(FD, ReturnType); } void MultiplexASTMutationListener::ResolvedOperatorDelete( - const CXXDestructorDecl *DD, const FunctionDecl *Delete) { + const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) { for (auto *L : Listeners) - L->ResolvedOperatorDelete(DD, Delete); + L->ResolvedOperatorDelete(DD, Delete, ThisArg); } void MultiplexASTMutationListener::CompletedImplicitDefinition( const FunctionDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->CompletedImplicitDefinition(D); } -void MultiplexASTMutationListener::StaticDataMemberInstantiated( - const VarDecl *D) { +void MultiplexASTMutationListener::InstantiationRequested(const ValueDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->InstantiationRequested(D); +} +void MultiplexASTMutationListener::VariableDefinitionInstantiated( + const VarDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) - Listeners[i]->StaticDataMemberInstantiated(D); + Listeners[i]->VariableDefinitionInstantiated(D); +} +void MultiplexASTMutationListener::FunctionDefinitionInstantiated( + const FunctionDecl *D) { + for (auto &Listener : Listeners) + Listener->FunctionDefinitionInstantiated(D); } void MultiplexASTMutationListener::DefaultArgumentInstantiated( const ParmVarDecl *D) { @@ -213,11 +224,6 @@ void MultiplexASTMutationListener::AddedObjCCategoryToInterface( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD); } -void MultiplexASTMutationListener::FunctionDefinitionInstantiated( - const FunctionDecl *D) { - for (auto &Listener : Listeners) - Listener->FunctionDefinitionInstantiated(D); -} void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedUsed(D); diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp index 15b24cbed4841..f6964d02b2373 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -24,15 +24,45 @@ #include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" +#include "llvm/Support/Process.h" + +#include <utility> using namespace clang; namespace { +StringRef getInMemoryPreamblePath() { +#if defined(LLVM_ON_UNIX) + return "/__clang_tmp/___clang_inmemory_preamble___"; +#elif defined(LLVM_ON_WIN32) + return "C:\\__clang_tmp\\___clang_inmemory_preamble___"; +#else +#warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs" + return "/__clang_tmp/___clang_inmemory_preamble___"; +#endif +} + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSOverlayForPreamblePCH(StringRef PCHFilename, + std::unique_ptr<llvm::MemoryBuffer> PCHBuffer, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { + // We want only the PCH file from the real filesystem to be available, + // so we create an in-memory VFS with just that and overlay it on top. + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> PCHFS( + new vfs::InMemoryFileSystem()); + PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer)); + IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay( + new vfs::OverlayFileSystem(VFS)); + Overlay->pushOverlay(PCHFS); + return Overlay; +} + /// Keeps a track of files to be deleted in destructor. class TemporaryFiles { public: @@ -85,23 +115,11 @@ void TemporaryFiles::removeFile(StringRef File) { llvm::sys::fs::remove(File); } -class PreambleMacroCallbacks : public PPCallbacks { -public: - PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {} - - void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override { - Callbacks.HandleMacroDefined(MacroNameTok, MD); - } - -private: - PreambleCallbacks &Callbacks; -}; - class PrecompilePreambleAction : public ASTFrontendAction { public: - PrecompilePreambleAction(PreambleCallbacks &Callbacks) - : Callbacks(Callbacks) {} + PrecompilePreambleAction(std::string *InMemStorage, + PreambleCallbacks &Callbacks) + : InMemStorage(InMemStorage), Callbacks(Callbacks) {} std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; @@ -122,6 +140,7 @@ private: friend class PrecompilePreambleConsumer; bool HasEmittedPreamblePCH = false; + std::string *InMemStorage; PreambleCallbacks &Callbacks; }; @@ -163,21 +182,24 @@ private: std::unique_ptr<ASTConsumer> PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { std::string Sysroot; - std::string OutputFile; - std::unique_ptr<raw_ostream> OS = - GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, - OutputFile); + if (!GeneratePCHAction::ComputeASTConsumerArguments(CI, Sysroot)) + return nullptr; + + std::unique_ptr<llvm::raw_ostream> OS; + if (InMemStorage) { + OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage); + } else { + std::string OutputFile; + OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile); + } if (!OS) return nullptr; if (!CI.getFrontendOpts().RelocatablePCH) Sysroot.clear(); - CI.getPreprocessor().addPPCallbacks( - llvm::make_unique<PreambleMacroCallbacks>(Callbacks)); return llvm::make_unique<PrecompilePreambleConsumer>( *this, CI.getPreprocessor(), Sysroot, std::move(OS)); } @@ -194,15 +216,14 @@ template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) { PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts, llvm::MemoryBuffer *Buffer, unsigned MaxLines) { - auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines); - return PreambleBounds(Pre.first, Pre.second); + return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines); } llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS, - std::shared_ptr<PCHContainerOperations> PCHContainerOps, + std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory, PreambleCallbacks &Callbacks) { assert(VFS && "VFS is null"); @@ -214,12 +235,19 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( PreprocessorOptions &PreprocessorOpts = PreambleInvocation->getPreprocessorOpts(); - // Create a temporary file for the precompiled preamble. In rare - // circumstances, this can fail. - llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile = - PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile(); - if (!PreamblePCHFile) - return BuildPreambleError::CouldntCreateTempFile; + llvm::Optional<TempPCHFile> TempFile; + if (!StoreInMemory) { + // Create a temporary file for the precompiled preamble. In rare + // circumstances, this can fail. + llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile = + PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile(); + if (!PreamblePCHFile) + return BuildPreambleError::CouldntCreateTempFile; + TempFile = std::move(*PreamblePCHFile); + } + + PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble()) + : PCHStorage(std::move(*TempFile)); // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. @@ -230,10 +258,12 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( // Tell the compiler invocation to generate a temporary precompiled header. FrontendOpts.ProgramAction = frontend::GeneratePCH; - // FIXME: Generate the precompiled header into memory? - FrontendOpts.OutputFile = PreamblePCHFile->getFilePath(); + FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath() + : Storage.asFile().getFilePath(); PreprocessorOpts.PrecompiledPreambleBytes.first = 0; PreprocessorOpts.PrecompiledPreambleBytes.second = false; + // Inform preprocessor to record conditional stack when building the preamble. + PreprocessorOpts.GeneratePreamble = true; // Create the compiler instance to use for building the precompiled preamble. std::unique_ptr<CompilerInstance> Clang( @@ -301,10 +331,16 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( } std::unique_ptr<PrecompilePreambleAction> Act; - Act.reset(new PrecompilePreambleAction(Callbacks)); + Act.reset(new PrecompilePreambleAction( + StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks)); if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) return BuildPreambleError::BeginSourceFileFailed; + std::unique_ptr<PPCallbacks> DelegatedPPCallbacks = + Callbacks.createPPCallbacks(); + if (DelegatedPPCallbacks) + Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks)); + Act->Execute(); // Run the callbacks. @@ -335,9 +371,9 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( } } - return PrecompiledPreamble( - std::move(*PreamblePCHFile), std::move(PreambleBytes), - PreambleEndsAtStartOfLine, std::move(FilesInPreamble)); + return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes), + PreambleEndsAtStartOfLine, + std::move(FilesInPreamble)); } PreambleBounds PrecompiledPreamble::getBounds() const { @@ -425,27 +461,33 @@ bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation, } void PrecompiledPreamble::AddImplicitPreamble( - CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const { + CompilerInvocation &CI, IntrusiveRefCntPtr<vfs::FileSystem> &VFS, + llvm::MemoryBuffer *MainFileBuffer) const { + assert(VFS && "VFS must not be null"); + auto &PreprocessorOpts = CI.getPreprocessorOpts(); + // Remap main file to point to MainFileBuffer. + auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile(); + PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer); + // Configure ImpicitPCHInclude. PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size(); PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; - PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath(); PreprocessorOpts.DisablePCHValidation = true; - // Remap main file to point to MainFileBuffer. - auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile(); - PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer); + setupPreambleStorage(Storage, PreprocessorOpts, VFS); } PrecompiledPreamble::PrecompiledPreamble( - TempPCHFile PCHFile, std::vector<char> PreambleBytes, + PCHStorage Storage, std::vector<char> PreambleBytes, bool PreambleEndsAtStartOfLine, llvm::StringMap<PreambleFileHash> FilesInPreamble) - : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble), + : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)), PreambleBytes(std::move(PreambleBytes)), - PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) { + assert(this->Storage.getKind() != PCHStorage::Kind::Empty); +} llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() { @@ -462,9 +504,15 @@ llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, StringRef Suffix) { llvm::SmallString<64> File; - auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File); + // Using a version of createTemporaryFile with a file descriptor guarantees + // that we would never get a race condition in a multi-threaded setting (i.e., + // multiple threads getting the same temporary path). + int FD; + auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File); if (EC) return EC; + // We only needed to make sure the file exists, close the file right away. + llvm::sys::Process::SafelyCloseFileDescriptor(FD); return TempPCHFile(std::move(File).str()); } @@ -506,6 +554,87 @@ llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const { return *FilePath; } +PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File) + : StorageKind(Kind::TempFile) { + new (&asFile()) TempPCHFile(std::move(File)); +} + +PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory) + : StorageKind(Kind::InMemory) { + new (&asMemory()) InMemoryPreamble(std::move(Memory)); +} + +PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() { + *this = std::move(Other); +} + +PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage:: +operator=(PCHStorage &&Other) { + destroy(); + + StorageKind = Other.StorageKind; + switch (StorageKind) { + case Kind::Empty: + // do nothing; + break; + case Kind::TempFile: + new (&asFile()) TempPCHFile(std::move(Other.asFile())); + break; + case Kind::InMemory: + new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory())); + break; + } + + Other.setEmpty(); + return *this; +} + +PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); } + +PrecompiledPreamble::PCHStorage::Kind +PrecompiledPreamble::PCHStorage::getKind() const { + return StorageKind; +} + +PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() { + assert(getKind() == Kind::TempFile); + return *reinterpret_cast<TempPCHFile *>(Storage.buffer); +} + +const PrecompiledPreamble::TempPCHFile & +PrecompiledPreamble::PCHStorage::asFile() const { + return const_cast<PCHStorage *>(this)->asFile(); +} + +PrecompiledPreamble::InMemoryPreamble & +PrecompiledPreamble::PCHStorage::asMemory() { + assert(getKind() == Kind::InMemory); + return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer); +} + +const PrecompiledPreamble::InMemoryPreamble & +PrecompiledPreamble::PCHStorage::asMemory() const { + return const_cast<PCHStorage *>(this)->asMemory(); +} + +void PrecompiledPreamble::PCHStorage::destroy() { + switch (StorageKind) { + case Kind::Empty: + return; + case Kind::TempFile: + asFile().~TempPCHFile(); + return; + case Kind::InMemory: + asMemory().~InMemoryPreamble(); + return; + } +} + +void PrecompiledPreamble::PCHStorage::setEmpty() { + destroy(); + StorageKind = Kind::Empty; +} + PrecompiledPreamble::PreambleFileHash PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size, time_t ModTime) { @@ -530,11 +659,47 @@ PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer( return Result; } +void PrecompiledPreamble::setupPreambleStorage( + const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts, + IntrusiveRefCntPtr<vfs::FileSystem> &VFS) { + if (Storage.getKind() == PCHStorage::Kind::TempFile) { + const TempPCHFile &PCHFile = Storage.asFile(); + PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath(); + + // Make sure we can access the PCH file even if we're using a VFS + IntrusiveRefCntPtr<vfs::FileSystem> RealFS = vfs::getRealFileSystem(); + auto PCHPath = PCHFile.getFilePath(); + if (VFS == RealFS || VFS->exists(PCHPath)) + return; + auto Buf = RealFS->getBufferForFile(PCHPath); + if (!Buf) { + // We can't read the file even from RealFS, this is clearly an error, + // but we'll just leave the current VFS as is and let clang's code + // figure out what to do with missing PCH. + return; + } + + // We have a slight inconsistency here -- we're using the VFS to + // read files, but the PCH was generated in the real file system. + VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS); + } else { + assert(Storage.getKind() == PCHStorage::Kind::InMemory); + // For in-memory preamble, we have to provide a VFS overlay that makes it + // accessible. + StringRef PCHPath = getInMemoryPreamblePath(); + PreprocessorOpts.ImplicitPCHInclude = PCHPath; + + auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data); + VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS); + } +} + void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {} void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {} void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {} -void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) {} +std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() { + return nullptr; +} std::error_code clang::make_error_code(BuildPreambleError Error) { return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory()); diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 914039ad5bb1d..2e023294f1e8e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -143,6 +143,8 @@ public: ArrayRef<int> Ids) override; void PragmaWarningPush(SourceLocation Loc, int Level) override; void PragmaWarningPop(SourceLocation Loc) override; + void PragmaAssumeNonNullBegin(SourceLocation Loc) override; + void PragmaAssumeNonNullEnd(SourceLocation Loc) override; bool HandleFirstTokOnLine(Token &Tok); @@ -549,6 +551,22 @@ void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) { setEmittedDirectiveOnThisLine(); } +void PrintPPOutputPPCallbacks:: +PragmaAssumeNonNullBegin(SourceLocation Loc) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma clang assume_nonnull begin"; + setEmittedDirectiveOnThisLine(); +} + +void PrintPPOutputPPCallbacks:: +PragmaAssumeNonNullEnd(SourceLocation Loc) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma clang assume_nonnull end"; + setEmittedDirectiveOnThisLine(); +} + /// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this /// is called for the first token on each new line. If this really is the start /// of a new logical line, handle it and return true, otherwise return false. @@ -702,6 +720,12 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. SourceLocation StartLoc = Tok.getLocation(); Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); + } else if (Tok.is(tok::eod)) { + // Don't print end of directive tokens, since they are typically newlines + // that mess up our line tracking. These come from unknown pre-processor + // directives or hash-prefixed comments in standalone assembly files. + PP.Lex(Tok); + continue; } else if (Tok.is(tok::annot_module_include)) { // PrintPPOutputPPCallbacks::InclusionDirective handles producing // appropriate output here. Ignore this token entirely. diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 5efa6aeaf760a..4d587048f62d7 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -154,7 +154,7 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { return true; } -#ifdef CLANG_ENABLE_OBJC_REWRITER +#if CLANG_ENABLE_OBJC_REWRITER std::unique_ptr<ASTConsumer> RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 21686b8c78ea5..1954b24aedad3 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -31,7 +31,7 @@ #include "llvm/Support/raw_ostream.h" #include <memory> -#ifdef CLANG_ENABLE_OBJC_REWRITER +#if CLANG_ENABLE_OBJC_REWRITER using namespace clang; using llvm::utostr; diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index e0d813df70f8a..096b81bc3f08c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -30,7 +30,7 @@ #include "llvm/Support/raw_ostream.h" #include <memory> -#ifdef CLANG_ENABLE_OBJC_REWRITER +#if CLANG_ENABLE_OBJC_REWRITER using namespace clang; using llvm::utostr; diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp index d49e983fcd377..288507310baab 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -30,34 +30,45 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level, default: llvm_unreachable( "Diagnostic not handled during diagnostic buffering!"); case DiagnosticsEngine::Note: + All.emplace_back(Level, Notes.size()); Notes.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Warning: + All.emplace_back(Level, Warnings.size()); Warnings.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Remark: + All.emplace_back(Level, Remarks.size()); Remarks.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Error: case DiagnosticsEngine::Fatal: + All.emplace_back(Level, Errors.size()); Errors.emplace_back(Info.getLocation(), Buf.str()); break; } } void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { - // FIXME: Flush the diagnostics in order. - for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) - << it->second; - for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, "%0")) - << it->second; - for (const_iterator it = remark_begin(), ie = remark_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Remark, "%0")) - << it->second; - for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) - << it->second; + for (auto it = All.begin(), ie = All.end(); it != ie; ++it) { + auto Diag = Diags.Report(Diags.getCustomDiagID(it->first, "%0")); + switch (it->first) { + default: llvm_unreachable( + "Diagnostic not handled during diagnostic flushing!"); + case DiagnosticsEngine::Note: + Diag << Notes[it->second].second; + break; + case DiagnosticsEngine::Warning: + Diag << Warnings[it->second].second; + break; + case DiagnosticsEngine::Remark: + Diag << Remarks[it->second].second; + break; + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: + Diag << Errors[it->second].second; + break; + } + } } diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 427d15ed703ae..0df5393a309bf 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -229,22 +229,52 @@ public: return true; } - // Return true if string literal is found. - // When true, P marks begin-position of S in content. - bool Search(StringRef S, bool EnsureStartOfWord = false) { + // Return true if string literal S is matched in content. + // When true, P marks begin-position of the match, and calling Advance sets C + // to end-position of the match. + // If S is the empty string, then search for any letter instead (makes sense + // with FinishDirectiveToken=true). + // If EnsureStartOfWord, then skip matches that don't start a new word. + // If FinishDirectiveToken, then assume the match is the start of a comment + // directive for -verify, and extend the match to include the entire first + // token of that directive. + bool Search(StringRef S, bool EnsureStartOfWord = false, + bool FinishDirectiveToken = false) { do { - P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.size(); + if (!S.empty()) { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.size(); + } + else { + P = C; + while (P != End && !isLetter(*P)) + ++P; + PEnd = P + 1; + } if (P == End) break; - if (!EnsureStartOfWord - // Check if string literal starts a new word. - || P == Begin || isWhitespace(P[-1]) - // Or it could be preceded by the start of a comment. - || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') - && P[-2] == '/')) - return true; - // Otherwise, skip and search again. + // If not start of word but required, skip and search again. + if (EnsureStartOfWord + // Check if string literal starts a new word. + && !(P == Begin || isWhitespace(P[-1]) + // Or it could be preceded by the start of a comment. + || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') + && P[-2] == '/'))) + continue; + if (FinishDirectiveToken) { + while (PEnd != End && (isAlphanumeric(*PEnd) + || *PEnd == '-' || *PEnd == '_')) + ++PEnd; + // Put back trailing digits and hyphens to be parsed later as a count + // or count range. Because -verify prefixes must start with letters, + // we know the actual directive we found starts with a letter, so + // we won't put back the entire directive word and thus record an empty + // string. + assert(isLetter(*P) && "-verify prefix must start with a letter"); + while (isDigit(PEnd[-1]) || PEnd[-1] == '-') + --PEnd; + } + return true; } while (Advance()); return false; } @@ -314,37 +344,68 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { - // Search for token: expected - if (!PH.Search("expected", true)) + // Search for the initial directive token. + // If one prefix, save time by searching only for its directives. + // Otherwise, search for any potential directive token and check it later. + const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes; + if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true) + : PH.Search("", true, true))) break; PH.Advance(); - // Next token: - - if (!PH.Next("-")) - continue; - PH.Advance(); + // Default directive kind. + bool RegexKind = false; + const char* KindStr = "string"; + + // Parse the initial directive token in reverse so we can easily determine + // its exact actual prefix. If we were to parse it from the front instead, + // it would be harder to determine where the prefix ends because there + // might be multiple matching -verify prefixes because some might prefix + // others. + StringRef DToken(PH.P, PH.C - PH.P); - // Next token: { error | warning | note } + // Regex in initial directive token: -re + if (DToken.endswith("-re")) { + RegexKind = true; + KindStr = "regex"; + DToken = DToken.substr(0, DToken.size()-3); + } + + // Type in initial directive token: -{error|warning|note|no-diagnostics} DirectiveList *DL = nullptr; - if (PH.Next("error")) + bool NoDiag = false; + StringRef DType; + if (DToken.endswith(DType="-error")) DL = ED ? &ED->Errors : nullptr; - else if (PH.Next("warning")) + else if (DToken.endswith(DType="-warning")) DL = ED ? &ED->Warnings : nullptr; - else if (PH.Next("remark")) + else if (DToken.endswith(DType="-remark")) DL = ED ? &ED->Remarks : nullptr; - else if (PH.Next("note")) + else if (DToken.endswith(DType="-note")) DL = ED ? &ED->Notes : nullptr; - else if (PH.Next("no-diagnostics")) { + else if (DToken.endswith(DType="-no-diagnostics")) { + NoDiag = true; + if (RegexKind) + continue; + } + else + continue; + DToken = DToken.substr(0, DToken.size()-DType.size()); + + // What's left in DToken is the actual prefix. That might not be a -verify + // prefix even if there is only one -verify prefix (for example, the full + // DToken is foo-bar-warning, but foo is the only -verify prefix). + if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken)) + continue; + + if (NoDiag) { if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/true; else Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; continue; - } else - continue; - PH.Advance(); - + } if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/false; @@ -357,17 +418,6 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, if (!DL) return true; - // Default directive kind. - bool RegexKind = false; - const char* KindStr = "string"; - - // Next optional token: - - if (PH.Next("-re")) { - PH.Advance(); - RegexKind = true; - KindStr = "regex"; - } - // Next optional token: @ SourceLocation ExpectedLoc; bool MatchAnyLine = false; @@ -416,9 +466,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, MatchAnyLine = true; ExpectedLoc = SM.translateFileLineCol(FE, 1, 1); } + } else if (PH.Next("*")) { + MatchAnyLine = true; + ExpectedLoc = SourceLocation(); } - if (ExpectedLoc.isInvalid()) { + if (ExpectedLoc.isInvalid() && !MatchAnyLine) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_line) << KindStr; continue; @@ -650,7 +703,10 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, llvm::raw_svector_ostream OS(Fmt); for (auto *DirPtr : DL) { Directive &D = *DirPtr; - OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc); + if (D.DiagnosticLoc.isInvalid()) + OS << "\n File *"; + else + OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc); if (D.MatchAnyLine) OS << " Line *"; else @@ -708,7 +764,8 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, continue; } - if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) + if (!D.DiagnosticLoc.isInvalid() && + !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) continue; const std::string &RightText = II->second; diff --git a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 1666315588065..4167e1fe20b81 100644 --- a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -94,18 +94,18 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case RewriteMacros: return llvm::make_unique<RewriteMacrosAction>(); case RewriteTest: return llvm::make_unique<RewriteTestAction>(); -#ifdef CLANG_ENABLE_OBJC_REWRITER +#if CLANG_ENABLE_OBJC_REWRITER case RewriteObjC: return llvm::make_unique<RewriteObjCAction>(); #else case RewriteObjC: Action = "RewriteObjC"; break; #endif -#ifdef CLANG_ENABLE_ARCMT +#if CLANG_ENABLE_ARCMT case MigrateSource: return llvm::make_unique<arcmt::MigrateSourceAction>(); #else case MigrateSource: Action = "MigrateSource"; break; #endif -#ifdef CLANG_ENABLE_STATIC_ANALYZER +#if CLANG_ENABLE_STATIC_ANALYZER case RunAnalysis: return llvm::make_unique<ento::AnalysisAction>(); #else case RunAnalysis: Action = "RunAnalysis"; break; @@ -113,8 +113,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case RunPreprocessorOnly: return llvm::make_unique<PreprocessOnlyAction>(); } -#if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \ - || !defined(CLANG_ENABLE_OBJC_REWRITER) +#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER \ + || !CLANG_ENABLE_OBJC_REWRITER CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action; return 0; #else @@ -135,7 +135,7 @@ CreateFrontendAction(CompilerInstance &CI) { Act = llvm::make_unique<FixItRecompile>(std::move(Act)); } -#ifdef CLANG_ENABLE_ARCMT +#if CLANG_ENABLE_ARCMT if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource && CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) { // Potentially wrap the base FE action in an ARC Migrate Tool action. @@ -179,7 +179,8 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { std::unique_ptr<OptTable> Opts = driver::createDriverOptTable(); Opts->PrintHelp(llvm::outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org", - /*Include=*/ driver::options::CC1Option, /*Exclude=*/ 0); + /*Include=*/driver::options::CC1Option, + /*Exclude=*/0, /*ShowAllAliases=*/false); return true; } @@ -227,7 +228,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); } -#ifdef CLANG_ENABLE_STATIC_ANALYZER +#if CLANG_ENABLE_STATIC_ANALYZER // Honor -analyzer-checker-help. // This should happen AFTER plugins have been loaded! if (Clang->getAnalyzerOpts()->ShowCheckerHelp) { diff --git a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_cmath.h b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_cmath.h index 9bef82611aa42..5331ba401a954 100644 --- a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_cmath.h +++ b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_cmath.h @@ -131,15 +131,6 @@ __DEVICE__ float ldexp(float __arg, int __exp) { __DEVICE__ float log(float __x) { return ::logf(__x); } __DEVICE__ float log10(float __x) { return ::log10f(__x); } __DEVICE__ float modf(float __x, float *__iptr) { return ::modff(__x, __iptr); } -__DEVICE__ float nexttoward(float __from, double __to) { - return __builtin_nexttowardf(__from, __to); -} -__DEVICE__ double nexttoward(double __from, double __to) { - return __builtin_nexttoward(__from, __to); -} -__DEVICE__ float nexttowardf(float __from, double __to) { - return __builtin_nexttowardf(__from, __to); -} __DEVICE__ float pow(float __base, float __exp) { return ::powf(__base, __exp); } @@ -157,6 +148,10 @@ __DEVICE__ float sqrt(float __x) { return ::sqrtf(__x); } __DEVICE__ float tan(float __x) { return ::tanf(__x); } __DEVICE__ float tanh(float __x) { return ::tanhf(__x); } +// Notably missing above is nexttoward. We omit it because +// libdevice doesn't provide an implementation, and we don't want to be in the +// business of implementing tricky libm functions in this header. + // Now we've defined everything we promised we'd define in // __clang_cuda_math_forward_declares.h. We need to do two additional things to // fix up our math functions. @@ -295,13 +290,6 @@ ldexp(__T __x, int __exp) { return std::ldexp((double)__x, __exp); } -template <typename __T> -__DEVICE__ typename __clang_cuda_enable_if<std::numeric_limits<__T>::is_integer, - double>::type -nexttoward(__T __from, double __to) { - return std::nexttoward((double)__from, __to); -} - template <typename __T1, typename __T2> __DEVICE__ typename __clang_cuda_enable_if< std::numeric_limits<__T1>::is_specialized && @@ -388,7 +376,6 @@ using ::lrint; using ::lround; using ::nearbyint; using ::nextafter; -using ::nexttoward; using ::pow; using ::remainder; using ::remquo; @@ -456,8 +443,6 @@ using ::lroundf; using ::modff; using ::nearbyintf; using ::nextafterf; -using ::nexttowardf; -using ::nexttowardf; using ::powf; using ::remainderf; using ::remquof; diff --git a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_intrinsics.h b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_intrinsics.h index b43ce21d0bb32..02d68a2e618ed 100644 --- a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_intrinsics.h +++ b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_intrinsics.h @@ -92,6 +92,152 @@ __MAKE_SHUFFLES(__shfl_xor, __nvvm_shfl_bfly_i32, __nvvm_shfl_bfly_f32, 0x1f); #endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300 +#if CUDA_VERSION >= 9000 +#if (!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300) +// __shfl_sync_* variants available in CUDA-9 +#pragma push_macro("__MAKE_SYNC_SHUFFLES") +#define __MAKE_SYNC_SHUFFLES(__FnName, __IntIntrinsic, __FloatIntrinsic, \ + __Mask) \ + inline __device__ int __FnName(unsigned int __mask, int __val, int __offset, \ + int __width = warpSize) { \ + return __IntIntrinsic(__mask, __val, __offset, \ + ((warpSize - __width) << 8) | (__Mask)); \ + } \ + inline __device__ float __FnName(unsigned int __mask, float __val, \ + int __offset, int __width = warpSize) { \ + return __FloatIntrinsic(__mask, __val, __offset, \ + ((warpSize - __width) << 8) | (__Mask)); \ + } \ + inline __device__ unsigned int __FnName(unsigned int __mask, \ + unsigned int __val, int __offset, \ + int __width = warpSize) { \ + return static_cast<unsigned int>( \ + ::__FnName(__mask, static_cast<int>(__val), __offset, __width)); \ + } \ + inline __device__ long long __FnName(unsigned int __mask, long long __val, \ + int __offset, int __width = warpSize) { \ + struct __Bits { \ + int __a, __b; \ + }; \ + _Static_assert(sizeof(__val) == sizeof(__Bits)); \ + _Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \ + __Bits __tmp; \ + memcpy(&__val, &__tmp, sizeof(__val)); \ + __tmp.__a = ::__FnName(__mask, __tmp.__a, __offset, __width); \ + __tmp.__b = ::__FnName(__mask, __tmp.__b, __offset, __width); \ + long long __ret; \ + memcpy(&__ret, &__tmp, sizeof(__tmp)); \ + return __ret; \ + } \ + inline __device__ unsigned long long __FnName( \ + unsigned int __mask, unsigned long long __val, int __offset, \ + int __width = warpSize) { \ + return static_cast<unsigned long long>(::__FnName( \ + __mask, static_cast<unsigned long long>(__val), __offset, __width)); \ + } \ + inline __device__ long __FnName(unsigned int __mask, long __val, \ + int __offset, int __width = warpSize) { \ + _Static_assert(sizeof(long) == sizeof(long long) || \ + sizeof(long) == sizeof(int)); \ + if (sizeof(long) == sizeof(long long)) { \ + return static_cast<long>(::__FnName( \ + __mask, static_cast<long long>(__val), __offset, __width)); \ + } else if (sizeof(long) == sizeof(int)) { \ + return static_cast<long>( \ + ::__FnName(__mask, static_cast<int>(__val), __offset, __width)); \ + } \ + } \ + inline __device__ unsigned long __FnName(unsigned int __mask, \ + unsigned long __val, int __offset, \ + int __width = warpSize) { \ + return static_cast<unsigned long>( \ + ::__FnName(__mask, static_cast<long>(__val), __offset, __width)); \ + } \ + inline __device__ double __FnName(unsigned int __mask, double __val, \ + int __offset, int __width = warpSize) { \ + long long __tmp; \ + _Static_assert(sizeof(__tmp) == sizeof(__val)); \ + memcpy(&__tmp, &__val, sizeof(__val)); \ + __tmp = ::__FnName(__mask, __tmp, __offset, __width); \ + double __ret; \ + memcpy(&__ret, &__tmp, sizeof(__ret)); \ + return __ret; \ + } +__MAKE_SYNC_SHUFFLES(__shfl_sync, __nvvm_shfl_sync_idx_i32, + __nvvm_shfl_sync_idx_f32, 0x1f); +// We use 0 rather than 31 as our mask, because shfl.up applies to lanes >= +// maxLane. +__MAKE_SYNC_SHUFFLES(__shfl_up_sync, __nvvm_shfl_sync_up_i32, + __nvvm_shfl_sync_up_f32, 0); +__MAKE_SYNC_SHUFFLES(__shfl_down_sync, __nvvm_shfl_sync_down_i32, + __nvvm_shfl_sync_down_f32, 0x1f); +__MAKE_SYNC_SHUFFLES(__shfl_xor_sync, __nvvm_shfl_sync_bfly_i32, + __nvvm_shfl_sync_bfly_f32, 0x1f); +#pragma pop_macro("__MAKE_SYNC_SHUFFLES") + +inline __device__ void __syncwarp(unsigned int mask = 0xffffffff) { + return __nvvm_bar_warp_sync(mask); +} + +inline __device__ void __barrier_sync(unsigned int id) { + __nvvm_barrier_sync(id); +} + +inline __device__ void __barrier_sync_count(unsigned int id, + unsigned int count) { + __nvvm_barrier_sync_cnt(id, count); +} + +inline __device__ int __all_sync(unsigned int mask, int pred) { + return __nvvm_vote_all_sync(mask, pred); +} + +inline __device__ int __any_sync(unsigned int mask, int pred) { + return __nvvm_vote_any_sync(mask, pred); +} + +inline __device__ int __uni_sync(unsigned int mask, int pred) { + return __nvvm_vote_uni_sync(mask, pred); +} + +inline __device__ unsigned int __ballot_sync(unsigned int mask, int pred) { + return __nvvm_vote_ballot_sync(mask, pred); +} + +inline __device__ unsigned int __activemask() { return __nvvm_vote_ballot(1); } + +inline __device__ unsigned int __fns(unsigned mask, unsigned base, int offset) { + return __nvvm_fns(mask, base, offset); +} + +#endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300 + +// Define __match* builtins CUDA-9 headers expect to see. +#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 700 +inline __device__ unsigned int __match32_any_sync(unsigned int mask, + unsigned int value) { + return __nvvm_match_any_sync_i32(mask, value); +} + +inline __device__ unsigned long long +__match64_any_sync(unsigned int mask, unsigned long long value) { + return __nvvm_match_any_sync_i64(mask, value); +} + +inline __device__ unsigned int +__match32_all_sync(unsigned int mask, unsigned int value, int *pred) { + return __nvvm_match_all_sync_i32p(mask, value, pred); +} + +inline __device__ unsigned long long +__match64_all_sync(unsigned int mask, unsigned long long value, int *pred) { + return __nvvm_match_all_sync_i64p(mask, value, pred); +} +#include "crt/sm_70_rt.hpp" + +#endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 700 +#endif // __CUDA_VERSION >= 9000 + // sm_32 intrinsics: __ldg and __funnelshift_{l,lc,r,rc}. // Prevent the vanilla sm_32 intrinsics header from being included. diff --git a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_math_forward_declares.h b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_math_forward_declares.h index 49c805151d65f..c31b1f4cda355 100644 --- a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_math_forward_declares.h +++ b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_math_forward_declares.h @@ -149,9 +149,6 @@ __DEVICE__ double nearbyint(double); __DEVICE__ float nearbyint(float); __DEVICE__ double nextafter(double, double); __DEVICE__ float nextafter(float, float); -__DEVICE__ double nexttoward(double, double); -__DEVICE__ float nexttoward(float, double); -__DEVICE__ float nexttowardf(float, double); __DEVICE__ double pow(double, double); __DEVICE__ double pow(double, int); __DEVICE__ float pow(float, float); @@ -185,6 +182,10 @@ __DEVICE__ float tgamma(float); __DEVICE__ double trunc(double); __DEVICE__ float trunc(float); +// Notably missing above is nexttoward, which we don't define on +// the device side because libdevice doesn't give us an implementation, and we +// don't want to be in the business of writing one ourselves. + // We need to define these overloads in exactly the namespace our standard // library uses (including the right inline namespace), otherwise they won't be // picked up by other functions in the standard library (e.g. functions in @@ -255,7 +256,6 @@ using ::nan; using ::nanf; using ::nearbyint; using ::nextafter; -using ::nexttoward; using ::pow; using ::remainder; using ::remquo; diff --git a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_runtime_wrapper.h b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_runtime_wrapper.h index 931d44b6965b7..a82a8490f3670 100644 --- a/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_runtime_wrapper.h +++ b/contrib/llvm/tools/clang/lib/Headers/__clang_cuda_runtime_wrapper.h @@ -62,7 +62,7 @@ #include "cuda.h" #if !defined(CUDA_VERSION) #error "cuda.h did not define CUDA_VERSION" -#elif CUDA_VERSION < 7000 || CUDA_VERSION > 8000 +#elif CUDA_VERSION < 7000 || CUDA_VERSION > 9000 #error "Unsupported CUDA version!" #endif @@ -86,7 +86,11 @@ #define __COMMON_FUNCTIONS_H__ #undef __CUDACC__ +#if CUDA_VERSION < 9000 #define __CUDABE__ +#else +#define __CUDA_LIBDEVICE__ +#endif // Disables definitions of device-side runtime support stubs in // cuda_device_runtime_api.h #include "driver_types.h" @@ -94,6 +98,7 @@ #include "host_defines.h" #undef __CUDABE__ +#undef __CUDA_LIBDEVICE__ #define __CUDACC__ #include "cuda_runtime.h" @@ -105,7 +110,9 @@ #define __nvvm_memcpy(s, d, n, a) __builtin_memcpy(s, d, n) #define __nvvm_memset(d, c, n, a) __builtin_memset(d, c, n) +#if CUDA_VERSION < 9000 #include "crt/device_runtime.h" +#endif #include "crt/host_runtime.h" // device_runtime.h defines __cxa_* macros that will conflict with // cxxabi.h. @@ -166,7 +173,18 @@ inline __host__ double __signbitd(double x) { // __device__. #pragma push_macro("__forceinline__") #define __forceinline__ __device__ __inline__ __attribute__((always_inline)) + +#pragma push_macro("__float2half_rn") +#if CUDA_VERSION >= 9000 +// CUDA-9 has conflicting prototypes for __float2half_rn(float f) in +// cuda_fp16.h[pp] and device_functions.hpp. We need to get the one in +// device_functions.hpp out of the way. +#define __float2half_rn __float2half_rn_disabled +#endif + #include "device_functions.hpp" +#pragma pop_macro("__float2half_rn") + // math_function.hpp uses the __USE_FAST_MATH__ macro to determine whether we // get the slow-but-accurate or fast-but-inaccurate versions of functions like @@ -247,7 +265,23 @@ static inline __device__ void __brkpt(int __c) { __brkpt(); } #pragma push_macro("__GNUC__") #undef __GNUC__ #define signbit __ignored_cuda_signbit + +// CUDA-9 omits device-side definitions of some math functions if it sees +// include guard from math.h wrapper from libstdc++. We have to undo the header +// guard temporarily to get the definitions we need. +#pragma push_macro("_GLIBCXX_MATH_H") +#pragma push_macro("_LIBCPP_VERSION") +#if CUDA_VERSION >= 9000 +#undef _GLIBCXX_MATH_H +// We also need to undo another guard that checks for libc++ 3.8+ +#ifdef _LIBCPP_VERSION +#define _LIBCPP_VERSION 3700 +#endif +#endif + #include "math_functions.hpp" +#pragma pop_macro("_GLIBCXX_MATH_H") +#pragma pop_macro("_LIBCPP_VERSION") #pragma pop_macro("__GNUC__") #pragma pop_macro("signbit") diff --git a/contrib/llvm/tools/clang/lib/Headers/arm64intr.h b/contrib/llvm/tools/clang/lib/Headers/arm64intr.h new file mode 100644 index 0000000000000..be5228361895c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/arm64intr.h @@ -0,0 +1,49 @@ +/*===---- arm64intr.h - ARM64 Windows intrinsics -------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +/* Only include this if we're compiling for the windows platform. */ +#ifndef _MSC_VER +#include_next <arm64intr.h> +#else + +#ifndef __ARM64INTR_H +#define __ARM64INTR_H + +typedef enum +{ + _ARM64_BARRIER_SY = 0xF, + _ARM64_BARRIER_ST = 0xE, + _ARM64_BARRIER_LD = 0xD, + _ARM64_BARRIER_ISH = 0xB, + _ARM64_BARRIER_ISHST = 0xA, + _ARM64_BARRIER_ISHLD = 0x9, + _ARM64_BARRIER_NSH = 0x7, + _ARM64_BARRIER_NSHST = 0x6, + _ARM64_BARRIER_NSHLD = 0x5, + _ARM64_BARRIER_OSH = 0x3, + _ARM64_BARRIER_OSHST = 0x2, + _ARM64_BARRIER_OSHLD = 0x1 +} _ARM64INTR_BARRIER_TYPE; + +#endif /* __ARM64INTR_H */ +#endif /* _MSC_VER */ diff --git a/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h b/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h index 576f761b25426..caf4ced920545 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h @@ -145,13 +145,21 @@ _mm256_andnot_si256(__m256i __a, __m256i __b) static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_avg_epu8(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pavgb256((__v32qi)__a, (__v32qi)__b); + typedef unsigned short __v32hu __attribute__((__vector_size__(64))); + return (__m256i)__builtin_convertvector( + ((__builtin_convertvector((__v32qu)__a, __v32hu) + + __builtin_convertvector((__v32qu)__b, __v32hu)) + 1) + >> 1, __v32qu); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_avg_epu16(__m256i __a, __m256i __b) { - return (__m256i)__builtin_ia32_pavgw256((__v16hi)__a, (__v16hi)__b); + typedef unsigned int __v16su __attribute__((__vector_size__(64))); + return (__m256i)__builtin_convertvector( + ((__builtin_convertvector((__v16hu)__a, __v16su) + + __builtin_convertvector((__v16hu)__b, __v16su)) + 1) + >> 1, __v16hu); } static __inline__ __m256i __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h index 41958b7214e2f..3ff0e3aafdcc2 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h @@ -56,293 +56,145 @@ _mm512_setzero_hi(void) { /* Integer compare */ -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_pcmpeqb512_mask((__v64qi)__a, (__v64qi)__b, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_pcmpeqb512_mask((__v64qi)__a, (__v64qi)__b, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 0, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 0, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_pcmpeqw512_mask((__v32hi)__a, (__v32hi)__b, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_pcmpeqw512_mask((__v32hi)__a, (__v32hi)__b, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 0, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 0, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpge_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 5, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 5, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpge_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 5, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 5, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpge_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 5, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 5, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpge_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 5, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 5, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_pcmpgtb512_mask((__v64qi)__a, (__v64qi)__b, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_pcmpgtb512_mask((__v64qi)__a, (__v64qi)__b, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 6, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 6, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_pcmpgtw512_mask((__v32hi)__a, (__v32hi)__b, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_pcmpgtw512_mask((__v32hi)__a, (__v32hi)__b, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 6, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 6, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmple_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 2, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 2, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmple_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 2, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 2, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmple_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 2, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 2, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmple_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 2, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 2, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmplt_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 1, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 1, - __u); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmplt_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 1, - (__mmask64)-1); -} - -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 1, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmplt_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 1, - (__mmask32)-1); -} +#define _mm512_cmp_epi8_mask(a, b, p) __extension__ ({ \ + (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)-1); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 1, - __u); -} +#define _mm512_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ + (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)(m)); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmplt_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 1, - (__mmask32)-1); -} +#define _mm512_cmp_epu8_mask(a, b, p) __extension__ ({ \ + (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)-1); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 1, - __u); -} +#define _mm512_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ + (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)(m)); }) -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epi8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 4, - (__mmask64)-1); -} +#define _mm512_cmp_epi16_mask(a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)-1); }) -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epi8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)__a, (__v64qi)__b, 4, - __u); -} +#define _mm512_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)(m)); }) -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epu8_mask(__m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 4, - (__mmask64)-1); -} +#define _mm512_cmp_epu16_mask(a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)-1); }) -static __inline__ __mmask64 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epu8_mask(__mmask64 __u, __m512i __a, __m512i __b) { - return (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)__a, (__v64qi)__b, 4, - __u); -} +#define _mm512_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)(m)); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epi16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 4, - (__mmask32)-1); -} +#define _mm512_cmpeq_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epi8_mask(A, B) \ + _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epi8_mask(k, A, B) \ + _mm512_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epi16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)__a, (__v32hi)__b, 4, - __u); -} +#define _mm512_cmpeq_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epu8_mask(A, B) \ + _mm512_cmp_epu8_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epu8_mask(k, A, B) \ + _mm512_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epu16_mask(__m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 4, - (__mmask32)-1); -} +#define _mm512_cmpeq_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epi16_mask(A, B) \ + _mm512_cmp_epi16_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epi16_mask(k, A, B) \ + _mm512_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epu16_mask(__mmask32 __u, __m512i __a, __m512i __b) { - return (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)__a, (__v32hi)__b, 4, - __u); -} +#define _mm512_cmpeq_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epu16_mask(A, B) \ + _mm512_cmp_epu16_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epu16_mask(k, A, B) \ + _mm512_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_NE) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_add_epi8 (__m512i __A, __m512i __B) { @@ -706,57 +558,55 @@ _mm512_maskz_adds_epu16 (__mmask32 __U, __m512i __A, __m512i __B) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_avg_epu8 (__m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A, - (__v64qi) __B, - (__v64qi) _mm512_setzero_qi(), - (__mmask64) -1); + typedef unsigned short __v64hu __attribute__((__vector_size__(128))); + return (__m512i)__builtin_convertvector( + ((__builtin_convertvector((__v64qu) __A, __v64hu) + + __builtin_convertvector((__v64qu) __B, __v64hu)) + 1) + >> 1, __v64qu); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_avg_epu8 (__m512i __W, __mmask64 __U, __m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A, - (__v64qi) __B, - (__v64qi) __W, - (__mmask64) __U); + return (__m512i)__builtin_ia32_selectb_512((__mmask64)__U, + (__v64qi)_mm512_avg_epu8(__A, __B), + (__v64qi)__W); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_avg_epu8 (__mmask64 __U, __m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A, - (__v64qi) __B, - (__v64qi) _mm512_setzero_qi(), - (__mmask64) __U); + return (__m512i)__builtin_ia32_selectb_512((__mmask64)__U, + (__v64qi)_mm512_avg_epu8(__A, __B), + (__v64qi)_mm512_setzero_qi()); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_avg_epu16 (__m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A, - (__v32hi) __B, - (__v32hi) _mm512_setzero_hi(), - (__mmask32) -1); + typedef unsigned int __v32su __attribute__((__vector_size__(128))); + return (__m512i)__builtin_convertvector( + ((__builtin_convertvector((__v32hu) __A, __v32su) + + __builtin_convertvector((__v32hu) __B, __v32su)) + 1) + >> 1, __v32hu); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_avg_epu16 (__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A, - (__v32hi) __B, - (__v32hi) __W, - (__mmask32) __U); + return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, + (__v32hi)_mm512_avg_epu16(__A, __B), + (__v32hi)__W); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_avg_epu16 (__mmask32 __U, __m512i __A, __m512i __B) { - return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A, - (__v32hi) __B, - (__v32hi) _mm512_setzero_hi(), - (__mmask32) __U); + return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, + (__v32hi)_mm512_avg_epu16(__A, __B), + (__v32hi) _mm512_setzero_hi()); } static __inline__ __m512i __DEFAULT_FN_ATTRS @@ -1543,46 +1393,6 @@ _mm512_maskz_cvtepu8_epi16(__mmask32 __U, __m256i __A) } -#define _mm512_cmp_epi8_mask(a, b, p) __extension__ ({ \ - (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)-1); }) - -#define _mm512_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ - (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)(m)); }) - -#define _mm512_cmp_epu8_mask(a, b, p) __extension__ ({ \ - (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)-1); }) - -#define _mm512_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ - (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)(m)); }) - -#define _mm512_cmp_epi16_mask(a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)-1); }) - -#define _mm512_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)(m)); }) - -#define _mm512_cmp_epu16_mask(a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)-1); }) - -#define _mm512_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)(m)); }) - #define _mm512_shufflehi_epi16(A, imm) __extension__ ({ \ (__m512i)__builtin_shufflevector((__v32hi)(__m512i)(A), \ (__v32hi)_mm512_undefined_epi32(), \ @@ -2028,32 +1838,29 @@ _mm512_maskz_mov_epi8 (__mmask64 __U, __m512i __A) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_set1_epi8 (__m512i __O, __mmask64 __M, char __A) { - return (__m512i) __builtin_ia32_pbroadcastb512_gpr_mask (__A, - (__v64qi) __O, - __M); + return (__m512i) __builtin_ia32_selectb_512(__M, + (__v64qi)_mm512_set1_epi8(__A), + (__v64qi) __O); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_set1_epi8 (__mmask64 __M, char __A) { - return (__m512i) __builtin_ia32_pbroadcastb512_gpr_mask (__A, - (__v64qi) - _mm512_setzero_qi(), - __M); + return (__m512i) __builtin_ia32_selectb_512(__M, + (__v64qi) _mm512_set1_epi8(__A), + (__v64qi) _mm512_setzero_si512()); } static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_kunpackd (__mmask64 __A, __mmask64 __B) { - return (__mmask64) __builtin_ia32_kunpckdi ((__mmask64) __A, - (__mmask64) __B); + return (__mmask64) (( __A & 0xFFFFFFFF) | ( __B << 32)); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm512_kunpackw (__mmask32 __A, __mmask32 __B) { - return (__mmask32) __builtin_ia32_kunpcksi ((__mmask32) __A, - (__mmask32) __B); +return (__mmask32) (( __A & 0xFFFF) | ( __B << 16)); } static __inline__ __m512i __DEFAULT_FN_ATTRS @@ -2108,61 +1915,56 @@ _mm512_mask_storeu_epi8 (void *__P, __mmask64 __U, __m512i __A) static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_test_epi8_mask (__m512i __A, __m512i __B) { - return (__mmask64) __builtin_ia32_ptestmb512 ((__v64qi) __A, - (__v64qi) __B, - (__mmask64) -1); + return _mm512_cmpneq_epi8_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_mask_test_epi8_mask (__mmask64 __U, __m512i __A, __m512i __B) { - return (__mmask64) __builtin_ia32_ptestmb512 ((__v64qi) __A, - (__v64qi) __B, __U); + return _mm512_mask_cmpneq_epi8_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm512_test_epi16_mask (__m512i __A, __m512i __B) { - return (__mmask32) __builtin_ia32_ptestmw512 ((__v32hi) __A, - (__v32hi) __B, - (__mmask32) -1); + return _mm512_cmpneq_epi16_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm512_mask_test_epi16_mask (__mmask32 __U, __m512i __A, __m512i __B) { - return (__mmask32) __builtin_ia32_ptestmw512 ((__v32hi) __A, - (__v32hi) __B, __U); + return _mm512_mask_cmpneq_epi16_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_testn_epi8_mask (__m512i __A, __m512i __B) { - return (__mmask64) __builtin_ia32_ptestnmb512 ((__v64qi) __A, - (__v64qi) __B, - (__mmask64) -1); + return _mm512_cmpeq_epi8_mask (_mm512_and_epi32 (__A, __B), _mm512_setzero_qi()); } static __inline__ __mmask64 __DEFAULT_FN_ATTRS _mm512_mask_testn_epi8_mask (__mmask64 __U, __m512i __A, __m512i __B) { - return (__mmask64) __builtin_ia32_ptestnmb512 ((__v64qi) __A, - (__v64qi) __B, __U); + return _mm512_mask_cmpeq_epi8_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm512_testn_epi16_mask (__m512i __A, __m512i __B) { - return (__mmask32) __builtin_ia32_ptestnmw512 ((__v32hi) __A, - (__v32hi) __B, - (__mmask32) -1); + return _mm512_cmpeq_epi16_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm512_mask_testn_epi16_mask (__mmask32 __U, __m512i __A, __m512i __B) { - return (__mmask32) __builtin_ia32_ptestnmw512 ((__v32hi) __A, - (__v32hi) __B, __U); + return _mm512_mask_cmpeq_epi16_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_qi()); } static __inline__ __mmask64 __DEFAULT_FN_ATTRS @@ -2219,17 +2021,17 @@ _mm512_maskz_broadcastb_epi8 (__mmask64 __M, __m128i __A) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_set1_epi16 (__m512i __O, __mmask32 __M, short __A) { - return (__m512i) __builtin_ia32_pbroadcastw512_gpr_mask (__A, - (__v32hi) __O, - __M); + return (__m512i) __builtin_ia32_selectw_512(__M, + (__v32hi) _mm512_set1_epi16(__A), + (__v32hi) __O); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_set1_epi16 (__mmask32 __M, short __A) { - return (__m512i) __builtin_ia32_pbroadcastw512_gpr_mask (__A, - (__v32hi) _mm512_setzero_hi(), - __M); + return (__m512i) __builtin_ia32_selectw_512(__M, + (__v32hi) _mm512_set1_epi16(__A), + (__v32hi) _mm512_setzero_si512()); } static __inline__ __m512i __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512cdintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512cdintrin.h index 23c423584a7a4..ec7e0cd443b4d 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512cdintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512cdintrin.h @@ -130,13 +130,14 @@ _mm512_maskz_lzcnt_epi64 (__mmask8 __U, __m512i __A) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_broadcastmb_epi64 (__mmask8 __A) { - return (__m512i) __builtin_ia32_broadcastmb512 (__A); + return (__m512i) _mm512_set1_epi64((long long) __A); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_broadcastmw_epi32 (__mmask16 __A) { - return (__m512i) __builtin_ia32_broadcastmw512 (__A); + return (__m512i) _mm512_set1_epi32((int) __A); + } #undef __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h index 4fd1add7735b9..2c431d9740cd1 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h @@ -973,25 +973,26 @@ _mm512_movepi64_mask (__m512i __A) static __inline__ __m512 __DEFAULT_FN_ATTRS _mm512_broadcast_f32x2 (__m128 __A) { - return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A, - (__v16sf)_mm512_undefined_ps(), - (__mmask16) -1); + return (__m512)__builtin_shufflevector((__v4sf)__A, + (__v4sf)_mm_undefined_ps(), + 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1); } static __inline__ __m512 __DEFAULT_FN_ATTRS _mm512_mask_broadcast_f32x2 (__m512 __O, __mmask16 __M, __m128 __A) { - return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A, - (__v16sf) - __O, __M); + return (__m512)__builtin_ia32_selectps_512((__mmask16)__M, + (__v16sf)_mm512_broadcast_f32x2(__A), + (__v16sf)__O); } static __inline__ __m512 __DEFAULT_FN_ATTRS _mm512_maskz_broadcast_f32x2 (__mmask16 __M, __m128 __A) { - return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A, - (__v16sf)_mm512_setzero_ps (), - __M); + return (__m512)__builtin_ia32_selectps_512((__mmask16)__M, + (__v16sf)_mm512_broadcast_f32x2(__A), + (__v16sf)_mm512_setzero_ps()); } static __inline__ __m512 __DEFAULT_FN_ATTRS @@ -1044,25 +1045,26 @@ _mm512_maskz_broadcast_f64x2(__mmask8 __M, __m128d __A) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_broadcast_i32x2 (__m128i __A) { - return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A, - (__v16si)_mm512_setzero_si512(), - (__mmask16) -1); + return (__m512i)__builtin_shufflevector((__v4si)__A, + (__v4si)_mm_undefined_si128(), + 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_broadcast_i32x2 (__m512i __O, __mmask16 __M, __m128i __A) { - return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A, - (__v16si) - __O, __M); + return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M, + (__v16si)_mm512_broadcast_i32x2(__A), + (__v16si)__O); } static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_maskz_broadcast_i32x2 (__mmask16 __M, __m128i __A) { - return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A, - (__v16si)_mm512_setzero_si512 (), - __M); + return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M, + (__v16si)_mm512_broadcast_i32x2(__A), + (__v16si)_mm512_setzero_si512()); } static __inline__ __m512i __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h index 4b66acc02fa98..d34f0b1327ae7 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h @@ -258,25 +258,6 @@ _mm512_maskz_broadcastq_epi64 (__mmask8 __M, __m128i __A) (__v8di) _mm512_setzero_si512()); } -static __inline __m512i __DEFAULT_FN_ATTRS -_mm512_maskz_set1_epi32(__mmask16 __M, int __A) -{ - return (__m512i) __builtin_ia32_pbroadcastd512_gpr_mask (__A, - (__v16si) - _mm512_setzero_si512 (), - __M); -} - -#ifdef __x86_64__ -static __inline __m512i __DEFAULT_FN_ATTRS -_mm512_maskz_set1_epi64(__mmask8 __M, long long __A) -{ - return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A, - (__v8di) - _mm512_setzero_si512 (), - __M); -} -#endif static __inline __m512 __DEFAULT_FN_ATTRS _mm512_setzero_ps(void) @@ -336,11 +317,29 @@ _mm512_set1_epi32(int __s) } static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_maskz_set1_epi32(__mmask16 __M, int __A) +{ + return (__m512i)__builtin_ia32_selectd_512(__M, + (__v16si)_mm512_set1_epi32(__A), + (__v16si)_mm512_setzero_si512()); +} + +static __inline __m512i __DEFAULT_FN_ATTRS _mm512_set1_epi64(long long __d) { return (__m512i)(__v8di){ __d, __d, __d, __d, __d, __d, __d, __d }; } +#ifdef __x86_64__ +static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_maskz_set1_epi64(__mmask8 __M, long long __A) +{ + return (__m512i)__builtin_ia32_selectq_512(__M, + (__v8di)_mm512_set1_epi64(__A), + (__v8di)_mm512_setzero_si512()); +} +#endif + static __inline__ __m512 __DEFAULT_FN_ATTRS _mm512_broadcastss_ps(__m128 __A) { @@ -4544,37 +4543,6 @@ _mm512_maskz_unpacklo_epi64 (__mmask8 __U, __m512i __A, __m512i __B) (__v8di)_mm512_setzero_si512()); } -/* Bit Test */ - -static __inline __mmask16 __DEFAULT_FN_ATTRS -_mm512_test_epi32_mask(__m512i __A, __m512i __B) -{ - return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A, - (__v16si) __B, - (__mmask16) -1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) -{ - return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A, - (__v16si) __B, __U); -} - -static __inline __mmask8 __DEFAULT_FN_ATTRS -_mm512_test_epi64_mask(__m512i __A, __m512i __B) -{ - return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A, - (__v8di) __B, - (__mmask8) -1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) -{ - return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A, (__v8di) __B, __U); -} - /* SIMD load ops */ @@ -4845,293 +4813,105 @@ _mm512_knot(__mmask16 __M) /* Integer compare */ -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b, - (__mmask16)-1); -} +#define _mm512_cmpeq_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epi32_mask(A, B) \ + _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epi32_mask(k, A, B) \ + _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b, - __u); -} +#define _mm512_cmpeq_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epu32_mask(A, B) \ + _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epu32_mask(k, A, B) \ + _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b, - __u); -} +#define _mm512_cmpeq_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epi64_mask(A, B) \ + _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epi64_mask(k, A, B) \ + _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpeq_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpeq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpge_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpge_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpge_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpge_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpge_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpgt_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpgt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmple_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmple_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmple_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmple_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmple_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmplt_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmplt_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmplt_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmplt_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmplt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epi32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epu32_mask(__m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { - return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epi64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_cmpneq_epu64_mask(__m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_cmpneq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { - return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4, - __u); -} +#define _mm512_cmpeq_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm512_mask_cmpeq_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm512_cmpge_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GE) +#define _mm512_mask_cmpge_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm512_cmpgt_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GT) +#define _mm512_mask_cmpgt_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm512_cmple_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LE) +#define _mm512_mask_cmple_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm512_cmplt_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LT) +#define _mm512_mask_cmplt_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm512_cmpneq_epu64_mask(A, B) \ + _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_NE) +#define _mm512_mask_cmpneq_epu64_mask(k, A, B) \ + _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_NE) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_cvtepi8_epi32(__m128i __A) @@ -6798,35 +6578,6 @@ _mm512_maskz_permutex2var_ps (__mmask16 __U, __m512 __A, __m512i __I, (__mmask16) __U); } -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_testn_epi32_mask (__m512i __A, __m512i __B) -{ - return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A, - (__v16si) __B, - (__mmask16) -1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) -{ - return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A, - (__v16si) __B, __U); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_testn_epi64_mask (__m512i __A, __m512i __B) -{ - return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A, - (__v8di) __B, - (__mmask8) -1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) -{ - return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A, - (__v8di) __B, __U); -} #define _mm512_cvtt_roundpd_epu32(A, R) __extension__ ({ \ (__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ @@ -7195,76 +6946,100 @@ _mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, int __B) } #define _mm512_shuffle_f32x4(A, B, imm) __extension__ ({ \ - (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(imm), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1); }) + (__m512)__builtin_shufflevector((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + 0 + ((((imm) >> 0) & 0x3) * 4), \ + 1 + ((((imm) >> 0) & 0x3) * 4), \ + 2 + ((((imm) >> 0) & 0x3) * 4), \ + 3 + ((((imm) >> 0) & 0x3) * 4), \ + 0 + ((((imm) >> 2) & 0x3) * 4), \ + 1 + ((((imm) >> 2) & 0x3) * 4), \ + 2 + ((((imm) >> 2) & 0x3) * 4), \ + 3 + ((((imm) >> 2) & 0x3) * 4), \ + 16 + ((((imm) >> 4) & 0x3) * 4), \ + 17 + ((((imm) >> 4) & 0x3) * 4), \ + 18 + ((((imm) >> 4) & 0x3) * 4), \ + 19 + ((((imm) >> 4) & 0x3) * 4), \ + 16 + ((((imm) >> 6) & 0x3) * 4), \ + 17 + ((((imm) >> 6) & 0x3) * 4), \ + 18 + ((((imm) >> 6) & 0x3) * 4), \ + 19 + ((((imm) >> 6) & 0x3) * 4)); }) #define _mm512_mask_shuffle_f32x4(W, U, A, B, imm) __extension__ ({ \ - (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(imm), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U)); }) + (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ + (__v16sf)(__m512)(W)); }) #define _mm512_maskz_shuffle_f32x4(U, A, B, imm) __extension__ ({ \ - (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(imm), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U)); }) + (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ + (__v16sf)_mm512_setzero_ps()); }) #define _mm512_shuffle_f64x2(A, B, imm) __extension__ ({ \ - (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(imm), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1); }) + (__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + 0 + ((((imm) >> 0) & 0x3) * 2), \ + 1 + ((((imm) >> 0) & 0x3) * 2), \ + 0 + ((((imm) >> 2) & 0x3) * 2), \ + 1 + ((((imm) >> 2) & 0x3) * 2), \ + 8 + ((((imm) >> 4) & 0x3) * 2), \ + 9 + ((((imm) >> 4) & 0x3) * 2), \ + 8 + ((((imm) >> 6) & 0x3) * 2), \ + 9 + ((((imm) >> 6) & 0x3) * 2)); }) #define _mm512_mask_shuffle_f64x2(W, U, A, B, imm) __extension__ ({ \ - (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(imm), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U)); }) + (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ + (__v8df)(__m512d)(W)); }) #define _mm512_maskz_shuffle_f64x2(U, A, B, imm) __extension__ ({ \ - (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(imm), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U)); }) + (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ + (__v8df)_mm512_setzero_pd()); }) #define _mm512_shuffle_i32x4(A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(imm), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)-1); }) + (__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), \ + 0 + ((((imm) >> 0) & 0x3) * 2), \ + 1 + ((((imm) >> 0) & 0x3) * 2), \ + 0 + ((((imm) >> 2) & 0x3) * 2), \ + 1 + ((((imm) >> 2) & 0x3) * 2), \ + 8 + ((((imm) >> 4) & 0x3) * 2), \ + 9 + ((((imm) >> 4) & 0x3) * 2), \ + 8 + ((((imm) >> 6) & 0x3) * 2), \ + 9 + ((((imm) >> 6) & 0x3) * 2)); }) #define _mm512_mask_shuffle_i32x4(W, U, A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(imm), \ - (__v16si)(__m512i)(W), \ - (__mmask16)(U)); }) + (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ + (__v16si)(__m512i)(W)); }) #define _mm512_maskz_shuffle_i32x4(U, A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(imm), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)(U)); }) + (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ + (__v16si)_mm512_setzero_si512()); }) #define _mm512_shuffle_i64x2(A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(imm), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1); }) + (__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), \ + 0 + ((((imm) >> 0) & 0x3) * 2), \ + 1 + ((((imm) >> 0) & 0x3) * 2), \ + 0 + ((((imm) >> 2) & 0x3) * 2), \ + 1 + ((((imm) >> 2) & 0x3) * 2), \ + 8 + ((((imm) >> 4) & 0x3) * 2), \ + 9 + ((((imm) >> 4) & 0x3) * 2), \ + 8 + ((((imm) >> 6) & 0x3) * 2), \ + 9 + ((((imm) >> 6) & 0x3) * 2)); }) #define _mm512_mask_shuffle_i64x2(W, U, A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(imm), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U)); }) + (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ + (__v8di)(__m512i)(W)); }) #define _mm512_maskz_shuffle_i64x2(U, A, B, imm) __extension__ ({ \ - (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(imm), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U)); }) + (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ + (__v8di)_mm512_setzero_si512()); }) #define _mm512_shuffle_pd(A, B, M) __extension__ ({ \ (__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \ @@ -9012,7 +8787,7 @@ _mm512_kortestz (__mmask16 __A, __mmask16 __B) static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm512_kunpackb (__mmask16 __A, __mmask16 __B) { - return (__mmask16) __builtin_ia32_kunpckhi ((__mmask16) __A, (__mmask16) __B); + return (__mmask16) (( __A & 0xFF) | ( __B << 8)); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS @@ -9035,7 +8810,7 @@ _mm512_stream_si512 (__m512i * __P, __m512i __A) } static __inline__ __m512i __DEFAULT_FN_ATTRS -_mm512_stream_load_si512 (void *__P) +_mm512_stream_load_si512 (void const *__P) { typedef __v8di __v8di_aligned __attribute__((aligned(64))); return (__m512i) __builtin_nontemporal_load((const __v8di_aligned *)__P); @@ -9167,6 +8942,64 @@ _mm512_maskz_compress_epi32 (__mmask16 __U, __m512i __A) (__mmask8)(M), \ _MM_FROUND_CUR_DIRECTION); }) +/* Bit Test */ + +static __inline __mmask16 __DEFAULT_FN_ATTRS +_mm512_test_epi32_mask (__m512i __A, __m512i __B) +{ + return _mm512_cmpneq_epi32_mask (_mm512_and_epi32(__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask16 __DEFAULT_FN_ATTRS +_mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) +{ + return _mm512_mask_cmpneq_epi32_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline __mmask8 __DEFAULT_FN_ATTRS +_mm512_test_epi64_mask (__m512i __A, __m512i __B) +{ + return _mm512_cmpneq_epi64_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask8 __DEFAULT_FN_ATTRS +_mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) +{ + return _mm512_mask_cmpneq_epi64_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask16 __DEFAULT_FN_ATTRS +_mm512_testn_epi32_mask (__m512i __A, __m512i __B) +{ + return _mm512_cmpeq_epi32_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask16 __DEFAULT_FN_ATTRS +_mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) +{ + return _mm512_mask_cmpeq_epi32_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask8 __DEFAULT_FN_ATTRS +_mm512_testn_epi64_mask (__m512i __A, __m512i __B) +{ + return _mm512_cmpeq_epi64_mask (_mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + +static __inline__ __mmask8 __DEFAULT_FN_ATTRS +_mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) +{ + return _mm512_mask_cmpeq_epi64_mask (__U, _mm512_and_epi32 (__A, __B), + _mm512_setzero_epi32()); +} + static __inline__ __m512 __DEFAULT_FN_ATTRS _mm512_movehdup_ps (__m512 __A) { @@ -9737,16 +9570,18 @@ _mm_cvtu64_ss (__m128 __A, unsigned long long __B) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_set1_epi32 (__m512i __O, __mmask16 __M, int __A) { - return (__m512i) __builtin_ia32_pbroadcastd512_gpr_mask (__A, (__v16si) __O, - __M); + return (__m512i) __builtin_ia32_selectd_512(__M, + (__v16si) _mm512_set1_epi32(__A), + (__v16si) __O); } #ifdef __x86_64__ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_mask_set1_epi64 (__m512i __O, __mmask8 __M, long long __A) { - return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A, (__v8di) __O, - __M); + return (__m512i) __builtin_ia32_selectq_512(__M, + (__v8di) _mm512_set1_epi64(__A), + (__v8di) __O); } #endif diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vlbwintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vlbwintrin.h index 3b58d043395a7..e940e2b68533d 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512vlbwintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512vlbwintrin.h @@ -38,581 +38,285 @@ _mm_setzero_hi(void){ /* Integer compare */ -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpeq_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_pcmpeqb128_mask((__v16qi)__a, (__v16qi)__b, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_pcmpeqb128_mask((__v16qi)__a, (__v16qi)__b, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpeq_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 0, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 0, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_pcmpeqb256_mask((__v32qi)__a, (__v32qi)__b, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_pcmpeqb256_mask((__v32qi)__a, (__v32qi)__b, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 0, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 0, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqw128_mask((__v8hi)__a, (__v8hi)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqw128_mask((__v8hi)__a, (__v8hi)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 0, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_pcmpeqw256_mask((__v16hi)__a, (__v16hi)__b, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_pcmpeqw256_mask((__v16hi)__a, (__v16hi)__b, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 0, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 0, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpge_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpge_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 5, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpge_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 5, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 5, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpge_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 5, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpge_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpge_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 5, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 5, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpgt_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_pcmpgtb128_mask((__v16qi)__a, (__v16qi)__b, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_pcmpgtb128_mask((__v16qi)__a, (__v16qi)__b, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpgt_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 6, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 6, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_pcmpgtb256_mask((__v32qi)__a, (__v32qi)__b, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_pcmpgtb256_mask((__v32qi)__a, (__v32qi)__b, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 6, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtw128_mask((__v8hi)__a, (__v8hi)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtw128_mask((__v8hi)__a, (__v8hi)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 6, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_pcmpgtw256_mask((__v16hi)__a, (__v16hi)__b, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_pcmpgtw256_mask((__v16hi)__a, (__v16hi)__b, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 6, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 6, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmple_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmple_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 2, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmple_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 2, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 2, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmple_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 2, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmple_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmple_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 2, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 2, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmplt_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 1, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 1, - __u); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmplt_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 1, - (__mmask16)-1); -} - -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 1, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmplt_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 1, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 1, - __u); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmplt_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 1, - (__mmask32)-1); -} - -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 1, - (__mmask8)-1); -} +#define _mm_cmp_epi8_mask(a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)-1); }) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 1, - __u); -} +#define _mm_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)(m)); }) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 1, - (__mmask8)-1); -} +#define _mm_cmp_epu8_mask(a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)-1); }) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 1, - __u); -} +#define _mm_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)(m)); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmplt_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 1, - (__mmask16)-1); -} +#define _mm256_cmp_epi8_mask(a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)-1); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 1, - __u); -} +#define _mm256_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)(m)); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmplt_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 1, - (__mmask16)-1); -} +#define _mm256_cmp_epu8_mask(a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)-1); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 1, - __u); -} +#define _mm256_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ + (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)(m)); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpneq_epi8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 4, - (__mmask16)-1); -} +#define _mm_cmp_epi16_mask(a, b, p) __extension__ ({ \ + (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)-1); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epi8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)__a, (__v16qi)__b, 4, - __u); -} +#define _mm_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ + (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)(m)); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_cmpneq_epu8_mask(__m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 4, - (__mmask16)-1); -} +#define _mm_cmp_epu16_mask(a, b, p) __extension__ ({ \ + (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)-1); }) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epu8_mask(__mmask16 __u, __m128i __a, __m128i __b) { - return (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)__a, (__v16qi)__b, 4, - __u); -} +#define _mm_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ + (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)(m)); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epi8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 4, - (__mmask32)-1); -} +#define _mm256_cmp_epi16_mask(a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)-1); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epi8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)__a, (__v32qi)__b, 4, - __u); -} +#define _mm256_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)(m)); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epu8_mask(__m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 4, - (__mmask32)-1); -} +#define _mm256_cmp_epu16_mask(a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)-1); }) -static __inline__ __mmask32 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epu8_mask(__mmask32 __u, __m256i __a, __m256i __b) { - return (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)__a, (__v32qi)__b, 4, - __u); -} +#define _mm256_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ + (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)(m)); }) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epi16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 4, - (__mmask8)-1); -} +#define _mm_cmpeq_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epi8_mask(A, B) \ + _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epi8_mask(k, A, B) \ + _mm_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epi16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)__a, (__v8hi)__b, 4, - __u); -} +#define _mm256_cmpeq_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epi8_mask(A, B) \ + _mm256_cmp_epi8_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epi8_mask(k, A, B) \ + _mm256_mask_cmp_epi8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epu16_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 4, - (__mmask8)-1); -} +#define _mm_cmpeq_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epu8_mask(A, B) \ + _mm_cmp_epu8_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epu8_mask(k, A, B) \ + _mm_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epu16_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)__a, (__v8hi)__b, 4, - __u); -} +#define _mm256_cmpeq_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epu8_mask(A, B) \ + _mm256_cmp_epu8_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epu8_mask(k, A, B) \ + _mm256_mask_cmp_epu8_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epi16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 4, - (__mmask16)-1); -} +#define _mm_cmpeq_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epi16_mask(A, B) \ + _mm_cmp_epi16_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epi16_mask(k, A, B) \ + _mm_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epi16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)__a, (__v16hi)__b, 4, - __u); -} +#define _mm256_cmpeq_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epi16_mask(A, B) \ + _mm256_cmp_epi16_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epi16_mask(k, A, B) \ + _mm256_mask_cmp_epi16_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epu16_mask(__m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 4, - (__mmask16)-1); -} +#define _mm_cmpeq_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epu16_mask(A, B) \ + _mm_cmp_epu16_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epu16_mask(k, A, B) \ + _mm_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask16 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epu16_mask(__mmask16 __u, __m256i __a, __m256i __b) { - return (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)__a, (__v16hi)__b, 4, - __u); -} +#define _mm256_cmpeq_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epu16_mask(A, B) \ + _mm256_cmp_epu16_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epu16_mask(k, A, B) \ + _mm256_mask_cmp_epu16_mask((k), (A), (B), _MM_CMPINT_NE) static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_add_epi8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B){ @@ -2146,86 +1850,6 @@ _mm256_maskz_cvtepu8_epi16 (__mmask16 __U, __m128i __A) } -#define _mm_cmp_epi8_mask(a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)-1); }) - -#define _mm_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)(m)); }) - -#define _mm_cmp_epu8_mask(a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)-1); }) - -#define _mm_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)(m)); }) - -#define _mm256_cmp_epi8_mask(a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)-1); }) - -#define _mm256_mask_cmp_epi8_mask(m, a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)(m)); }) - -#define _mm256_cmp_epu8_mask(a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)-1); }) - -#define _mm256_mask_cmp_epu8_mask(m, a, b, p) __extension__ ({ \ - (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)(m)); }) - -#define _mm_cmp_epi16_mask(a, b, p) __extension__ ({ \ - (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)-1); }) - -#define _mm_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ - (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)(m)); }) - -#define _mm_cmp_epu16_mask(a, b, p) __extension__ ({ \ - (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)-1); }) - -#define _mm_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ - (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)(m)); }) - -#define _mm256_cmp_epi16_mask(a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)-1); }) - -#define _mm256_mask_cmp_epi16_mask(m, a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)(m)); }) - -#define _mm256_cmp_epu16_mask(a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)-1); }) - -#define _mm256_mask_cmp_epu16_mask(m, a, b, p) __extension__ ({ \ - (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)(m)); }) - #define _mm_mask_shufflehi_epi16(W, U, A, imm) __extension__ ({ \ (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ (__v8hi)_mm_shufflehi_epi16((A), (imm)), \ @@ -2660,35 +2284,33 @@ _mm256_maskz_mov_epi8 (__mmask32 __U, __m256i __A) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mask_set1_epi8 (__m128i __O, __mmask16 __M, char __A) { - return (__m128i) __builtin_ia32_pbroadcastb128_gpr_mask (__A, - (__v16qi) __O, - __M); + return (__m128i) __builtin_ia32_selectb_128(__M, + (__v16qi) _mm_set1_epi8(__A), + (__v16qi) __O); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_maskz_set1_epi8 (__mmask16 __M, char __A) { - return (__m128i) __builtin_ia32_pbroadcastb128_gpr_mask (__A, - (__v16qi) - _mm_setzero_si128 (), - __M); + return (__m128i) __builtin_ia32_selectb_128(__M, + (__v16qi) _mm_set1_epi8(__A), + (__v16qi) _mm_setzero_si128()); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_set1_epi8 (__m256i __O, __mmask32 __M, char __A) { - return (__m256i) __builtin_ia32_pbroadcastb256_gpr_mask (__A, - (__v32qi) __O, - __M); + return (__m256i) __builtin_ia32_selectb_256(__M, + (__v32qi) _mm256_set1_epi8(__A), + (__v32qi) __O); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_maskz_set1_epi8 (__mmask32 __M, char __A) { - return (__m256i) __builtin_ia32_pbroadcastb256_gpr_mask (__A, - (__v32qi) - _mm256_setzero_si256 (), - __M); + return (__m256i) __builtin_ia32_selectb_256(__M, + (__v32qi) _mm256_set1_epi8(__A), + (__v32qi) _mm256_setzero_si256()); } static __inline__ __m128i __DEFAULT_FN_ATTRS @@ -2793,121 +2415,108 @@ _mm256_mask_storeu_epi8 (void *__P, __mmask32 __U, __m256i __A) static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm_test_epi8_mask (__m128i __A, __m128i __B) { - return (__mmask16) __builtin_ia32_ptestmb128 ((__v16qi) __A, - (__v16qi) __B, - (__mmask16) -1); + return _mm_cmpneq_epi8_mask (_mm_and_si128(__A, __B), _mm_setzero_hi()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm_mask_test_epi8_mask (__mmask16 __U, __m128i __A, __m128i __B) { - return (__mmask16) __builtin_ia32_ptestmb128 ((__v16qi) __A, - (__v16qi) __B, __U); + return _mm_mask_cmpneq_epi8_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_hi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm256_test_epi8_mask (__m256i __A, __m256i __B) { - return (__mmask32) __builtin_ia32_ptestmb256 ((__v32qi) __A, - (__v32qi) __B, - (__mmask32) -1); + return _mm256_cmpneq_epi8_mask (_mm256_and_si256(__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm256_mask_test_epi8_mask (__mmask32 __U, __m256i __A, __m256i __B) { - return (__mmask32) __builtin_ia32_ptestmb256 ((__v32qi) __A, - (__v32qi) __B, __U); + return _mm256_mask_cmpneq_epi8_mask (__U, _mm256_and_si256(__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_test_epi16_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmw128 ((__v8hi) __A, - (__v8hi) __B, - (__mmask8) -1); + return _mm_cmpneq_epi16_mask (_mm_and_si128 (__A, __B), _mm_setzero_hi()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_test_epi16_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmw128 ((__v8hi) __A, - (__v8hi) __B, __U); + return _mm_mask_cmpneq_epi16_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_hi()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm256_test_epi16_mask (__m256i __A, __m256i __B) { - return (__mmask16) __builtin_ia32_ptestmw256 ((__v16hi) __A, - (__v16hi) __B, - (__mmask16) -1); + return _mm256_cmpneq_epi16_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256 ()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm256_mask_test_epi16_mask (__mmask16 __U, __m256i __A, __m256i __B) { - return (__mmask16) __builtin_ia32_ptestmw256 ((__v16hi) __A, - (__v16hi) __B, __U); + return _mm256_mask_cmpneq_epi16_mask (__U, _mm256_and_si256(__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm_testn_epi8_mask (__m128i __A, __m128i __B) { - return (__mmask16) __builtin_ia32_ptestnmb128 ((__v16qi) __A, - (__v16qi) __B, - (__mmask16) -1); + return _mm_cmpeq_epi8_mask (_mm_and_si128 (__A, __B), _mm_setzero_hi()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm_mask_testn_epi8_mask (__mmask16 __U, __m128i __A, __m128i __B) { - return (__mmask16) __builtin_ia32_ptestnmb128 ((__v16qi) __A, - (__v16qi) __B, __U); + return _mm_mask_cmpeq_epi8_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_hi()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm256_testn_epi8_mask (__m256i __A, __m256i __B) { - return (__mmask32) __builtin_ia32_ptestnmb256 ((__v32qi) __A, - (__v32qi) __B, - (__mmask32) -1); + return _mm256_cmpeq_epi8_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask32 __DEFAULT_FN_ATTRS _mm256_mask_testn_epi8_mask (__mmask32 __U, __m256i __A, __m256i __B) { - return (__mmask32) __builtin_ia32_ptestnmb256 ((__v32qi) __A, - (__v32qi) __B, __U); + return _mm256_mask_cmpeq_epi8_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_testn_epi16_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmw128 ((__v8hi) __A, - (__v8hi) __B, - (__mmask8) -1); + return _mm_cmpeq_epi16_mask (_mm_and_si128 (__A, __B), _mm_setzero_hi()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_testn_epi16_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmw128 ((__v8hi) __A, - (__v8hi) __B, __U); + return _mm_mask_cmpeq_epi16_mask (__U, _mm_and_si128(__A, __B), _mm_setzero_hi()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm256_testn_epi16_mask (__m256i __A, __m256i __B) { - return (__mmask16) __builtin_ia32_ptestnmw256 ((__v16hi) __A, - (__v16hi) __B, - (__mmask16) -1); + return _mm256_cmpeq_epi16_mask (_mm256_and_si256(__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm256_mask_testn_epi16_mask (__mmask16 __U, __m256i __A, __m256i __B) { - return (__mmask16) __builtin_ia32_ptestnmw256 ((__v16hi) __A, - (__v16hi) __B, __U); + return _mm256_mask_cmpeq_epi16_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask16 __DEFAULT_FN_ATTRS @@ -3025,33 +2634,33 @@ _mm256_maskz_broadcastw_epi16 (__mmask16 __M, __m128i __A) static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_set1_epi16 (__m256i __O, __mmask16 __M, short __A) { - return (__m256i) __builtin_ia32_pbroadcastw256_gpr_mask (__A, - (__v16hi) __O, - __M); + return (__m256i) __builtin_ia32_selectw_256 (__M, + (__v16hi) _mm256_set1_epi16(__A), + (__v16hi) __O); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_maskz_set1_epi16 (__mmask16 __M, short __A) { - return (__m256i) __builtin_ia32_pbroadcastw256_gpr_mask (__A, - (__v16hi) _mm256_setzero_si256 (), - __M); + return (__m256i) __builtin_ia32_selectw_256(__M, + (__v16hi)_mm256_set1_epi16(__A), + (__v16hi) _mm256_setzero_si256()); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mask_set1_epi16 (__m128i __O, __mmask8 __M, short __A) { - return (__m128i) __builtin_ia32_pbroadcastw128_gpr_mask (__A, - (__v8hi) __O, - __M); + return (__m128i) __builtin_ia32_selectw_128(__M, + (__v8hi) _mm_set1_epi16(__A), + (__v8hi) __O); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_maskz_set1_epi16 (__mmask8 __M, short __A) { - return (__m128i) __builtin_ia32_pbroadcastw128_gpr_mask (__A, - (__v8hi) _mm_setzero_si128 (), - __M); + return (__m128i) __builtin_ia32_selectw_128(__M, + (__v8hi) _mm_set1_epi16(__A), + (__v8hi) _mm_setzero_si128()); } static __inline__ __m128i __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vlcdintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vlcdintrin.h index 7b02e2e1f92a2..8f1cd25f0b50c 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512vlcdintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512vlcdintrin.h @@ -33,26 +33,26 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_broadcastmb_epi64 (__mmask8 __A) -{ - return (__m128i) __builtin_ia32_broadcastmb128 (__A); +{ + return (__m128i) _mm_set1_epi64x((long long) __A); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_broadcastmb_epi64 (__mmask8 __A) { - return (__m256i) __builtin_ia32_broadcastmb256 (__A); + return (__m256i) _mm256_set1_epi64x((long long)__A); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_broadcastmw_epi32 (__mmask16 __A) { - return (__m128i) __builtin_ia32_broadcastmw128 (__A); + return (__m128i) _mm_set1_epi32((int)__A); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_broadcastmw_epi32 (__mmask16 __A) { - return (__m256i) __builtin_ia32_broadcastmw256 (__A); + return (__m256i) _mm256_set1_epi32((int)__A); } diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h index aecd7df34d050..d80df9eaffea9 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h @@ -978,25 +978,25 @@ _mm256_movepi64_mask (__m256i __A) static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_broadcast_f32x2 (__m128 __A) { - return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A, - (__v8sf)_mm256_undefined_ps(), - (__mmask8) -1); + return (__m256)__builtin_shufflevector((__v4sf)__A, + (__v4sf)_mm_undefined_ps(), + 0, 1, 0, 1, 0, 1, 0, 1); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_mask_broadcast_f32x2 (__m256 __O, __mmask8 __M, __m128 __A) { - return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A, - (__v8sf) __O, - __M); + return (__m256)__builtin_ia32_selectps_256((__mmask8)__M, + (__v8sf)_mm256_broadcast_f32x2(__A), + (__v8sf)__O); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_maskz_broadcast_f32x2 (__mmask8 __M, __m128 __A) { - return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A, - (__v8sf) _mm256_setzero_ps (), - __M); + return (__m256)__builtin_ia32_selectps_256((__mmask8)__M, + (__v8sf)_mm256_broadcast_f32x2(__A), + (__v8sf)_mm256_setzero_ps()); } static __inline__ __m256d __DEFAULT_FN_ATTRS @@ -1025,49 +1025,49 @@ _mm256_maskz_broadcast_f64x2 (__mmask8 __M, __m128d __A) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_broadcast_i32x2 (__m128i __A) { - return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A, - (__v4si)_mm_undefined_si128(), - (__mmask8) -1); + return (__m128i)__builtin_shufflevector((__v4si)__A, + (__v4si)_mm_undefined_si128(), + 0, 1, 0, 1); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mask_broadcast_i32x2 (__m128i __O, __mmask8 __M, __m128i __A) { - return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A, - (__v4si) __O, - __M); + return (__m128i)__builtin_ia32_selectd_128((__mmask8)__M, + (__v4si)_mm_broadcast_i32x2(__A), + (__v4si)__O); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_maskz_broadcast_i32x2 (__mmask8 __M, __m128i __A) { - return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A, - (__v4si) _mm_setzero_si128 (), - __M); + return (__m128i)__builtin_ia32_selectd_128((__mmask8)__M, + (__v4si)_mm_broadcast_i32x2(__A), + (__v4si)_mm_setzero_si128()); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_broadcast_i32x2 (__m128i __A) { - return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A, - (__v8si)_mm256_undefined_si256(), - (__mmask8) -1); + return (__m256i)__builtin_shufflevector((__v4si)__A, + (__v4si)_mm_undefined_si128(), + 0, 1, 0, 1, 0, 1, 0, 1); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_broadcast_i32x2 (__m256i __O, __mmask8 __M, __m128i __A) { - return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A, - (__v8si) __O, - __M); + return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M, + (__v8si)_mm256_broadcast_i32x2(__A), + (__v8si)__O); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_maskz_broadcast_i32x2 (__mmask8 __M, __m128i __A) { - return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A, - (__v8si) _mm256_setzero_si256 (), - __M); + return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M, + (__v8si)_mm256_broadcast_i32x2(__A), + (__v8si)_mm256_setzero_si256()); } static __inline__ __m256i __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h index 99bb050de4d71..fb8056e3f8d83 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h @@ -38,582 +38,205 @@ _mm_setzero_di(void) { /* Integer compare */ -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqd128_mask((__v4si)__a, (__v4si)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqd128_mask((__v4si)__a, (__v4si)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 0, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpeqd256_mask((__v8si)__a, (__v8si)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpeqd256_mask((__v8si)__a, (__v8si)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 0, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq128_mask((__v2di)__a, (__v2di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq128_mask((__v2di)__a, (__v2di)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpeq_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpeq_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 0, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq256_mask((__v4di)__a, (__v4di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpeqq256_mask((__v4di)__a, (__v4di)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpeq_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 0, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpeq_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 0, - __u); -} - - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpge_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpge_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpge_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpge_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpge_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpge_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 5, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpge_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 5, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtd128_mask((__v4si)__a, (__v4si)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtd128_mask((__v4si)__a, (__v4si)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpgtd256_mask((__v8si)__a, (__v8si)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpgtd256_mask((__v8si)__a, (__v8si)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq128_mask((__v2di)__a, (__v2di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq128_mask((__v2di)__a, (__v2di)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpgt_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpgt_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq256_mask((__v4di)__a, (__v4di)__b, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_pcmpgtq256_mask((__v4di)__a, (__v4di)__b, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpgt_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 6, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpgt_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 6, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmple_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmple_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmple_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmple_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmple_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmple_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 2, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmple_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 2, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmplt_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmplt_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 1, - (__mmask8)-1); -} +#define _mm_cmpeq_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epi32_mask(A, B) \ + _mm_cmp_epi32_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epi32_mask(k, A, B) \ + _mm_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmplt_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmplt_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmplt_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmplt_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 1, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmplt_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 1, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epi32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)__a, (__v4si)__b, 4, - __u); -} +#define _mm256_cmpeq_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epi32_mask(A, B) \ + _mm256_cmp_epi32_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epi32_mask(k, A, B) \ + _mm256_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epu32_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epu32_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)__a, (__v4si)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epi32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 4, - (__mmask8)-1); -} +#define _mm_cmpeq_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epu32_mask(A, B) \ + _mm_cmp_epu32_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epu32_mask(k, A, B) \ + _mm_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)__a, (__v8si)__b, 4, - __u); -} +#define _mm256_cmpeq_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epu32_mask(A, B) \ + _mm256_cmp_epu32_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epu32_mask(k, A, B) \ + _mm256_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epu32_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 4, - (__mmask8)-1); -} +#define _mm_cmpeq_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epi64_mask(A, B) \ + _mm_cmp_epi64_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epi64_mask(k, A, B) \ + _mm_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epu32_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)__a, (__v8si)__b, 4, - __u); -} +#define _mm256_cmpeq_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epi64_mask(A, B) \ + _mm256_cmp_epi64_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epi64_mask(k, A, B) \ + _mm256_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epi64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 4, - (__mmask8)-1); -} +#define _mm_cmpeq_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm_mask_cmpeq_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm_cmpge_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_GE) +#define _mm_mask_cmpge_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm_cmpgt_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_GT) +#define _mm_mask_cmpgt_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm_cmple_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_LE) +#define _mm_mask_cmple_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm_cmplt_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_LT) +#define _mm_mask_cmplt_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm_cmpneq_epu64_mask(A, B) \ + _mm_cmp_epu64_mask((A), (B), _MM_CMPINT_NE) +#define _mm_mask_cmpneq_epu64_mask(k, A, B) \ + _mm_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_NE) -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)__a, (__v2di)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_cmpneq_epu64_mask(__m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm_mask_cmpneq_epu64_mask(__mmask8 __u, __m128i __a, __m128i __b) { - return (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)__a, (__v2di)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epi64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)__a, (__v4di)__b, 4, - __u); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_cmpneq_epu64_mask(__m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 4, - (__mmask8)-1); -} - -static __inline__ __mmask8 __DEFAULT_FN_ATTRS -_mm256_mask_cmpneq_epu64_mask(__mmask8 __u, __m256i __a, __m256i __b) { - return (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)__a, (__v4di)__b, 4, - __u); -} +#define _mm256_cmpeq_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_EQ) +#define _mm256_mask_cmpeq_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_EQ) +#define _mm256_cmpge_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_GE) +#define _mm256_mask_cmpge_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GE) +#define _mm256_cmpgt_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_GT) +#define _mm256_mask_cmpgt_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GT) +#define _mm256_cmple_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_LE) +#define _mm256_mask_cmple_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LE) +#define _mm256_cmplt_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_LT) +#define _mm256_mask_cmplt_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LT) +#define _mm256_cmpneq_epu64_mask(A, B) \ + _mm256_cmp_epu64_mask((A), (B), _MM_CMPINT_NE) +#define _mm256_mask_cmpneq_epu64_mask(k, A, B) \ + _mm256_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_NE) static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_add_epi32(__m256i __W, __mmask8 __U, __m256i __A, __m256i __B) @@ -5723,59 +5346,72 @@ _mm256_maskz_movedup_pd (__mmask8 __U, __m256d __A) (__v4df)_mm256_setzero_pd()); } +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_set1_epi32(__m128i __O, __mmask8 __M, int __A) +{ + return (__m128i)__builtin_ia32_selectd_128(__M, + (__v4si) _mm_set1_epi32(__A), + (__v4si)__O); +} -#define _mm_mask_set1_epi32(O, M, A) __extension__ ({ \ - (__m128i)__builtin_ia32_pbroadcastd128_gpr_mask((int)(A), \ - (__v4si)(__m128i)(O), \ - (__mmask8)(M)); }) +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_set1_epi32( __mmask8 __M, int __A) +{ + return (__m128i)__builtin_ia32_selectd_128(__M, + (__v4si) _mm_set1_epi32(__A), + (__v4si)_mm_setzero_si128()); +} -#define _mm_maskz_set1_epi32(M, A) __extension__ ({ \ - (__m128i)__builtin_ia32_pbroadcastd128_gpr_mask((int)(A), \ - (__v4si)_mm_setzero_si128(), \ - (__mmask8)(M)); }) +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_set1_epi32(__m256i __O, __mmask8 __M, int __A) +{ + return (__m256i)__builtin_ia32_selectd_256(__M, + (__v8si) _mm256_set1_epi32(__A), + (__v8si)__O); +} -#define _mm256_mask_set1_epi32(O, M, A) __extension__ ({ \ - (__m256i)__builtin_ia32_pbroadcastd256_gpr_mask((int)(A), \ - (__v8si)(__m256i)(O), \ - (__mmask8)(M)); }) +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_set1_epi32( __mmask8 __M, int __A) +{ + return (__m256i)__builtin_ia32_selectd_256(__M, + (__v8si) _mm256_set1_epi32(__A), + (__v8si)_mm256_setzero_si256()); +} -#define _mm256_maskz_set1_epi32(M, A) __extension__ ({ \ - (__m256i)__builtin_ia32_pbroadcastd256_gpr_mask((int)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(M)); }) #ifdef __x86_64__ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mask_set1_epi64 (__m128i __O, __mmask8 __M, long long __A) { - return (__m128i) __builtin_ia32_pbroadcastq128_gpr_mask (__A, (__v2di) __O, - __M); + return (__m128i) __builtin_ia32_selectq_128(__M, + (__v2di) _mm_set1_epi64x(__A), + (__v2di) __O); } static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_maskz_set1_epi64 (__mmask8 __M, long long __A) { - return (__m128i) __builtin_ia32_pbroadcastq128_gpr_mask (__A, - (__v2di) - _mm_setzero_si128 (), - __M); + return (__m128i) __builtin_ia32_selectq_128(__M, + (__v2di) _mm_set1_epi64x(__A), + (__v2di) _mm_setzero_si128()); } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_mask_set1_epi64 (__m256i __O, __mmask8 __M, long long __A) { - return (__m256i) __builtin_ia32_pbroadcastq256_gpr_mask (__A, (__v4di) __O, - __M); + return (__m256i) __builtin_ia32_selectq_256(__M, + (__v4di) _mm256_set1_epi64x(__A), + (__v4di) __O) ; } static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_maskz_set1_epi64 (__mmask8 __M, long long __A) { - return (__m256i) __builtin_ia32_pbroadcastq256_gpr_mask (__A, - (__v4di) - _mm256_setzero_si256 (), - __M); + return (__m256i) __builtin_ia32_selectq_256(__M, + (__v4di) _mm256_set1_epi64x(__A), + (__v4di) _mm256_setzero_si256()); } + #endif #define _mm_fixupimm_pd(A, B, C, imm) __extension__ ({ \ @@ -6490,125 +6126,111 @@ _mm256_maskz_permutevar_ps(__mmask8 __U, __m256 __A, __m256i __C) static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_test_epi32_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmd128 ((__v4si) __A, - (__v4si) __B, - (__mmask8) -1); + return _mm_cmpneq_epi32_mask (_mm_and_si128 (__A, __B), _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_test_epi32_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmd128 ((__v4si) __A, - (__v4si) __B, __U); + return _mm_mask_cmpneq_epi32_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_test_epi32_mask (__m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestmd256 ((__v8si) __A, - (__v8si) __B, - (__mmask8) -1); + return _mm256_cmpneq_epi32_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_mask_test_epi32_mask (__mmask8 __U, __m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestmd256 ((__v8si) __A, - (__v8si) __B, __U); + return _mm256_mask_cmpneq_epi32_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_test_epi64_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmq128 ((__v2di) __A, - (__v2di) __B, - (__mmask8) -1); + return _mm_cmpneq_epi64_mask (_mm_and_si128 (__A, __B), _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_test_epi64_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestmq128 ((__v2di) __A, - (__v2di) __B, __U); + return _mm_mask_cmpneq_epi64_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_test_epi64_mask (__m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestmq256 ((__v4di) __A, - (__v4di) __B, - (__mmask8) -1); + return _mm256_cmpneq_epi64_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_mask_test_epi64_mask (__mmask8 __U, __m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestmq256 ((__v4di) __A, - (__v4di) __B, __U); + return _mm256_mask_cmpneq_epi64_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_testn_epi32_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmd128 ((__v4si) __A, - (__v4si) __B, - (__mmask8) -1); + return _mm_cmpeq_epi32_mask (_mm_and_si128 (__A, __B), _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_testn_epi32_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmd128 ((__v4si) __A, - (__v4si) __B, __U); + return _mm_mask_cmpeq_epi32_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_testn_epi32_mask (__m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestnmd256 ((__v8si) __A, - (__v8si) __B, - (__mmask8) -1); + return _mm256_cmpeq_epi32_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_mask_testn_epi32_mask (__mmask8 __U, __m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestnmd256 ((__v8si) __A, - (__v8si) __B, __U); + return _mm256_mask_cmpeq_epi32_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_testn_epi64_mask (__m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmq128 ((__v2di) __A, - (__v2di) __B, - (__mmask8) -1); + return _mm_cmpeq_epi64_mask (_mm_and_si128 (__A, __B), _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm_mask_testn_epi64_mask (__mmask8 __U, __m128i __A, __m128i __B) { - return (__mmask8) __builtin_ia32_ptestnmq128 ((__v2di) __A, - (__v2di) __B, __U); + return _mm_mask_cmpeq_epi64_mask (__U, _mm_and_si128 (__A, __B), + _mm_setzero_di()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_testn_epi64_mask (__m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestnmq256 ((__v4di) __A, - (__v4di) __B, - (__mmask8) -1); + return _mm256_cmpeq_epi64_mask (_mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } static __inline__ __mmask8 __DEFAULT_FN_ATTRS _mm256_mask_testn_epi64_mask (__mmask8 __U, __m256i __A, __m256i __B) { - return (__mmask8) __builtin_ia32_ptestnmq256 ((__v4di) __A, - (__v4di) __B, __U); + return _mm256_mask_cmpeq_epi64_mask (__U, _mm256_and_si256 (__A, __B), + _mm256_setzero_si256()); } - - static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_mask_unpackhi_epi32(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) { @@ -6964,85 +6586,81 @@ _mm256_maskz_srai_epi64(__mmask8 __U, __m256i __A, int __imm) #define _mm256_shuffle_f32x4(A, B, imm) __extension__ ({ \ - (__m256)__builtin_ia32_shuf_f32x4_256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(imm), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1); }) + (__m256)__builtin_shufflevector((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), \ + 0 + ((((imm) >> 0) & 0x1) * 4), \ + 1 + ((((imm) >> 0) & 0x1) * 4), \ + 2 + ((((imm) >> 0) & 0x1) * 4), \ + 3 + ((((imm) >> 0) & 0x1) * 4), \ + 8 + ((((imm) >> 1) & 0x1) * 4), \ + 9 + ((((imm) >> 1) & 0x1) * 4), \ + 10 + ((((imm) >> 1) & 0x1) * 4), \ + 11 + ((((imm) >> 1) & 0x1) * 4)); }) #define _mm256_mask_shuffle_f32x4(W, U, A, B, imm) __extension__ ({ \ - (__m256)__builtin_ia32_shuf_f32x4_256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(imm), \ - (__v8sf)(__m256)(W), \ - (__mmask8)(U)); }) + (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ + (__v8sf)(__m256)(W)); }) #define _mm256_maskz_shuffle_f32x4(U, A, B, imm) __extension__ ({ \ - (__m256)__builtin_ia32_shuf_f32x4_256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(imm), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)); }) + (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ + (__v8sf)_mm256_setzero_ps()); }) #define _mm256_shuffle_f64x2(A, B, imm) __extension__ ({ \ - (__m256d)__builtin_ia32_shuf_f64x2_256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (int)(imm), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)-1); }) + (__m256d)__builtin_shufflevector((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), \ + 0 + ((((imm) >> 0) & 0x1) * 2), \ + 1 + ((((imm) >> 0) & 0x1) * 2), \ + 4 + ((((imm) >> 1) & 0x1) * 2), \ + 5 + ((((imm) >> 1) & 0x1) * 2)); }) #define _mm256_mask_shuffle_f64x2(W, U, A, B, imm) __extension__ ({ \ - (__m256d)__builtin_ia32_shuf_f64x2_256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (int)(imm), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)); }) + (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ + (__v4df)(__m256)(W)); }) #define _mm256_maskz_shuffle_f64x2(U, A, B, imm) __extension__ ({ \ - (__m256d)__builtin_ia32_shuf_f64x2_256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (int)(imm), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)); }) + (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ + (__v4df)_mm256_setzero_pd()); }) #define _mm256_shuffle_i32x4(A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i32x4_256_mask((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), \ - (int)(imm), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)-1); }) + (__m256i)__builtin_shufflevector((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), \ + 0 + ((((imm) >> 0) & 0x1) * 2), \ + 1 + ((((imm) >> 0) & 0x1) * 2), \ + 4 + ((((imm) >> 1) & 0x1) * 2), \ + 5 + ((((imm) >> 1) & 0x1) * 2)); }) #define _mm256_mask_shuffle_i32x4(W, U, A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i32x4_256_mask((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), \ - (int)(imm), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U)); }) + (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ + (__v8si)(__m256)(W)); }) #define _mm256_maskz_shuffle_i32x4(U, A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i32x4_256_mask((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), \ - (int)(imm), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U)); }) + (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ + (__v8si)_mm256_setzero_si256()); }) #define _mm256_shuffle_i64x2(A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i64x2_256_mask((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (int)(imm), \ - (__v4di)_mm256_setzero_si256(), \ - (__mmask8)-1); }) + (__m256i)__builtin_shufflevector((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), \ + 0 + ((((imm) >> 0) & 0x1) * 2), \ + 1 + ((((imm) >> 0) & 0x1) * 2), \ + 4 + ((((imm) >> 1) & 0x1) * 2), \ + 5 + ((((imm) >> 1) & 0x1) * 2)); }) #define _mm256_mask_shuffle_i64x2(W, U, A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i64x2_256_mask((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (int)(imm), \ - (__v4di)(__m256i)(W), \ - (__mmask8)(U)); }) + (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ + (__v4di)(__m256)(W)); }) + #define _mm256_maskz_shuffle_i64x2(U, A, B, imm) __extension__ ({ \ - (__m256i)__builtin_ia32_shuf_i64x2_256_mask((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (int)(imm), \ - (__v4di)_mm256_setzero_si256(), \ - (__mmask8)(U)); }) + (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ + (__v4di)_mm256_setzero_si256()); }) #define _mm_mask_shuffle_pd(W, U, A, B, M) __extension__ ({ \ (__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqvlintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqvlintrin.h new file mode 100644 index 0000000000000..c2058a8f51543 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqvlintrin.h @@ -0,0 +1,99 @@ +/*===------------- avx512vpopcntdqintrin.h - AVX512VPOPCNTDQ intrinsics + *------------------=== + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ +#ifndef __IMMINTRIN_H +#error \ + "Never use <avx512vpopcntdqvlintrin.h> directly; include <immintrin.h> instead." +#endif + +#ifndef __AVX512VPOPCNTDQVLINTRIN_H +#define __AVX512VPOPCNTDQVLINTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("avx512vpopcntdq,avx512vl"))) + +static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_popcnt_epi64(__m128i __A) { + return (__m128i)__builtin_ia32_vpopcntq_128((__v2di)__A); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_popcnt_epi64(__m128i __W, __mmask8 __U, __m128i __A) { + return (__m128i)__builtin_ia32_selectq_128( + (__mmask8)__U, (__v2di)_mm_popcnt_epi64(__A), (__v2di)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_popcnt_epi64(__mmask8 __U, __m128i __A) { + return _mm_mask_popcnt_epi64((__m128i)_mm_setzero_si128(), __U, __A); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_popcnt_epi32(__m128i __A) { + return (__m128i)__builtin_ia32_vpopcntd_128((__v4si)__A); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_mask_popcnt_epi32(__m128i __W, __mmask8 __U, __m128i __A) { + return (__m128i)__builtin_ia32_selectd_128( + (__mmask8)__U, (__v4si)_mm_popcnt_epi32(__A), (__v4si)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS +_mm_maskz_popcnt_epi32(__mmask8 __U, __m128i __A) { + return _mm_mask_popcnt_epi32((__m128i)_mm_setzero_si128(), __U, __A); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_popcnt_epi64(__m256i __A) { + return (__m256i)__builtin_ia32_vpopcntq_256((__v4di)__A); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_popcnt_epi64(__m256i __W, __mmask8 __U, __m256i __A) { + return (__m256i)__builtin_ia32_selectq_256( + (__mmask8)__U, (__v4di)_mm256_popcnt_epi64(__A), (__v4di)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_popcnt_epi64(__mmask8 __U, __m256i __A) { + return _mm256_mask_popcnt_epi64((__m256i)_mm256_setzero_si256(), __U, __A); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS _mm256_popcnt_epi32(__m256i __A) { + return (__m256i)__builtin_ia32_vpopcntd_256((__v8si)__A); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_mask_popcnt_epi32(__m256i __W, __mmask8 __U, __m256i __A) { + return (__m256i)__builtin_ia32_selectd_256( + (__mmask8)__U, (__v8si)_mm256_popcnt_epi32(__A), (__v8si)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS +_mm256_maskz_popcnt_epi32(__mmask8 __U, __m256i __A) { + return _mm256_mask_popcnt_epi32((__m256i)_mm256_setzero_si256(), __U, __A); +} + +#undef __DEFAULT_FN_ATTRS + +#endif diff --git a/contrib/llvm/tools/clang/lib/Headers/cetintrin.h b/contrib/llvm/tools/clang/lib/Headers/cetintrin.h new file mode 100644 index 0000000000000..1256a3f63a162 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/cetintrin.h @@ -0,0 +1,93 @@ +/*===---- cetintrin.h - CET intrinsic ------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use <cetintrin.h> directly; include <immintrin.h> instead." +#endif + +#ifndef __CETINTRIN_H +#define __CETINTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("shstk"))) + +static __inline__ void __DEFAULT_FN_ATTRS _incsspd(int __a) { + __builtin_ia32_incsspd(__a); +} + +#ifdef __x86_64__ +static __inline__ void __DEFAULT_FN_ATTRS _incsspq(unsigned long long __a) { + __builtin_ia32_incsspq(__a); +} +#endif /* __x86_64__ */ + +static __inline__ unsigned int __DEFAULT_FN_ATTRS _rdsspd(unsigned int __a) { + return __builtin_ia32_rdsspd(__a); +} + +#ifdef __x86_64__ +static __inline__ unsigned long long __DEFAULT_FN_ATTRS _rdsspq(unsigned long long __a) { + return __builtin_ia32_rdsspq(__a); +} +#endif /* __x86_64__ */ + +static __inline__ void __DEFAULT_FN_ATTRS _saveprevssp() { + __builtin_ia32_saveprevssp(); +} + +static __inline__ void __DEFAULT_FN_ATTRS _rstorssp(void * __p) { + __builtin_ia32_rstorssp(__p); +} + +static __inline__ void __DEFAULT_FN_ATTRS _wrssd(unsigned int __a, void * __p) { + __builtin_ia32_wrssd(__a, __p); +} + +#ifdef __x86_64__ +static __inline__ void __DEFAULT_FN_ATTRS _wrssq(unsigned long long __a, void * __p) { + __builtin_ia32_wrssq(__a, __p); +} +#endif /* __x86_64__ */ + +static __inline__ void __DEFAULT_FN_ATTRS _wrussd(unsigned int __a, void * __p) { + __builtin_ia32_wrussd(__a, __p); +} + +#ifdef __x86_64__ +static __inline__ void __DEFAULT_FN_ATTRS _wrussq(unsigned long long __a, void * __p) { + __builtin_ia32_wrussq(__a, __p); +} +#endif /* __x86_64__ */ + +static __inline__ void __DEFAULT_FN_ATTRS _setssbsy() { + __builtin_ia32_setssbsy(); +} + +static __inline__ void __DEFAULT_FN_ATTRS _clrssbsy(void * __p) { + __builtin_ia32_clrssbsy(__p); +} + +#undef __DEFAULT_FN_ATTRS + +#endif /* __CETINTRIN_H */ diff --git a/contrib/llvm/tools/clang/lib/Headers/clflushoptintrin.h b/contrib/llvm/tools/clang/lib/Headers/clflushoptintrin.h index 60e0ead762754..f1f133023441a 100644 --- a/contrib/llvm/tools/clang/lib/Headers/clflushoptintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/clflushoptintrin.h @@ -32,7 +32,7 @@ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("clflushopt"))) static __inline__ void __DEFAULT_FN_ATTRS -_mm_clflushopt(char * __m) { +_mm_clflushopt(void const * __m) { __builtin_ia32_clflushopt(__m); } diff --git a/contrib/llvm/tools/clang/lib/Headers/clwbintrin.h b/contrib/llvm/tools/clang/lib/Headers/clwbintrin.h new file mode 100644 index 0000000000000..2594a6c387561 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/clwbintrin.h @@ -0,0 +1,52 @@ +/*===---- clwbintrin.h - CLWB intrinsic ------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use <clwbintrin.h> directly; include <immintrin.h> instead." +#endif + +#ifndef __CLWBINTRIN_H +#define __CLWBINTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("clwb"))) + +/// \brief Writes back to memory the cache line (if modified) that contains the +/// linear address specified in \a __p from any level of the cache hierarchy in +/// the cache coherence domain +/// +/// \headerfile <immintrin.h> +/// +/// This intrinsic corresponds to the <c> CLWB </c> instruction. +/// +/// \param __p +/// A pointer to the memory location used to identify the cache line to be +/// written back. +static __inline__ void __DEFAULT_FN_ATTRS +_mm_clwb(void const *__p) { + __builtin_ia32_clwb(__p); +} + +#undef __DEFAULT_FN_ATTRS + +#endif diff --git a/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/algorithm b/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/algorithm index 95d9beb73c682..cedd70762c486 100644 --- a/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/algorithm +++ b/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/algorithm @@ -80,7 +80,7 @@ min(const __T &__a, const __T &__b, __Cmp __cmp) { template <class __T> inline __device__ const __T & min(const __T &__a, const __T &__b) { - return __a < __b ? __b : __a; + return __a < __b ? __a : __b; } #ifdef _LIBCPP_END_NAMESPACE_STD diff --git a/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/new b/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/new index b77131af0e5b7..71b7a52363ce6 100644 --- a/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/new +++ b/contrib/llvm/tools/clang/lib/Headers/cuda_wrappers/new @@ -26,7 +26,6 @@ #include_next <new> -// Device overrides for placement new and delete. #pragma push_macro("CUDA_NOEXCEPT") #if __cplusplus >= 201103L #define CUDA_NOEXCEPT noexcept @@ -34,6 +33,55 @@ #define CUDA_NOEXCEPT #endif +// Device overrides for non-placement new and delete. +__device__ inline void *operator new(__SIZE_TYPE__ size) { + if (size == 0) { + size = 1; + } + return ::malloc(size); +} +__device__ inline void *operator new(__SIZE_TYPE__ size, + const std::nothrow_t &) CUDA_NOEXCEPT { + return ::operator new(size); +} + +__device__ inline void *operator new[](__SIZE_TYPE__ size) { + return ::operator new(size); +} +__device__ inline void *operator new[](__SIZE_TYPE__ size, + const std::nothrow_t &) { + return ::operator new(size); +} + +__device__ inline void operator delete(void* ptr) CUDA_NOEXCEPT { + if (ptr) { + ::free(ptr); + } +} +__device__ inline void operator delete(void *ptr, + const std::nothrow_t &) CUDA_NOEXCEPT { + ::operator delete(ptr); +} + +__device__ inline void operator delete[](void* ptr) CUDA_NOEXCEPT { + ::operator delete(ptr); +} +__device__ inline void operator delete[](void *ptr, + const std::nothrow_t &) CUDA_NOEXCEPT { + ::operator delete(ptr); +} + +// Sized delete, C++14 only. +#if __cplusplus >= 201402L +__device__ void operator delete(void *ptr, __SIZE_TYPE__ size) CUDA_NOEXCEPT { + ::operator delete(ptr); +} +__device__ void operator delete[](void *ptr, __SIZE_TYPE__ size) CUDA_NOEXCEPT { + ::operator delete(ptr); +} +#endif + +// Device overrides for placement new and delete. __device__ inline void *operator new(__SIZE_TYPE__, void *__ptr) CUDA_NOEXCEPT { return __ptr; } @@ -42,6 +90,7 @@ __device__ inline void *operator new[](__SIZE_TYPE__, void *__ptr) CUDA_NOEXCEPT } __device__ inline void operator delete(void *, void *) CUDA_NOEXCEPT {} __device__ inline void operator delete[](void *, void *) CUDA_NOEXCEPT {} + #pragma pop_macro("CUDA_NOEXCEPT") #endif // include guard diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h index 709815cbb4c2d..3372508a7f818 100644 --- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h @@ -2258,7 +2258,11 @@ _mm_adds_epu16(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_avg_epu8(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b); + typedef unsigned short __v16hu __attribute__ ((__vector_size__ (32))); + return (__m128i)__builtin_convertvector( + ((__builtin_convertvector((__v16qu)__a, __v16hu) + + __builtin_convertvector((__v16qu)__b, __v16hu)) + 1) + >> 1, __v16qu); } /// \brief Computes the rounded avarages of corresponding elements of two @@ -2278,7 +2282,11 @@ _mm_avg_epu8(__m128i __a, __m128i __b) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_avg_epu16(__m128i __a, __m128i __b) { - return (__m128i)__builtin_ia32_pavgw128((__v8hi)__a, (__v8hi)__b); + typedef unsigned int __v8su __attribute__ ((__vector_size__ (32))); + return (__m128i)__builtin_convertvector( + ((__builtin_convertvector((__v8hu)__a, __v8su) + + __builtin_convertvector((__v8hu)__b, __v8su)) + 1) + >> 1, __v8hu); } /// \brief Multiplies the corresponding elements of two 128-bit signed [8 x i16] diff --git a/contrib/llvm/tools/clang/lib/Headers/float.h b/contrib/llvm/tools/clang/lib/Headers/float.h index 502143d4e4813..44d4d05494f5d 100644 --- a/contrib/llvm/tools/clang/lib/Headers/float.h +++ b/contrib/llvm/tools/clang/lib/Headers/float.h @@ -143,4 +143,18 @@ # define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__ #endif +#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define FLT16_MANT_DIG __FLT16_MANT_DIG__ +# define FLT16_DECIMAL_DIG __FLT16_DECIMAL_DIG__ +# define FLT16_DIG __FLT16_DIG__ +# define FLT16_MIN_EXP __FLT16_MIN_EXP__ +# define FLT16_MIN_10_EXP __FLT16_MIN_10_EXP__ +# define FLT16_MAX_EXP __FLT16_MAX_EXP__ +# define FLT16_MAX_10_EXP __FLT16_MAX_10_EXP__ +# define FLT16_MAX __FLT16_MAX__ +# define FLT16_EPSILON __FLT16_EPSILON__ +# define FLT16_MIN __FLT16_MIN__ +# define FLT16_TRUE_MIN __FLT16_TRUE_MIN__ +#endif /* __STDC_WANT_IEC_60559_TYPES_EXT__ */ + #endif /* __FLOAT_H */ diff --git a/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h b/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h index 11aa8ceacf375..962b1a60a2585 100644 --- a/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h @@ -60,73 +60,73 @@ _mm_macc_sd(__m128d __A, __m128d __B, __m128d __C) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_msub_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_msub_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_msub_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_msub_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_nmacc_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmaddps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps(-(__v4sf)__A, (__v4sf)__B, (__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_nmacc_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmaddpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd(-(__v2df)__A, (__v2df)__B, (__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_nmacc_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmaddss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss(-(__v4sf)__A, (__v4sf)__B, (__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_nmacc_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmaddsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd(-(__v2df)__A, (__v2df)__B, (__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_nmsub_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmsubps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps(-(__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_nmsub_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmsubpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd(-(__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_nmsub_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmsubss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss(-(__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_nmsub_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmsubsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd(-(__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS @@ -144,13 +144,13 @@ _mm_maddsub_pd(__m128d __A, __m128d __B, __m128d __C) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_msubadd_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubaddps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddsubps((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_msubadd_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubaddpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsubpd((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS @@ -168,37 +168,37 @@ _mm256_macc_pd(__m256d __A, __m256d __B, __m256d __C) static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_msub_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfmsubps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256((__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_msub_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfmsubpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256((__v4df)__A, (__v4df)__B, -(__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_nmacc_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfnmaddps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256(-(__v8sf)__A, (__v8sf)__B, (__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_nmacc_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfnmaddpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256(-(__v4df)__A, (__v4df)__B, (__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_nmsub_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfnmsubps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256(-(__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_nmsub_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfnmsubpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256(-(__v4df)__A, (__v4df)__B, -(__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS @@ -216,13 +216,13 @@ _mm256_maddsub_pd(__m256d __A, __m256d __B, __m256d __C) static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_msubadd_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfmsubaddps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddsubps256((__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_msubadd_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfmsubaddpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddsubpd256((__v4df)__A, (__v4df)__B, -(__v4df)__C); } #undef __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/fmaintrin.h b/contrib/llvm/tools/clang/lib/Headers/fmaintrin.h index 0e2ef0b1716bb..478a0ac81cf26 100644 --- a/contrib/llvm/tools/clang/lib/Headers/fmaintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/fmaintrin.h @@ -46,85 +46,85 @@ _mm_fmadd_pd(__m128d __A, __m128d __B, __m128d __C) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fmadd_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmaddss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss3((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fmadd_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmaddsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd3((__v2df)__A, (__v2df)__B, (__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fmsub_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fmsub_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fmsub_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss3((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fmsub_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd3((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fnmadd_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmaddps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps(-(__v4sf)__A, (__v4sf)__B, (__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fnmadd_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmaddpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd(-(__v2df)__A, (__v2df)__B, (__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fnmadd_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmaddss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss3((__v4sf)__A, -(__v4sf)__B, (__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fnmadd_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmaddsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd3((__v2df)__A, -(__v2df)__B, (__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fnmsub_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmsubps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddps(-(__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fnmsub_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmsubpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddpd(-(__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fnmsub_ss(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfnmsubss((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddss3((__v4sf)__A, -(__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fnmsub_sd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfnmsubsd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsd3((__v2df)__A, -(__v2df)__B, -(__v2df)__C); } static __inline__ __m128 __DEFAULT_FN_ATTRS @@ -142,13 +142,13 @@ _mm_fmaddsub_pd(__m128d __A, __m128d __B, __m128d __C) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_fmsubadd_ps(__m128 __A, __m128 __B, __m128 __C) { - return (__m128)__builtin_ia32_vfmsubaddps((__v4sf)__A, (__v4sf)__B, (__v4sf)__C); + return (__m128)__builtin_ia32_vfmaddsubps((__v4sf)__A, (__v4sf)__B, -(__v4sf)__C); } static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_fmsubadd_pd(__m128d __A, __m128d __B, __m128d __C) { - return (__m128d)__builtin_ia32_vfmsubaddpd((__v2df)__A, (__v2df)__B, (__v2df)__C); + return (__m128d)__builtin_ia32_vfmaddsubpd((__v2df)__A, (__v2df)__B, -(__v2df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS @@ -166,37 +166,37 @@ _mm256_fmadd_pd(__m256d __A, __m256d __B, __m256d __C) static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_fmsub_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfmsubps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256((__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_fmsub_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfmsubpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256((__v4df)__A, (__v4df)__B, -(__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_fnmadd_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfnmaddps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256(-(__v8sf)__A, (__v8sf)__B, (__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_fnmadd_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfnmaddpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256(-(__v4df)__A, (__v4df)__B, (__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_fnmsub_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfnmsubps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddps256(-(__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_fnmsub_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfnmsubpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddpd256(-(__v4df)__A, (__v4df)__B, -(__v4df)__C); } static __inline__ __m256 __DEFAULT_FN_ATTRS @@ -214,13 +214,13 @@ _mm256_fmaddsub_pd(__m256d __A, __m256d __B, __m256d __C) static __inline__ __m256 __DEFAULT_FN_ATTRS _mm256_fmsubadd_ps(__m256 __A, __m256 __B, __m256 __C) { - return (__m256)__builtin_ia32_vfmsubaddps256((__v8sf)__A, (__v8sf)__B, (__v8sf)__C); + return (__m256)__builtin_ia32_vfmaddsubps256((__v8sf)__A, (__v8sf)__B, -(__v8sf)__C); } static __inline__ __m256d __DEFAULT_FN_ATTRS _mm256_fmsubadd_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfmsubaddpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); + return (__m256d)__builtin_ia32_vfmaddsubpd256((__v4df)__A, (__v4df)__B, -(__v4df)__C); } #undef __DEFAULT_FN_ATTRS diff --git a/contrib/llvm/tools/clang/lib/Headers/immintrin.h b/contrib/llvm/tools/clang/lib/Headers/immintrin.h index c5f25bfcb5c14..64ad6e6584224 100644 --- a/contrib/llvm/tools/clang/lib/Headers/immintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/immintrin.h @@ -58,6 +58,10 @@ #include <clflushoptintrin.h> #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__CLWB__) +#include <clwbintrin.h> +#endif + #if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX__) #include <avxintrin.h> #endif @@ -150,6 +154,11 @@ _mm256_cvtph_ps(__m128i __a) #include <avx512vpopcntdqintrin.h> #endif +#if !defined(_MSC_VER) || __has_feature(modules) || \ + (defined(__AVX512VL__) && defined(__AVX512VPOPCNTDQ__)) +#include <avx512vpopcntdqvlintrin.h> +#endif + #if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512DQ__) #include <avx512dqintrin.h> #endif @@ -315,6 +324,10 @@ _writegsbase_u64(unsigned long long __V) #include <xsavesintrin.h> #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__SHSTK__) +#include <cetintrin.h> +#endif + /* Some intrinsics inside adxintrin.h are available only on processors with ADX, * whereas others are also available at all times. */ #include <adxintrin.h> diff --git a/contrib/llvm/tools/clang/lib/Headers/intrin.h b/contrib/llvm/tools/clang/lib/Headers/intrin.h index 881d05c0d1649..b30aa215a452e 100644 --- a/contrib/llvm/tools/clang/lib/Headers/intrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/intrin.h @@ -38,6 +38,10 @@ #include <armintr.h> #endif +#if defined(_M_ARM64) +#include <arm64intr.h> +#endif + /* For the definition of jmp_buf. */ #if __STDC_HOSTED__ #include <setjmp.h> @@ -828,7 +832,7 @@ _InterlockedCompareExchange_nf(long volatile *_Destination, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); return _Comparand; } -static __inline__ short __DEFAULT_FN_ATTRS +static __inline__ long __DEFAULT_FN_ATTRS _InterlockedCompareExchange_rel(long volatile *_Destination, long _Exchange, long _Comparand) { __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, diff --git a/contrib/llvm/tools/clang/lib/Headers/opencl-c.h b/contrib/llvm/tools/clang/lib/Headers/opencl-c.h index 58c8daf3a5369..ce204b04c0305 100644 --- a/contrib/llvm/tools/clang/lib/Headers/opencl-c.h +++ b/contrib/llvm/tools/clang/lib/Headers/opencl-c.h @@ -11381,6 +11381,8 @@ half16 __ovld __cnfn bitselect(half16 a, half16 b, half16 c); * For each component of a vector type, * result[i] = if MSB of c[i] is set ? b[i] : a[i]. * For a scalar type, result = c ? b : a. + * b and a must have the same type. + * c must have the same number of elements and bits as a. */ char __ovld __cnfn select(char a, char b, char c); uchar __ovld __cnfn select(uchar a, uchar b, char c); @@ -11394,60 +11396,7 @@ char8 __ovld __cnfn select(char8 a, char8 b, char8 c); uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, char8 c); char16 __ovld __cnfn select(char16 a, char16 b, char16 c); uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, char16 c); -short __ovld __cnfn select(short a, short b, char c); -ushort __ovld __cnfn select(ushort a, ushort b, char c); -short2 __ovld __cnfn select(short2 a, short2 b, char2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, char2 c); -short3 __ovld __cnfn select(short3 a, short3 b, char3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, char3 c); -short4 __ovld __cnfn select(short4 a, short4 b, char4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, char4 c); -short8 __ovld __cnfn select(short8 a, short8 b, char8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, char8 c); -short16 __ovld __cnfn select(short16 a, short16 b, char16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, char16 c); -int __ovld __cnfn select(int a, int b, char c); -uint __ovld __cnfn select(uint a, uint b, char c); -int2 __ovld __cnfn select(int2 a, int2 b, char2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, char2 c); -int3 __ovld __cnfn select(int3 a, int3 b, char3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, char3 c); -int4 __ovld __cnfn select(int4 a, int4 b, char4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, char4 c); -int8 __ovld __cnfn select(int8 a, int8 b, char8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, char8 c); -int16 __ovld __cnfn select(int16 a, int16 b, char16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, char16 c); -long __ovld __cnfn select(long a, long b, char c); -ulong __ovld __cnfn select(ulong a, ulong b, char c); -long2 __ovld __cnfn select(long2 a, long2 b, char2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, char2 c); -long3 __ovld __cnfn select(long3 a, long3 b, char3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, char3 c); -long4 __ovld __cnfn select(long4 a, long4 b, char4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, char4 c); -long8 __ovld __cnfn select(long8 a, long8 b, char8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, char8 c); -long16 __ovld __cnfn select(long16 a, long16 b, char16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, char16 c); -float __ovld __cnfn select(float a, float b, char c); -float2 __ovld __cnfn select(float2 a, float2 b, char2 c); -float3 __ovld __cnfn select(float3 a, float3 b, char3 c); -float4 __ovld __cnfn select(float4 a, float4 b, char4 c); -float8 __ovld __cnfn select(float8 a, float8 b, char8 c); -float16 __ovld __cnfn select(float16 a, float16 b, char16 c); -char __ovld __cnfn select(char a, char b, short c); -uchar __ovld __cnfn select(uchar a, uchar b, short c); -char2 __ovld __cnfn select(char2 a, char2 b, short2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, short2 c); -char3 __ovld __cnfn select(char3 a, char3 b, short3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, short3 c); -char4 __ovld __cnfn select(char4 a, char4 b, short4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, short4 c); -char8 __ovld __cnfn select(char8 a, char8 b, short8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, short8 c); -char16 __ovld __cnfn select(char16 a, char16 b, short16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, short16 c); + short __ovld __cnfn select(short a, short b, short c); ushort __ovld __cnfn select(ushort a, ushort b, short c); short2 __ovld __cnfn select(short2 a, short2 b, short2 c); @@ -11460,60 +11409,7 @@ short8 __ovld __cnfn select(short8 a, short8 b, short8 c); ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, short8 c); short16 __ovld __cnfn select(short16 a, short16 b, short16 c); ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, short16 c); -int __ovld __cnfn select(int a, int b, short c); -uint __ovld __cnfn select(uint a, uint b, short c); -int2 __ovld __cnfn select(int2 a, int2 b, short2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, short2 c); -int3 __ovld __cnfn select(int3 a, int3 b, short3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, short3 c); -int4 __ovld __cnfn select(int4 a, int4 b, short4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, short4 c); -int8 __ovld __cnfn select(int8 a, int8 b, short8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, short8 c); -int16 __ovld __cnfn select(int16 a, int16 b, short16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, short16 c); -long __ovld __cnfn select(long a, long b, short c); -ulong __ovld __cnfn select(ulong a, ulong b, short c); -long2 __ovld __cnfn select(long2 a, long2 b, short2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, short2 c); -long3 __ovld __cnfn select(long3 a, long3 b, short3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, short3 c); -long4 __ovld __cnfn select(long4 a, long4 b, short4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, short4 c); -long8 __ovld __cnfn select(long8 a, long8 b, short8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, short8 c); -long16 __ovld __cnfn select(long16 a, long16 b, short16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, short16 c); -float __ovld __cnfn select(float a, float b, short c); -float2 __ovld __cnfn select(float2 a, float2 b, short2 c); -float3 __ovld __cnfn select(float3 a, float3 b, short3 c); -float4 __ovld __cnfn select(float4 a, float4 b, short4 c); -float8 __ovld __cnfn select(float8 a, float8 b, short8 c); -float16 __ovld __cnfn select(float16 a, float16 b, short16 c); -char __ovld __cnfn select(char a, char b, int c); -uchar __ovld __cnfn select(uchar a, uchar b, int c); -char2 __ovld __cnfn select(char2 a, char2 b, int2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, int2 c); -char3 __ovld __cnfn select(char3 a, char3 b, int3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, int3 c); -char4 __ovld __cnfn select(char4 a, char4 b, int4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, int4 c); -char8 __ovld __cnfn select(char8 a, char8 b, int8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, int8 c); -char16 __ovld __cnfn select(char16 a, char16 b, int16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, int16 c); -short __ovld __cnfn select(short a, short b, int c); -ushort __ovld __cnfn select(ushort a, ushort b, int c); -short2 __ovld __cnfn select(short2 a, short2 b, int2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, int2 c); -short3 __ovld __cnfn select(short3 a, short3 b, int3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, int3 c); -short4 __ovld __cnfn select(short4 a, short4 b, int4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, int4 c); -short8 __ovld __cnfn select(short8 a, short8 b, int8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, int8 c); -short16 __ovld __cnfn select(short16 a, short16 b, int16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, int16 c); + int __ovld __cnfn select(int a, int b, int c); uint __ovld __cnfn select(uint a, uint b, int c); int2 __ovld __cnfn select(int2 a, int2 b, int2 c); @@ -11526,60 +11422,13 @@ int8 __ovld __cnfn select(int8 a, int8 b, int8 c); uint8 __ovld __cnfn select(uint8 a, uint8 b, int8 c); int16 __ovld __cnfn select(int16 a, int16 b, int16 c); uint16 __ovld __cnfn select(uint16 a, uint16 b, int16 c); -long __ovld __cnfn select(long a, long b, int c); -ulong __ovld __cnfn select(ulong a, ulong b, int c); -long2 __ovld __cnfn select(long2 a, long2 b, int2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, int2 c); -long3 __ovld __cnfn select(long3 a, long3 b, int3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, int3 c); -long4 __ovld __cnfn select(long4 a, long4 b, int4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, int4 c); -long8 __ovld __cnfn select(long8 a, long8 b, int8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, int8 c); -long16 __ovld __cnfn select(long16 a, long16 b, int16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, int16 c); float __ovld __cnfn select(float a, float b, int c); float2 __ovld __cnfn select(float2 a, float2 b, int2 c); float3 __ovld __cnfn select(float3 a, float3 b, int3 c); float4 __ovld __cnfn select(float4 a, float4 b, int4 c); float8 __ovld __cnfn select(float8 a, float8 b, int8 c); float16 __ovld __cnfn select(float16 a, float16 b, int16 c); -char __ovld __cnfn select(char a, char b, long c); -uchar __ovld __cnfn select(uchar a, uchar b, long c); -char2 __ovld __cnfn select(char2 a, char2 b, long2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, long2 c); -char3 __ovld __cnfn select(char3 a, char3 b, long3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, long3 c); -char4 __ovld __cnfn select(char4 a, char4 b, long4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, long4 c); -char8 __ovld __cnfn select(char8 a, char8 b, long8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, long8 c); -char16 __ovld __cnfn select(char16 a, char16 b, long16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, long16 c); -short __ovld __cnfn select(short a, short b, long c); -ushort __ovld __cnfn select(ushort a, ushort b, long c); -short2 __ovld __cnfn select(short2 a, short2 b, long2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, long2 c); -short3 __ovld __cnfn select(short3 a, short3 b, long3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, long3 c); -short4 __ovld __cnfn select(short4 a, short4 b, long4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, long4 c); -short8 __ovld __cnfn select(short8 a, short8 b, long8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, long8 c); -short16 __ovld __cnfn select(short16 a, short16 b, long16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, long16 c); -int __ovld __cnfn select(int a, int b, long c); -uint __ovld __cnfn select(uint a, uint b, long c); -int2 __ovld __cnfn select(int2 a, int2 b, long2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, long2 c); -int3 __ovld __cnfn select(int3 a, int3 b, long3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, long3 c); -int4 __ovld __cnfn select(int4 a, int4 b, long4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, long4 c); -int8 __ovld __cnfn select(int8 a, int8 b, long8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, long8 c); -int16 __ovld __cnfn select(int16 a, int16 b, long16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, long16 c); + long __ovld __cnfn select(long a, long b, long c); ulong __ovld __cnfn select(ulong a, ulong b, long c); long2 __ovld __cnfn select(long2 a, long2 b, long2 c); @@ -11592,12 +11441,7 @@ long8 __ovld __cnfn select(long8 a, long8 b, long8 c); ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, long8 c); long16 __ovld __cnfn select(long16 a, long16 b, long16 c); ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, long16 c); -float __ovld __cnfn select(float a, float b, long c); -float2 __ovld __cnfn select(float2 a, float2 b, long2 c); -float3 __ovld __cnfn select(float3 a, float3 b, long3 c); -float4 __ovld __cnfn select(float4 a, float4 b, long4 c); -float8 __ovld __cnfn select(float8 a, float8 b, long8 c); -float16 __ovld __cnfn select(float16 a, float16 b, long16 c); + char __ovld __cnfn select(char a, char b, uchar c); uchar __ovld __cnfn select(uchar a, uchar b, uchar c); char2 __ovld __cnfn select(char2 a, char2 b, uchar2 c); @@ -11610,60 +11454,7 @@ char8 __ovld __cnfn select(char8 a, char8 b, uchar8 c); uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, uchar8 c); char16 __ovld __cnfn select(char16 a, char16 b, uchar16 c); uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, uchar16 c); -short __ovld __cnfn select(short a, short b, uchar c); -ushort __ovld __cnfn select(ushort a, ushort b, uchar c); -short2 __ovld __cnfn select(short2 a, short2 b, uchar2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, uchar2 c); -short3 __ovld __cnfn select(short3 a, short3 b, uchar3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, uchar3 c); -short4 __ovld __cnfn select(short4 a, short4 b, uchar4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, uchar4 c); -short8 __ovld __cnfn select(short8 a, short8 b, uchar8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, uchar8 c); -short16 __ovld __cnfn select(short16 a, short16 b, uchar16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, uchar16 c); -int __ovld __cnfn select(int a, int b, uchar c); -uint __ovld __cnfn select(uint a, uint b, uchar c); -int2 __ovld __cnfn select(int2 a, int2 b, uchar2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, uchar2 c); -int3 __ovld __cnfn select(int3 a, int3 b, uchar3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, uchar3 c); -int4 __ovld __cnfn select(int4 a, int4 b, uchar4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, uchar4 c); -int8 __ovld __cnfn select(int8 a, int8 b, uchar8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, uchar8 c); -int16 __ovld __cnfn select(int16 a, int16 b, uchar16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, uchar16 c); -long __ovld __cnfn select(long a, long b, uchar c); -ulong __ovld __cnfn select(ulong a, ulong b, uchar c); -long2 __ovld __cnfn select(long2 a, long2 b, uchar2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, uchar2 c); -long3 __ovld __cnfn select(long3 a, long3 b, uchar3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, uchar3 c); -long4 __ovld __cnfn select(long4 a, long4 b, uchar4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, uchar4 c); -long8 __ovld __cnfn select(long8 a, long8 b, uchar8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, uchar8 c); -long16 __ovld __cnfn select(long16 a, long16 b, uchar16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, uchar16 c); -float __ovld __cnfn select(float a, float b, uchar c); -float2 __ovld __cnfn select(float2 a, float2 b, uchar2 c); -float3 __ovld __cnfn select(float3 a, float3 b, uchar3 c); -float4 __ovld __cnfn select(float4 a, float4 b, uchar4 c); -float8 __ovld __cnfn select(float8 a, float8 b, uchar8 c); -float16 __ovld __cnfn select(float16 a, float16 b, uchar16 c); -char __ovld __cnfn select(char a, char b, ushort c); -uchar __ovld __cnfn select(uchar a, uchar b, ushort c); -char2 __ovld __cnfn select(char2 a, char2 b, ushort2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, ushort2 c); -char3 __ovld __cnfn select(char3 a, char3 b, ushort3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, ushort3 c); -char4 __ovld __cnfn select(char4 a, char4 b, ushort4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, ushort4 c); -char8 __ovld __cnfn select(char8 a, char8 b, ushort8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, ushort8 c); -char16 __ovld __cnfn select(char16 a, char16 b, ushort16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, ushort16 c); + short __ovld __cnfn select(short a, short b, ushort c); ushort __ovld __cnfn select(ushort a, ushort b, ushort c); short2 __ovld __cnfn select(short2 a, short2 b, ushort2 c); @@ -11676,60 +11467,7 @@ short8 __ovld __cnfn select(short8 a, short8 b, ushort8 c); ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, ushort8 c); short16 __ovld __cnfn select(short16 a, short16 b, ushort16 c); ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, ushort16 c); -int __ovld __cnfn select(int a, int b, ushort c); -uint __ovld __cnfn select(uint a, uint b, ushort c); -int2 __ovld __cnfn select(int2 a, int2 b, ushort2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, ushort2 c); -int3 __ovld __cnfn select(int3 a, int3 b, ushort3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, ushort3 c); -int4 __ovld __cnfn select(int4 a, int4 b, ushort4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, ushort4 c); -int8 __ovld __cnfn select(int8 a, int8 b, ushort8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, ushort8 c); -int16 __ovld __cnfn select(int16 a, int16 b, ushort16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, ushort16 c); -long __ovld __cnfn select(long a, long b, ushort c); -ulong __ovld __cnfn select(ulong a, ulong b, ushort c); -long2 __ovld __cnfn select(long2 a, long2 b, ushort2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, ushort2 c); -long3 __ovld __cnfn select(long3 a, long3 b, ushort3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, ushort3 c); -long4 __ovld __cnfn select(long4 a, long4 b, ushort4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, ushort4 c); -long8 __ovld __cnfn select(long8 a, long8 b, ushort8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, ushort8 c); -long16 __ovld __cnfn select(long16 a, long16 b, ushort16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, ushort16 c); -float __ovld __cnfn select(float a, float b, ushort c); -float2 __ovld __cnfn select(float2 a, float2 b, ushort2 c); -float3 __ovld __cnfn select(float3 a, float3 b, ushort3 c); -float4 __ovld __cnfn select(float4 a, float4 b, ushort4 c); -float8 __ovld __cnfn select(float8 a, float8 b, ushort8 c); -float16 __ovld __cnfn select(float16 a, float16 b, ushort16 c); -char __ovld __cnfn select(char a, char b, uint c); -uchar __ovld __cnfn select(uchar a, uchar b, uint c); -char2 __ovld __cnfn select(char2 a, char2 b, uint2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, uint2 c); -char3 __ovld __cnfn select(char3 a, char3 b, uint3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, uint3 c); -char4 __ovld __cnfn select(char4 a, char4 b, uint4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, uint4 c); -char8 __ovld __cnfn select(char8 a, char8 b, uint8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, uint8 c); -char16 __ovld __cnfn select(char16 a, char16 b, uint16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, uint16 c); -short __ovld __cnfn select(short a, short b, uint c); -ushort __ovld __cnfn select(ushort a, ushort b, uint c); -short2 __ovld __cnfn select(short2 a, short2 b, uint2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, uint2 c); -short3 __ovld __cnfn select(short3 a, short3 b, uint3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, uint3 c); -short4 __ovld __cnfn select(short4 a, short4 b, uint4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, uint4 c); -short8 __ovld __cnfn select(short8 a, short8 b, uint8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, uint8 c); -short16 __ovld __cnfn select(short16 a, short16 b, uint16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, uint16 c); + int __ovld __cnfn select(int a, int b, uint c); uint __ovld __cnfn select(uint a, uint b, uint c); int2 __ovld __cnfn select(int2 a, int2 b, uint2 c); @@ -11742,60 +11480,13 @@ int8 __ovld __cnfn select(int8 a, int8 b, uint8 c); uint8 __ovld __cnfn select(uint8 a, uint8 b, uint8 c); int16 __ovld __cnfn select(int16 a, int16 b, uint16 c); uint16 __ovld __cnfn select(uint16 a, uint16 b, uint16 c); -long __ovld __cnfn select(long a, long b, uint c); -ulong __ovld __cnfn select(ulong a, ulong b, uint c); -long2 __ovld __cnfn select(long2 a, long2 b, uint2 c); -ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, uint2 c); -long3 __ovld __cnfn select(long3 a, long3 b, uint3 c); -ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, uint3 c); -long4 __ovld __cnfn select(long4 a, long4 b, uint4 c); -ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, uint4 c); -long8 __ovld __cnfn select(long8 a, long8 b, uint8 c); -ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, uint8 c); -long16 __ovld __cnfn select(long16 a, long16 b, uint16 c); -ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, uint16 c); float __ovld __cnfn select(float a, float b, uint c); float2 __ovld __cnfn select(float2 a, float2 b, uint2 c); float3 __ovld __cnfn select(float3 a, float3 b, uint3 c); float4 __ovld __cnfn select(float4 a, float4 b, uint4 c); float8 __ovld __cnfn select(float8 a, float8 b, uint8 c); float16 __ovld __cnfn select(float16 a, float16 b, uint16 c); -char __ovld __cnfn select(char a, char b, ulong c); -uchar __ovld __cnfn select(uchar a, uchar b, ulong c); -char2 __ovld __cnfn select(char2 a, char2 b, ulong2 c); -uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, ulong2 c); -char3 __ovld __cnfn select(char3 a, char3 b, ulong3 c); -uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, ulong3 c); -char4 __ovld __cnfn select(char4 a, char4 b, ulong4 c); -uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, ulong4 c); -char8 __ovld __cnfn select(char8 a, char8 b, ulong8 c); -uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, ulong8 c); -char16 __ovld __cnfn select(char16 a, char16 b, ulong16 c); -uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, ulong16 c); -short __ovld __cnfn select(short a, short b, ulong c); -ushort __ovld __cnfn select(ushort a, ushort b, ulong c); -short2 __ovld __cnfn select(short2 a, short2 b, ulong2 c); -ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, ulong2 c); -short3 __ovld __cnfn select(short3 a, short3 b, ulong3 c); -ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, ulong3 c); -short4 __ovld __cnfn select(short4 a, short4 b, ulong4 c); -ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, ulong4 c); -short8 __ovld __cnfn select(short8 a, short8 b, ulong8 c); -ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, ulong8 c); -short16 __ovld __cnfn select(short16 a, short16 b, ulong16 c); -ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, ulong16 c); -int __ovld __cnfn select(int a, int b, ulong c); -uint __ovld __cnfn select(uint a, uint b, ulong c); -int2 __ovld __cnfn select(int2 a, int2 b, ulong2 c); -uint2 __ovld __cnfn select(uint2 a, uint2 b, ulong2 c); -int3 __ovld __cnfn select(int3 a, int3 b, ulong3 c); -uint3 __ovld __cnfn select(uint3 a, uint3 b, ulong3 c); -int4 __ovld __cnfn select(int4 a, int4 b, ulong4 c); -uint4 __ovld __cnfn select(uint4 a, uint4 b, ulong4 c); -int8 __ovld __cnfn select(int8 a, int8 b, ulong8 c); -uint8 __ovld __cnfn select(uint8 a, uint8 b, ulong8 c); -int16 __ovld __cnfn select(int16 a, int16 b, ulong16 c); -uint16 __ovld __cnfn select(uint16 a, uint16 b, ulong16 c); + long __ovld __cnfn select(long a, long b, ulong c); ulong __ovld __cnfn select(ulong a, ulong b, ulong c); long2 __ovld __cnfn select(long2 a, long2 b, ulong2 c); @@ -11808,12 +11499,7 @@ long8 __ovld __cnfn select(long8 a, long8 b, ulong8 c); ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, ulong8 c); long16 __ovld __cnfn select(long16 a, long16 b, ulong16 c); ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, ulong16 c); -float __ovld __cnfn select(float a, float b, ulong c); -float2 __ovld __cnfn select(float2 a, float2 b, ulong2 c); -float3 __ovld __cnfn select(float3 a, float3 b, ulong3 c); -float4 __ovld __cnfn select(float4 a, float4 b, ulong4 c); -float8 __ovld __cnfn select(float8 a, float8 b, ulong8 c); -float16 __ovld __cnfn select(float16 a, float16 b, ulong16 c); + #ifdef cl_khr_fp64 double __ovld __cnfn select(double a, double b, long c); double2 __ovld __cnfn select(double2 a, double2 b, long2 c); @@ -13141,13 +12827,14 @@ void __ovld __conv barrier(cl_mem_fence_flags flags); #if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 -typedef enum memory_scope -{ - memory_scope_work_item, - memory_scope_work_group, - memory_scope_device, - memory_scope_all_svm_devices, - memory_scope_sub_group +typedef enum memory_scope { + memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM, + memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP, + memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE, + memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES, +#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) + memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP +#endif } memory_scope; void __ovld __conv work_group_barrier(cl_mem_fence_flags flags, memory_scope scope); @@ -13952,11 +13639,11 @@ unsigned long __ovld atom_xor(volatile __local unsigned long *p, unsigned long v // enum values aligned with what clang uses in EmitAtomicExpr() typedef enum memory_order { - memory_order_relaxed, - memory_order_acquire, - memory_order_release, - memory_order_acq_rel, - memory_order_seq_cst + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST } memory_order; // double atomics support requires extensions cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics @@ -16199,6 +15886,313 @@ double __ovld __conv sub_group_scan_inclusive_max(double x); #endif //cl_khr_subgroups cl_intel_subgroups +#if defined(cl_intel_subgroups) +// Intel-Specific Sub Group Functions +float __ovld __conv intel_sub_group_shuffle( float x, uint c ); +float2 __ovld __conv intel_sub_group_shuffle( float2 x, uint c ); +float3 __ovld __conv intel_sub_group_shuffle( float3 x, uint c ); +float4 __ovld __conv intel_sub_group_shuffle( float4 x, uint c ); +float8 __ovld __conv intel_sub_group_shuffle( float8 x, uint c ); +float16 __ovld __conv intel_sub_group_shuffle( float16 x, uint c ); + +int __ovld __conv intel_sub_group_shuffle( int x, uint c ); +int2 __ovld __conv intel_sub_group_shuffle( int2 x, uint c ); +int3 __ovld __conv intel_sub_group_shuffle( int3 x, uint c ); +int4 __ovld __conv intel_sub_group_shuffle( int4 x, uint c ); +int8 __ovld __conv intel_sub_group_shuffle( int8 x, uint c ); +int16 __ovld __conv intel_sub_group_shuffle( int16 x, uint c ); + +uint __ovld __conv intel_sub_group_shuffle( uint x, uint c ); +uint2 __ovld __conv intel_sub_group_shuffle( uint2 x, uint c ); +uint3 __ovld __conv intel_sub_group_shuffle( uint3 x, uint c ); +uint4 __ovld __conv intel_sub_group_shuffle( uint4 x, uint c ); +uint8 __ovld __conv intel_sub_group_shuffle( uint8 x, uint c ); +uint16 __ovld __conv intel_sub_group_shuffle( uint16 x, uint c ); + +long __ovld __conv intel_sub_group_shuffle( long x, uint c ); +ulong __ovld __conv intel_sub_group_shuffle( ulong x, uint c ); + +float __ovld __conv intel_sub_group_shuffle_down( float cur, float next, uint c ); +float2 __ovld __conv intel_sub_group_shuffle_down( float2 cur, float2 next, uint c ); +float3 __ovld __conv intel_sub_group_shuffle_down( float3 cur, float3 next, uint c ); +float4 __ovld __conv intel_sub_group_shuffle_down( float4 cur, float4 next, uint c ); +float8 __ovld __conv intel_sub_group_shuffle_down( float8 cur, float8 next, uint c ); +float16 __ovld __conv intel_sub_group_shuffle_down( float16 cur, float16 next, uint c ); + +int __ovld __conv intel_sub_group_shuffle_down( int cur, int next, uint c ); +int2 __ovld __conv intel_sub_group_shuffle_down( int2 cur, int2 next, uint c ); +int3 __ovld __conv intel_sub_group_shuffle_down( int3 cur, int3 next, uint c ); +int4 __ovld __conv intel_sub_group_shuffle_down( int4 cur, int4 next, uint c ); +int8 __ovld __conv intel_sub_group_shuffle_down( int8 cur, int8 next, uint c ); +int16 __ovld __conv intel_sub_group_shuffle_down( int16 cur, int16 next, uint c ); + +uint __ovld __conv intel_sub_group_shuffle_down( uint cur, uint next, uint c ); +uint2 __ovld __conv intel_sub_group_shuffle_down( uint2 cur, uint2 next, uint c ); +uint3 __ovld __conv intel_sub_group_shuffle_down( uint3 cur, uint3 next, uint c ); +uint4 __ovld __conv intel_sub_group_shuffle_down( uint4 cur, uint4 next, uint c ); +uint8 __ovld __conv intel_sub_group_shuffle_down( uint8 cur, uint8 next, uint c ); +uint16 __ovld __conv intel_sub_group_shuffle_down( uint16 cur, uint16 next, uint c ); + +long __ovld __conv intel_sub_group_shuffle_down( long prev, long cur, uint c ); +ulong __ovld __conv intel_sub_group_shuffle_down( ulong prev, ulong cur, uint c ); + +float __ovld __conv intel_sub_group_shuffle_up( float prev, float cur, uint c ); +float2 __ovld __conv intel_sub_group_shuffle_up( float2 prev, float2 cur, uint c ); +float3 __ovld __conv intel_sub_group_shuffle_up( float3 prev, float3 cur, uint c ); +float4 __ovld __conv intel_sub_group_shuffle_up( float4 prev, float4 cur, uint c ); +float8 __ovld __conv intel_sub_group_shuffle_up( float8 prev, float8 cur, uint c ); +float16 __ovld __conv intel_sub_group_shuffle_up( float16 prev, float16 cur, uint c ); + +int __ovld __conv intel_sub_group_shuffle_up( int prev, int cur, uint c ); +int2 __ovld __conv intel_sub_group_shuffle_up( int2 prev, int2 cur, uint c ); +int3 __ovld __conv intel_sub_group_shuffle_up( int3 prev, int3 cur, uint c ); +int4 __ovld __conv intel_sub_group_shuffle_up( int4 prev, int4 cur, uint c ); +int8 __ovld __conv intel_sub_group_shuffle_up( int8 prev, int8 cur, uint c ); +int16 __ovld __conv intel_sub_group_shuffle_up( int16 prev, int16 cur, uint c ); + +uint __ovld __conv intel_sub_group_shuffle_up( uint prev, uint cur, uint c ); +uint2 __ovld __conv intel_sub_group_shuffle_up( uint2 prev, uint2 cur, uint c ); +uint3 __ovld __conv intel_sub_group_shuffle_up( uint3 prev, uint3 cur, uint c ); +uint4 __ovld __conv intel_sub_group_shuffle_up( uint4 prev, uint4 cur, uint c ); +uint8 __ovld __conv intel_sub_group_shuffle_up( uint8 prev, uint8 cur, uint c ); +uint16 __ovld __conv intel_sub_group_shuffle_up( uint16 prev, uint16 cur, uint c ); + +long __ovld __conv intel_sub_group_shuffle_up( long prev, long cur, uint c ); +ulong __ovld __conv intel_sub_group_shuffle_up( ulong prev, ulong cur, uint c ); + +float __ovld __conv intel_sub_group_shuffle_xor( float x, uint c ); +float2 __ovld __conv intel_sub_group_shuffle_xor( float2 x, uint c ); +float3 __ovld __conv intel_sub_group_shuffle_xor( float3 x, uint c ); +float4 __ovld __conv intel_sub_group_shuffle_xor( float4 x, uint c ); +float8 __ovld __conv intel_sub_group_shuffle_xor( float8 x, uint c ); +float16 __ovld __conv intel_sub_group_shuffle_xor( float16 x, uint c ); + +int __ovld __conv intel_sub_group_shuffle_xor( int x, uint c ); +int2 __ovld __conv intel_sub_group_shuffle_xor( int2 x, uint c ); +int3 __ovld __conv intel_sub_group_shuffle_xor( int3 x, uint c ); +int4 __ovld __conv intel_sub_group_shuffle_xor( int4 x, uint c ); +int8 __ovld __conv intel_sub_group_shuffle_xor( int8 x, uint c ); +int16 __ovld __conv intel_sub_group_shuffle_xor( int16 x, uint c ); + +uint __ovld __conv intel_sub_group_shuffle_xor( uint x, uint c ); +uint2 __ovld __conv intel_sub_group_shuffle_xor( uint2 x, uint c ); +uint3 __ovld __conv intel_sub_group_shuffle_xor( uint3 x, uint c ); +uint4 __ovld __conv intel_sub_group_shuffle_xor( uint4 x, uint c ); +uint8 __ovld __conv intel_sub_group_shuffle_xor( uint8 x, uint c ); +uint16 __ovld __conv intel_sub_group_shuffle_xor( uint16 x, uint c ); + +long __ovld __conv intel_sub_group_shuffle_xor( long x, uint c ); +ulong __ovld __conv intel_sub_group_shuffle_xor( ulong x, uint c ); + +uint __ovld __conv intel_sub_group_block_read( read_only image2d_t image, int2 coord ); +uint2 __ovld __conv intel_sub_group_block_read2( read_only image2d_t image, int2 coord ); +uint4 __ovld __conv intel_sub_group_block_read4( read_only image2d_t image, int2 coord ); +uint8 __ovld __conv intel_sub_group_block_read8( read_only image2d_t image, int2 coord ); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +uint __ovld __conv intel_sub_group_block_read(read_write image2d_t image, int2 coord); +uint2 __ovld __conv intel_sub_group_block_read2(read_write image2d_t image, int2 coord); +uint4 __ovld __conv intel_sub_group_block_read4(read_write image2d_t image, int2 coord); +uint8 __ovld __conv intel_sub_group_block_read8(read_write image2d_t image, int2 coord); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +uint __ovld __conv intel_sub_group_block_read( const __global uint* p ); +uint2 __ovld __conv intel_sub_group_block_read2( const __global uint* p ); +uint4 __ovld __conv intel_sub_group_block_read4( const __global uint* p ); +uint8 __ovld __conv intel_sub_group_block_read8( const __global uint* p ); + +void __ovld __conv intel_sub_group_block_write(write_only image2d_t image, int2 coord, uint data); +void __ovld __conv intel_sub_group_block_write2(write_only image2d_t image, int2 coord, uint2 data); +void __ovld __conv intel_sub_group_block_write4(write_only image2d_t image, int2 coord, uint4 data); +void __ovld __conv intel_sub_group_block_write8(write_only image2d_t image, int2 coord, uint8 data); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +void __ovld __conv intel_sub_group_block_write(read_write image2d_t image, int2 coord, uint data); +void __ovld __conv intel_sub_group_block_write2(read_write image2d_t image, int2 coord, uint2 data); +void __ovld __conv intel_sub_group_block_write4(read_write image2d_t image, int2 coord, uint4 data); +void __ovld __conv intel_sub_group_block_write8(read_write image2d_t image, int2 coord, uint8 data); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +void __ovld __conv intel_sub_group_block_write( __global uint* p, uint data ); +void __ovld __conv intel_sub_group_block_write2( __global uint* p, uint2 data ); +void __ovld __conv intel_sub_group_block_write4( __global uint* p, uint4 data ); +void __ovld __conv intel_sub_group_block_write8( __global uint* p, uint8 data ); + +#ifdef cl_khr_fp16 +half __ovld __conv intel_sub_group_shuffle( half x, uint c ); +half __ovld __conv intel_sub_group_shuffle_down( half prev, half cur, uint c ); +half __ovld __conv intel_sub_group_shuffle_up( half prev, half cur, uint c ); +half __ovld __conv intel_sub_group_shuffle_xor( half x, uint c ); +#endif + +#if defined(cl_khr_fp64) +double __ovld __conv intel_sub_group_shuffle( double x, uint c ); +double __ovld __conv intel_sub_group_shuffle_down( double prev, double cur, uint c ); +double __ovld __conv intel_sub_group_shuffle_up( double prev, double cur, uint c ); +double __ovld __conv intel_sub_group_shuffle_xor( double x, uint c ); +#endif + +#endif //cl_intel_subgroups + +#if defined(cl_intel_subgroups_short) +short __ovld __conv intel_sub_group_broadcast( short x, uint sub_group_local_id ); +short2 __ovld __conv intel_sub_group_broadcast( short2 x, uint sub_group_local_id ); +short3 __ovld __conv intel_sub_group_broadcast( short3 x, uint sub_group_local_id ); +short4 __ovld __conv intel_sub_group_broadcast( short4 x, uint sub_group_local_id ); +short8 __ovld __conv intel_sub_group_broadcast( short8 x, uint sub_group_local_id ); + +ushort __ovld __conv intel_sub_group_broadcast( ushort x, uint sub_group_local_id ); +ushort2 __ovld __conv intel_sub_group_broadcast( ushort2 x, uint sub_group_local_id ); +ushort3 __ovld __conv intel_sub_group_broadcast( ushort3 x, uint sub_group_local_id ); +ushort4 __ovld __conv intel_sub_group_broadcast( ushort4 x, uint sub_group_local_id ); +ushort8 __ovld __conv intel_sub_group_broadcast( ushort8 x, uint sub_group_local_id ); + +short __ovld __conv intel_sub_group_shuffle( short x, uint c ); +short2 __ovld __conv intel_sub_group_shuffle( short2 x, uint c ); +short3 __ovld __conv intel_sub_group_shuffle( short3 x, uint c ); +short4 __ovld __conv intel_sub_group_shuffle( short4 x, uint c ); +short8 __ovld __conv intel_sub_group_shuffle( short8 x, uint c ); +short16 __ovld __conv intel_sub_group_shuffle( short16 x, uint c); + +ushort __ovld __conv intel_sub_group_shuffle( ushort x, uint c ); +ushort2 __ovld __conv intel_sub_group_shuffle( ushort2 x, uint c ); +ushort3 __ovld __conv intel_sub_group_shuffle( ushort3 x, uint c ); +ushort4 __ovld __conv intel_sub_group_shuffle( ushort4 x, uint c ); +ushort8 __ovld __conv intel_sub_group_shuffle( ushort8 x, uint c ); +ushort16 __ovld __conv intel_sub_group_shuffle( ushort16 x, uint c ); + +short __ovld __conv intel_sub_group_shuffle_down( short cur, short next, uint c ); +short2 __ovld __conv intel_sub_group_shuffle_down( short2 cur, short2 next, uint c ); +short3 __ovld __conv intel_sub_group_shuffle_down( short3 cur, short3 next, uint c ); +short4 __ovld __conv intel_sub_group_shuffle_down( short4 cur, short4 next, uint c ); +short8 __ovld __conv intel_sub_group_shuffle_down( short8 cur, short8 next, uint c ); +short16 __ovld __conv intel_sub_group_shuffle_down( short16 cur, short16 next, uint c ); + +ushort __ovld __conv intel_sub_group_shuffle_down( ushort cur, ushort next, uint c ); +ushort2 __ovld __conv intel_sub_group_shuffle_down( ushort2 cur, ushort2 next, uint c ); +ushort3 __ovld __conv intel_sub_group_shuffle_down( ushort3 cur, ushort3 next, uint c ); +ushort4 __ovld __conv intel_sub_group_shuffle_down( ushort4 cur, ushort4 next, uint c ); +ushort8 __ovld __conv intel_sub_group_shuffle_down( ushort8 cur, ushort8 next, uint c ); +ushort16 __ovld __conv intel_sub_group_shuffle_down( ushort16 cur, ushort16 next, uint c ); + +short __ovld __conv intel_sub_group_shuffle_up( short cur, short next, uint c ); +short2 __ovld __conv intel_sub_group_shuffle_up( short2 cur, short2 next, uint c ); +short3 __ovld __conv intel_sub_group_shuffle_up( short3 cur, short3 next, uint c ); +short4 __ovld __conv intel_sub_group_shuffle_up( short4 cur, short4 next, uint c ); +short8 __ovld __conv intel_sub_group_shuffle_up( short8 cur, short8 next, uint c ); +short16 __ovld __conv intel_sub_group_shuffle_up( short16 cur, short16 next, uint c ); + +ushort __ovld __conv intel_sub_group_shuffle_up( ushort cur, ushort next, uint c ); +ushort2 __ovld __conv intel_sub_group_shuffle_up( ushort2 cur, ushort2 next, uint c ); +ushort3 __ovld __conv intel_sub_group_shuffle_up( ushort3 cur, ushort3 next, uint c ); +ushort4 __ovld __conv intel_sub_group_shuffle_up( ushort4 cur, ushort4 next, uint c ); +ushort8 __ovld __conv intel_sub_group_shuffle_up( ushort8 cur, ushort8 next, uint c ); +ushort16 __ovld __conv intel_sub_group_shuffle_up( ushort16 cur, ushort16 next, uint c ); + +short __ovld __conv intel_sub_group_shuffle_xor( short x, uint c ); +short2 __ovld __conv intel_sub_group_shuffle_xor( short2 x, uint c ); +short3 __ovld __conv intel_sub_group_shuffle_xor( short3 x, uint c ); +short4 __ovld __conv intel_sub_group_shuffle_xor( short4 x, uint c ); +short8 __ovld __conv intel_sub_group_shuffle_xor( short8 x, uint c ); +short16 __ovld __conv intel_sub_group_shuffle_xor( short16 x, uint c ); + +ushort __ovld __conv intel_sub_group_shuffle_xor( ushort x, uint c ); +ushort2 __ovld __conv intel_sub_group_shuffle_xor( ushort2 x, uint c ); +ushort3 __ovld __conv intel_sub_group_shuffle_xor( ushort3 x, uint c ); +ushort4 __ovld __conv intel_sub_group_shuffle_xor( ushort4 x, uint c ); +ushort8 __ovld __conv intel_sub_group_shuffle_xor( ushort8 x, uint c ); +ushort16 __ovld __conv intel_sub_group_shuffle_xor( ushort16 x, uint c ); + +short __ovld __conv intel_sub_group_reduce_add( short x ); +ushort __ovld __conv intel_sub_group_reduce_add( ushort x ); +short __ovld __conv intel_sub_group_reduce_min( short x ); +ushort __ovld __conv intel_sub_group_reduce_min( ushort x ); +short __ovld __conv intel_sub_group_reduce_max( short x ); +ushort __ovld __conv intel_sub_group_reduce_max( ushort x ); + +short __ovld __conv intel_sub_group_scan_exclusive_add( short x ); +ushort __ovld __conv intel_sub_group_scan_exclusive_add( ushort x ); +short __ovld __conv intel_sub_group_scan_exclusive_min( short x ); +ushort __ovld __conv intel_sub_group_scan_exclusive_min( ushort x ); +short __ovld __conv intel_sub_group_scan_exclusive_max( short x ); +ushort __ovld __conv intel_sub_group_scan_exclusive_max( ushort x ); + +short __ovld __conv intel_sub_group_scan_inclusive_add( short x ); +ushort __ovld __conv intel_sub_group_scan_inclusive_add( ushort x ); +short __ovld __conv intel_sub_group_scan_inclusive_min( short x ); +ushort __ovld __conv intel_sub_group_scan_inclusive_min( ushort x ); +short __ovld __conv intel_sub_group_scan_inclusive_max( short x ); +ushort __ovld __conv intel_sub_group_scan_inclusive_max( ushort x ); + +uint __ovld __conv intel_sub_group_block_read_ui( read_only image2d_t image, int2 byte_coord ); +uint2 __ovld __conv intel_sub_group_block_read_ui2( read_only image2d_t image, int2 byte_coord ); +uint4 __ovld __conv intel_sub_group_block_read_ui4( read_only image2d_t image, int2 byte_coord ); +uint8 __ovld __conv intel_sub_group_block_read_ui8( read_only image2d_t image, int2 byte_coord ); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +uint __ovld __conv intel_sub_group_block_read_ui( read_write image2d_t image, int2 byte_coord ); +uint2 __ovld __conv intel_sub_group_block_read_ui2( read_write image2d_t image, int2 byte_coord ); +uint4 __ovld __conv intel_sub_group_block_read_ui4( read_write image2d_t image, int2 byte_coord ); +uint8 __ovld __conv intel_sub_group_block_read_ui8( read_write image2d_t image, int2 byte_coord ); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +uint __ovld __conv intel_sub_group_block_read_ui( const __global uint* p ); +uint2 __ovld __conv intel_sub_group_block_read_ui2( const __global uint* p ); +uint4 __ovld __conv intel_sub_group_block_read_ui4( const __global uint* p ); +uint8 __ovld __conv intel_sub_group_block_read_ui8( const __global uint* p ); + +void __ovld __conv intel_sub_group_block_write_ui( read_only image2d_t image, int2 byte_coord, uint data ); +void __ovld __conv intel_sub_group_block_write_ui2( read_only image2d_t image, int2 byte_coord, uint2 data ); +void __ovld __conv intel_sub_group_block_write_ui4( read_only image2d_t image, int2 byte_coord, uint4 data ); +void __ovld __conv intel_sub_group_block_write_ui8( read_only image2d_t image, int2 byte_coord, uint8 data ); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +void __ovld __conv intel_sub_group_block_write_ui( read_write image2d_t image, int2 byte_coord, uint data ); +void __ovld __conv intel_sub_group_block_write_ui2( read_write image2d_t image, int2 byte_coord, uint2 data ); +void __ovld __conv intel_sub_group_block_write_ui4( read_write image2d_t image, int2 byte_coord, uint4 data ); +void __ovld __conv intel_sub_group_block_write_ui8( read_write image2d_t image, int2 byte_coord, uint8 data ); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +void __ovld __conv intel_sub_group_block_write_ui( __global uint* p, uint data ); +void __ovld __conv intel_sub_group_block_write_ui2( __global uint* p, uint2 data ); +void __ovld __conv intel_sub_group_block_write_ui4( __global uint* p, uint4 data ); +void __ovld __conv intel_sub_group_block_write_ui8( __global uint* p, uint8 data ); + +ushort __ovld __conv intel_sub_group_block_read_us( read_only image2d_t image, int2 coord ); +ushort2 __ovld __conv intel_sub_group_block_read_us2( read_only image2d_t image, int2 coord ); +ushort4 __ovld __conv intel_sub_group_block_read_us4( read_only image2d_t image, int2 coord ); +ushort8 __ovld __conv intel_sub_group_block_read_us8( read_only image2d_t image, int2 coord ); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +ushort __ovld __conv intel_sub_group_block_read_us(read_write image2d_t image, int2 coord); +ushort2 __ovld __conv intel_sub_group_block_read_us2(read_write image2d_t image, int2 coord); +ushort4 __ovld __conv intel_sub_group_block_read_us4(read_write image2d_t image, int2 coord); +ushort8 __ovld __conv intel_sub_group_block_read_us8(read_write image2d_t image, int2 coord); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +ushort __ovld __conv intel_sub_group_block_read_us( const __global ushort* p ); +ushort2 __ovld __conv intel_sub_group_block_read_us2( const __global ushort* p ); +ushort4 __ovld __conv intel_sub_group_block_read_us4( const __global ushort* p ); +ushort8 __ovld __conv intel_sub_group_block_read_us8( const __global ushort* p ); + +void __ovld __conv intel_sub_group_block_write_us(write_only image2d_t image, int2 coord, ushort data); +void __ovld __conv intel_sub_group_block_write_us2(write_only image2d_t image, int2 coord, ushort2 data); +void __ovld __conv intel_sub_group_block_write_us4(write_only image2d_t image, int2 coord, ushort4 data); +void __ovld __conv intel_sub_group_block_write_us8(write_only image2d_t image, int2 coord, ushort8 data); + +#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +void __ovld __conv intel_sub_group_block_write_us(read_write image2d_t image, int2 coord, ushort data); +void __ovld __conv intel_sub_group_block_write_us2(read_write image2d_t image, int2 coord, ushort2 data); +void __ovld __conv intel_sub_group_block_write_us4(read_write image2d_t image, int2 coord, ushort4 data); +void __ovld __conv intel_sub_group_block_write_us8(read_write image2d_t image, int2 coord, ushort8 data); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) + +void __ovld __conv intel_sub_group_block_write_us( __global ushort* p, ushort data ); +void __ovld __conv intel_sub_group_block_write_us2( __global ushort* p, ushort2 data ); +void __ovld __conv intel_sub_group_block_write_us4( __global ushort* p, ushort4 data ); +void __ovld __conv intel_sub_group_block_write_us8( __global ushort* p, ushort8 data ); +#endif // cl_intel_subgroups_short + #ifdef cl_amd_media_ops uint __ovld amd_bitalign(uint a, uint b, uint c); uint2 __ovld amd_bitalign(uint2 a, uint2 b, uint2 c); diff --git a/contrib/llvm/tools/clang/lib/Headers/stdbool.h b/contrib/llvm/tools/clang/lib/Headers/stdbool.h index 0467893f3403f..5cb66b55d02ab 100644 --- a/contrib/llvm/tools/clang/lib/Headers/stdbool.h +++ b/contrib/llvm/tools/clang/lib/Headers/stdbool.h @@ -32,12 +32,15 @@ #define true 1 #define false 0 #elif defined(__GNUC__) && !defined(__STRICT_ANSI__) -/* Define _Bool, bool, false, true as a GNU extension. */ +/* Define _Bool as a GNU extension. */ #define _Bool bool +#if __cplusplus < 201103L +/* For C++98, define bool, false, true as a GNU extension. */ #define bool bool #define false false #define true true #endif +#endif #define __bool_true_false_are_defined 1 diff --git a/contrib/llvm/tools/clang/lib/Headers/unwind.h b/contrib/llvm/tools/clang/lib/Headers/unwind.h index 4f74a3478740e..345fa4d0c1930 100644 --- a/contrib/llvm/tools/clang/lib/Headers/unwind.h +++ b/contrib/llvm/tools/clang/lib/Headers/unwind.h @@ -76,7 +76,13 @@ typedef intptr_t _sleb128_t; typedef uintptr_t _uleb128_t; struct _Unwind_Context; +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) +struct _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ +#else struct _Unwind_Exception; +typedef struct _Unwind_Exception _Unwind_Exception; +#endif typedef enum { _URC_NO_REASON = 0, #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ @@ -109,8 +115,42 @@ typedef enum { } _Unwind_Action; typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, - struct _Unwind_Exception *); + _Unwind_Exception *); +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) +typedef struct _Unwind_Control_Block _Unwind_Control_Block; +typedef uint32_t _Unwind_EHT_Header; + +struct _Unwind_Control_Block { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); + /* unwinder cache (private fields for the unwinder's use) */ + struct { + uint32_t reserved1; /* forced unwind stop function, 0 if not forced */ + uint32_t reserved2; /* personality routine */ + uint32_t reserved3; /* callsite */ + uint32_t reserved4; /* forced unwind stop argument */ + uint32_t reserved5; + } unwinder_cache; + /* propagation barrier cache (valid after phase 1) */ + struct { + uint32_t sp; + uint32_t bitpattern[5]; + } barrier_cache; + /* cleanup cache (preserved over cleanup) */ + struct { + uint32_t bitpattern[4]; + } cleanup_cache; + /* personality cache (for personality's benefit) */ + struct { + uint32_t fnstart; /* function start address */ + _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ + uint32_t additional; /* additional data */ + uint32_t reserved1; + } pr_cache; + long long int : 0; /* force alignment of next item to 8-byte boundary */ +} __attribute__((__aligned__(8))); +#else struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; @@ -120,23 +160,24 @@ struct _Unwind_Exception { * aligned". GCC has interpreted this to mean "use the maximum useful * alignment for the target"; so do we. */ } __attribute__((__aligned__)); +#endif typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action, _Unwind_Exception_Class, - struct _Unwind_Exception *, + _Unwind_Exception *, struct _Unwind_Context *, void *); -typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( - int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, - struct _Unwind_Context *); +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, _Unwind_Action, + _Unwind_Exception_Class, + _Unwind_Exception *, + struct _Unwind_Context *); typedef _Unwind_Personality_Fn __personality_routine; typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *); -#if defined(__arm__) && !defined(__APPLE__) - +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) typedef enum { _UVRSC_CORE = 0, /* integer register */ _UVRSC_VFP = 1, /* vfp */ @@ -158,14 +199,12 @@ typedef enum { _UVRSR_FAILED = 2 } _Unwind_VRS_Result; -#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) typedef uint32_t _Unwind_State; #define _US_VIRTUAL_UNWIND_FRAME ((_Unwind_State)0) #define _US_UNWIND_FRAME_STARTING ((_Unwind_State)1) #define _US_UNWIND_FRAME_RESUME ((_Unwind_State)2) #define _US_ACTION_MASK ((_Unwind_State)3) #define _US_FORCE_UNWIND ((_Unwind_State)8) -#endif _Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context, _Unwind_VRS_RegClass __regclass, @@ -224,13 +263,12 @@ _Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *); /* DWARF EH functions; currently not available on Darwin/ARM */ #if !defined(__APPLE__) || !defined(__arm__) - -_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *, - _Unwind_Stop_Fn, void *); -void _Unwind_DeleteException(struct _Unwind_Exception *); -void _Unwind_Resume(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *); +_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, + void *); +void _Unwind_DeleteException(_Unwind_Exception *); +void _Unwind_Resume(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *); #endif @@ -241,11 +279,11 @@ typedef struct SjLj_Function_Context *_Unwind_FunctionContext_t; void _Unwind_SjLj_Register(_Unwind_FunctionContext_t); void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t); -_Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *, +_Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, void *); -void _Unwind_SjLj_Resume(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *); +void _Unwind_SjLj_Resume(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *); void *_Unwind_FindEnclosingFunction(void *); diff --git a/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp b/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp index 92740b05703b5..bf52e2108baaf 100644 --- a/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp +++ b/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp @@ -68,7 +68,38 @@ struct CodegenNameGenerator::Implementation { return Name; } + enum ObjCKind { + ObjCClass, + ObjCMetaclass, + }; + + std::vector<std::string> getAllManglings(const ObjCContainerDecl *OCD) { + StringRef ClassName; + if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + else if (const auto *OID = dyn_cast<ObjCImplementationDecl>(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + + if (ClassName.empty()) + return {}; + + auto Mangle = [&](ObjCKind Kind, StringRef ClassName) -> std::string { + SmallString<40> Mangled; + auto Prefix = getClassSymbolPrefix(Kind, OCD->getASTContext()); + llvm::Mangler::getNameWithPrefix(Mangled, Prefix + ClassName, DL); + return Mangled.str(); + }; + + return { + Mangle(ObjCClass, ClassName), + Mangle(ObjCMetaclass, ClassName), + }; + } + std::vector<std::string> getAllManglings(const Decl *D) { + if (const auto *OCD = dyn_cast<ObjCContainerDecl>(D)) + return getAllManglings(OCD); + if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D))) return {}; @@ -135,12 +166,14 @@ private: } void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) { - OS << getClassSymbolPrefix(); + OS << getClassSymbolPrefix(ObjCClass, D->getASTContext()); OS << D->getObjCRuntimeNameAsString(); } - static StringRef getClassSymbolPrefix() { - return "OBJC_CLASS_$_"; + static StringRef getClassSymbolPrefix(ObjCKind Kind, const ASTContext &Context) { + if (Context.getLangOpts().ObjCRuntime.isGNUFamily()) + return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_"; + return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_"; } std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) { diff --git a/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp index e568c838b7b0f..918068a2405f7 100644 --- a/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp +++ b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp @@ -579,6 +579,7 @@ void getSourceTextOfDeclaration(const DeclInfo *ThisDecl, PrintingPolicy PPolicy(LangOpts); PPolicy.PolishForDeclaration = true; PPolicy.TerseOutput = true; + PPolicy.ConstantsAsWritten = true; ThisDecl->CurrentDecl->print(OS, PPolicy, /*Indentation*/0, /*PrintInstantiation*/false); } diff --git a/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp index 6bbd38102509f..ac34956b24840 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp @@ -427,6 +427,17 @@ public: return true; } + + bool VisitOffsetOfExpr(OffsetOfExpr *S) { + for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) { + const OffsetOfNode &Component = S->getComponent(I); + if (Component.getKind() == OffsetOfNode::Field) + IndexCtx.handleReference(Component.getField(), Component.getLocEnd(), + Parent, ParentDC, SymbolRoleSet(), {}); + // FIXME: Try to resolve dependent field references. + } + return true; + } }; } // anonymous namespace diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp index c5230c0f9acf8..e14750e046eb9 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp @@ -233,9 +233,8 @@ public: if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { if (CXXMD->isVirtual()) Roles |= (unsigned)SymbolRole::Dynamic; - for (auto I = CXXMD->begin_overridden_methods(), - E = CXXMD->end_overridden_methods(); I != E; ++I) { - Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); + for (const CXXMethodDecl *O : CXXMD->overridden_methods()) { + Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, O); } } gatherTemplatePseudoOverrides(D, Relations); @@ -267,6 +266,10 @@ public: TypeNameInfo->getTypeLoc().getLocStart(), Dtor->getParent(), Dtor->getDeclContext()); } + } else if (const auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) { + IndexCtx.handleReference(Guide->getDeducedTemplate()->getTemplatedDecl(), + Guide->getLocation(), Guide, + Guide->getDeclContext()); } // Template specialization arguments. if (const ASTTemplateArgumentListInfo *TemplateArgInfo = @@ -350,12 +353,10 @@ public: gatherTemplatePseudoOverrides(D, Relations); IndexCtx.indexTagDecl(D, Relations); } else { - auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); SmallVector<SymbolRelation, 1> Relations; gatherTemplatePseudoOverrides(D, Relations); - return IndexCtx.handleReference(D, D->getLocation(), Parent, - D->getLexicalDeclContext(), - SymbolRoleSet(), Relations); + return IndexCtx.handleDecl(D, D->getLocation(), SymbolRoleSet(), + Relations, D->getLexicalDeclContext()); } } return true; @@ -607,6 +608,24 @@ public: SymbolRoleSet()); } + bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { + TRY_DECL(D, IndexCtx.handleDecl(D)); + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + return true; + } + + bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { + TRY_DECL(D, IndexCtx.handleDecl(D)); + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + return true; + } + bool VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl *D) { // FIXME: Notify subsequent callbacks if info comes from implicit @@ -644,7 +663,6 @@ public: } bool VisitTemplateDecl(const TemplateDecl *D) { - // FIXME: Template parameters. // Index the default values for the template parameters. const NamedDecl *Parent = D->getTemplatedDecl(); @@ -661,7 +679,7 @@ public: } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) { if (TTPD->hasDefaultArgument()) handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, - /*DC=*/nullptr); + TP->getLexicalDeclContext()); } } } diff --git a/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp index 0dc3720208caf..03db0cd53f7a5 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp @@ -201,25 +201,22 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { Info.Properties |= (unsigned)SymbolProperty::UnitTest; break; } - case Decl::ObjCMethod: - if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) { - const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); - Info.Kind = SymbolKind::InstanceMethod; - if (MD->isPropertyAccessor()) { - if (MD->param_size()) - Info.SubKind = SymbolSubKind::AccessorSetter; - else - Info.SubKind = SymbolSubKind::AccessorGetter; - } - } else { - Info.Kind = SymbolKind::ClassMethod; + case Decl::ObjCMethod: { + const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); + Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod; + if (MD->isPropertyAccessor()) { + if (MD->param_size()) + Info.SubKind = SymbolSubKind::AccessorSetter; + else + Info.SubKind = SymbolSubKind::AccessorGetter; } Info.Lang = SymbolLanguage::ObjC; - if (isUnitTest(cast<ObjCMethodDecl>(D))) + if (isUnitTest(MD)) Info.Properties |= (unsigned)SymbolProperty::UnitTest; if (D->hasAttr<IBActionAttr>()) Info.Properties |= (unsigned)SymbolProperty::IBAnnotated; break; + } case Decl::ObjCProperty: Info.Kind = SymbolKind::InstanceProperty; Info.Lang = SymbolLanguage::ObjC; @@ -303,6 +300,18 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { Info.Kind = SymbolKind::TypeAlias; Info.Lang = SymbolLanguage::CXX; break; + case Decl::UnresolvedUsingTypename: + Info.Kind = SymbolKind::Using; + Info.SubKind = SymbolSubKind::UsingTypename; + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + break; + case Decl::UnresolvedUsingValue: + Info.Kind = SymbolKind::Using; + Info.SubKind = SymbolSubKind::UsingValue; + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + break; case Decl::Binding: Info.Kind = SymbolKind::Variable; Info.Lang = SymbolLanguage::CXX; @@ -451,6 +460,7 @@ StringRef index::getSymbolKindString(SymbolKind K) { case SymbolKind::Destructor: return "destructor"; case SymbolKind::ConversionFunction: return "coversion-func"; case SymbolKind::Parameter: return "param"; + case SymbolKind::Using: return "using"; } llvm_unreachable("invalid symbol kind"); } @@ -462,6 +472,8 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) { case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; case SymbolSubKind::AccessorGetter: return "acc-get"; case SymbolSubKind::AccessorSetter: return "acc-set"; + case SymbolSubKind::UsingTypename: return "using-typename"; + case SymbolSubKind::UsingValue: return "using-value"; } llvm_unreachable("invalid symbol subkind"); } diff --git a/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp index ae27ebe6ea4c0..c8ff3d72d4be1 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp @@ -126,8 +126,9 @@ public: return true; } - bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { - if (const TemplateSpecializationType *T = TL.getTypePtr()) { + template<typename TypeLocType> + bool HandleTemplateSpecializationTypeLoc(TypeLocType TL) { + if (const auto *T = TL.getTypePtr()) { if (IndexCtx.shouldIndexImplicitTemplateInsts()) { if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) IndexCtx.handleReference(RD, TL.getTemplateNameLoc(), @@ -141,6 +142,14 @@ public: return true; } + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + return HandleTemplateSpecializationTypeLoc(TL); + } + + bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) { + return HandleTemplateSpecializationTypeLoc(TL); + } + bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { const DependentNameType *DNT = TL.getTypePtr(); const NestedNameSpecifier *NNS = DNT->getQualifier(); diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp index 84d31200bab43..411657bf3dcdd 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp @@ -8,10 +8,11 @@ //===----------------------------------------------------------------------===// #include "clang/Index/IndexingAction.h" -#include "clang/Index/IndexDataConsumer.h" #include "IndexingContext.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Index/IndexDataConsumer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Serialization/ASTReader.h" @@ -42,16 +43,18 @@ bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD, namespace { class IndexASTConsumer : public ASTConsumer { + std::shared_ptr<Preprocessor> PP; IndexingContext &IndexCtx; public: - IndexASTConsumer(IndexingContext &IndexCtx) - : IndexCtx(IndexCtx) {} + IndexASTConsumer(std::shared_ptr<Preprocessor> PP, IndexingContext &IndexCtx) + : PP(std::move(PP)), IndexCtx(IndexCtx) {} protected: void Initialize(ASTContext &Context) override { IndexCtx.setASTContext(Context); IndexCtx.getDataConsumer().initialize(Context); + IndexCtx.getDataConsumer().setPreprocessor(PP); } bool HandleTopLevelDecl(DeclGroupRef DG) override { @@ -80,8 +83,10 @@ protected: : DataConsumer(std::move(dataConsumer)), IndexCtx(Opts, *DataConsumer) {} - std::unique_ptr<IndexASTConsumer> createIndexASTConsumer() { - return llvm::make_unique<IndexASTConsumer>(IndexCtx); + std::unique_ptr<IndexASTConsumer> + createIndexASTConsumer(CompilerInstance &CI) { + return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(), + IndexCtx); } void finish() { @@ -98,7 +103,7 @@ public: protected: std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { - return createIndexASTConsumer(); + return createIndexASTConsumer(CI); } void EndSourceFileAction() override { @@ -142,7 +147,7 @@ WrappingIndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::vector<std::unique_ptr<ASTConsumer>> Consumers; Consumers.push_back(std::move(OtherConsumer)); - Consumers.push_back(createIndexASTConsumer()); + Consumers.push_back(createIndexASTConsumer(CI)); return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } @@ -173,6 +178,7 @@ void index::indexASTUnit(ASTUnit &Unit, IndexingContext IndexCtx(Opts, *DataConsumer); IndexCtx.setASTContext(Unit.getASTContext()); DataConsumer->initialize(Unit.getASTContext()); + DataConsumer->setPreprocessor(Unit.getPreprocessorPtr()); indexTranslationUnit(Unit, IndexCtx); DataConsumer->finish(); } @@ -198,7 +204,7 @@ void index::indexModuleFile(serialization::ModuleFile &Mod, IndexCtx.setASTContext(Ctx); DataConsumer->initialize(Ctx); - for (const Decl *D :Reader.getModuleFileLevelDecls(Mod)) { + for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { IndexCtx.indexTopLevelDecl(D); } DataConsumer->finish(); diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp index addee691e8046..de9fe39df0310 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp @@ -231,8 +231,8 @@ static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, AST /// Whether the given NamedDecl should be skipped because it has no name. static bool shouldSkipNamelessDecl(const NamedDecl *ND) { - return ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && - !isa<ObjCCategoryDecl>(ND); + return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && + !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND); } static const Decl *adjustParent(const Decl *Parent) { diff --git a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp index 21054b099a8e7..3a06554b256c6 100644 --- a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp +++ b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp @@ -99,6 +99,8 @@ public: void VisitVarDecl(const VarDecl *D); void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); + void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); + void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); void VisitLinkageSpecDecl(const LinkageSpecDecl *D) { IgnoreResults = true; @@ -112,14 +114,6 @@ public: IgnoreResults = true; } - void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { - IgnoreResults = true; - } - - void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { - IgnoreResults = true; - } - bool ShouldGenerateLocation(const NamedDecl *D); bool isLocal(const NamedDecl *D) { @@ -609,6 +603,16 @@ bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) { return IgnoreResults; } +static void printQualifier(llvm::raw_ostream &Out, ASTContext &Ctx, NestedNameSpecifier *NNS) { + // FIXME: Encode the qualifier, don't just print it. + PrintingPolicy PO(Ctx.getLangOpts()); + PO.SuppressTagKeyword = true; + PO.SuppressUnwrittenScope = true; + PO.ConstantArraySizeAsWritten = false; + PO.AnonymousTagLocations = false; + NNS->print(Out, PO); +} + void USRGenerator::VisitType(QualType T) { // This method mangles in USR information for types. It can possibly // just reuse the naming-mangling logic used by codegen, although the @@ -676,6 +680,7 @@ void USRGenerator::VisitType(QualType T) { c = 'K'; break; case BuiltinType::Int128: c = 'J'; break; + case BuiltinType::Float16: case BuiltinType::Half: c = 'h'; break; case BuiltinType::Float: @@ -749,8 +754,12 @@ void USRGenerator::VisitType(QualType T) { if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { Out << 'F'; VisitType(FT->getReturnType()); - for (const auto &I : FT->param_types()) + Out << '('; + for (const auto &I : FT->param_types()) { + Out << '#'; VisitType(I); + } + Out << ')'; if (FT->isVariadic()) Out << '.'; return; @@ -797,13 +806,7 @@ void USRGenerator::VisitType(QualType T) { } if (const DependentNameType *DNT = T->getAs<DependentNameType>()) { Out << '^'; - // FIXME: Encode the qualifier, don't just print it. - PrintingPolicy PO(Ctx.getLangOpts()); - PO.SuppressTagKeyword = true; - PO.SuppressUnwrittenScope = true; - PO.ConstantArraySizeAsWritten = false; - PO.AnonymousTagLocations = false; - DNT->getQualifier()->print(Out, PO); + printQualifier(Out, Ctx, DNT->getQualifier()); Out << ':' << DNT->getIdentifier()->getName(); return; } @@ -817,6 +820,25 @@ void USRGenerator::VisitType(QualType T) { T = VT->getElementType(); continue; } + if (const auto *const AT = dyn_cast<ArrayType>(T)) { + Out << '{'; + switch (AT->getSizeModifier()) { + case ArrayType::Static: + Out << 's'; + break; + case ArrayType::Star: + Out << '*'; + break; + case ArrayType::Normal: + Out << 'n'; + break; + } + if (const auto *const CAT = dyn_cast<ConstantArrayType>(T)) + Out << CAT->getSize(); + + T = AT->getElementType(); + continue; + } // Unhandled type. Out << ' '; @@ -912,6 +934,26 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { } } +void USRGenerator::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + VisitDeclContext(D->getDeclContext()); + Out << "@UUV@"; + printQualifier(Out, D->getASTContext(), D->getQualifier()); + EmitDeclName(D); +} + +void USRGenerator::VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + VisitDeclContext(D->getDeclContext()); + Out << "@UUT@"; + printQualifier(Out, D->getASTContext(), D->getQualifier()); + Out << D->getName(); // Simple name. +} + + + //===----------------------------------------------------------------------===// // USR generation functions. //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp index 1ebcc0a1c657c..aa2588659ddfe 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp @@ -1,4 +1,4 @@ -//===--- HeaderSearch.cpp - Resolve Header File Locations ---===// +//===- HeaderSearch.cpp - Resolve Header File Locations -------------------===// // // The LLVM Compiler Infrastructure // @@ -12,25 +12,38 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/HeaderSearch.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Lex/DirectoryLookup.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderMap.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/LexDiagnostic.h" -#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleMap.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Capacity.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstddef> #include <cstdio> +#include <cstring> +#include <string> +#include <system_error> #include <utility> -#if defined(LLVM_ON_UNIX) -#include <limits.h> -#endif + using namespace clang; const IdentifierInfo * @@ -52,7 +65,7 @@ HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) { return ControllingMacro; } -ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {} +ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() = default; HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts, SourceManager &SourceMgr, DiagnosticsEngine &Diags, @@ -60,17 +73,7 @@ HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts, const TargetInfo *Target) : HSOpts(std::move(HSOpts)), Diags(Diags), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64), - ModMap(SourceMgr, Diags, LangOpts, Target, *this) { - AngledDirIdx = 0; - SystemDirIdx = 0; - NoCurDirSearch = false; - - ExternalLookup = nullptr; - ExternalSource = nullptr; - NumIncluded = 0; - NumMultiIncludeFileOptzn = 0; - NumFrameworkLookups = NumSubFrameworkLookups = 0; -} + ModMap(SourceMgr, Diags, LangOpts, Target, *this) {} HeaderSearch::~HeaderSearch() { // Delete headermaps. @@ -128,36 +131,40 @@ void HeaderSearch::getHeaderMapFileNames( Names.push_back(HM.first->getName()); } -std::string HeaderSearch::getModuleFileName(Module *Module) { +std::string HeaderSearch::getCachedModuleFileName(Module *Module) { const FileEntry *ModuleMap = getModuleMap().getModuleMapFileForUniquing(Module); - return getModuleFileName(Module->Name, ModuleMap->getName(), - /*UsePrebuiltPath*/false); + return getCachedModuleFileName(Module->Name, ModuleMap->getName()); } -std::string HeaderSearch::getModuleFileName(StringRef ModuleName, - StringRef ModuleMapPath, - bool UsePrebuiltPath) { - if (UsePrebuiltPath) { - if (HSOpts->PrebuiltModulePaths.empty()) - return std::string(); +std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName, + bool FileMapOnly) { + // First check the module name to pcm file map. + auto i (HSOpts->PrebuiltModuleFiles.find(ModuleName)); + if (i != HSOpts->PrebuiltModuleFiles.end()) + return i->second; - // Go though each prebuilt module path and try to find the pcm file. - for (const std::string &Dir : HSOpts->PrebuiltModulePaths) { - SmallString<256> Result(Dir); - llvm::sys::fs::make_absolute(Result); + if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty()) + return {}; - llvm::sys::path::append(Result, ModuleName + ".pcm"); - if (getFileMgr().getFile(Result.str())) - return Result.str().str(); - } - return std::string(); + // Then go through each prebuilt module directory and try to find the pcm + // file. + for (const std::string &Dir : HSOpts->PrebuiltModulePaths) { + SmallString<256> Result(Dir); + llvm::sys::fs::make_absolute(Result); + llvm::sys::path::append(Result, ModuleName + ".pcm"); + if (getFileMgr().getFile(Result.str())) + return Result.str().str(); } + return {}; +} +std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName, + StringRef ModuleMapPath) { // If we don't have a module cache path or aren't supposed to use one, we // can't do anything. if (getModuleCachePath().empty()) - return std::string(); + return {}; SmallString<256> Result(getModuleCachePath()); llvm::sys::fs::make_absolute(Result); @@ -177,7 +184,7 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName, Parent = "."; auto *Dir = FileMgr.getDirectory(Parent); if (!Dir) - return std::string(); + return {}; auto DirName = FileMgr.getCanonicalName(Dir); auto FileName = llvm::sys::path::filename(ModuleMapPath); @@ -376,7 +383,6 @@ const FileEntry *DirectoryLookup::LookupFile( Filename = StringRef(MappedName.begin(), MappedName.size()); HasBeenMapped = true; Result = HM->LookupFile(Filename, HS.getFileMgr()); - } else { Result = HS.getFileMgr().getFile(Dest); } @@ -587,7 +593,6 @@ void HeaderSearch::setTarget(const TargetInfo &Target) { ModMap.setTarget(Target); } - //===----------------------------------------------------------------------===// // Header File Location. //===----------------------------------------------------------------------===// @@ -954,7 +959,6 @@ LookupSubframeworkHeader(StringRef Filename, HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); if (!(FE = FileMgr.getFile(HeadersFilename, /*openFile=*/true))) { - // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" HeadersFilename = FrameworkName; HeadersFilename += "PrivateHeaders/"; @@ -1111,7 +1115,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, // FIXME: this is a workaround for the lack of proper modules-aware support // for #import / #pragma once - auto TryEnterImported = [&](void) -> bool { + auto TryEnterImported = [&]() -> bool { if (!ModulesEnabled) return false; // Ensure FileInfo bits are up to date. @@ -1444,7 +1448,6 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name, return ModMap.findModule(Name); } - HeaderSearch::LoadModuleMapResult HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem, bool IsFramework) { diff --git a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp index 61bcef8cb760e..830354ab23f0d 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp @@ -1,4 +1,4 @@ -//===--- Lexer.cpp - C Language Family Lexer ------------------------------===// +//===- Lexer.cpp - C Language Family Lexer --------------------------------===// // // The LLVM Compiler Infrastructure // @@ -15,17 +15,29 @@ #include "UnicodeCharSets.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/MultipleIncludeOpt.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Lex/Token.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/NativeFormatting.h" #include "llvm/Support/UnicodeCharRanges.h" #include <algorithm> #include <cassert> @@ -63,7 +75,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { // Lexer Class Implementation //===----------------------------------------------------------------------===// -void Lexer::anchor() { } +void Lexer::anchor() {} void Lexer::InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd) { @@ -120,31 +132,21 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) - : PreprocessorLexer(&PP, FID), - FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), - LangOpts(PP.getLangOpts()) { - + : PreprocessorLexer(&PP, FID), + FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), + LangOpts(PP.getLangOpts()) { InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(), InputFile->getBufferEnd()); resetExtendedTokenMode(); } -void Lexer::resetExtendedTokenMode() { - assert(PP && "Cannot reset token mode without a preprocessor"); - if (LangOpts.TraditionalCPP) - SetKeepWhitespaceMode(true); - else - SetCommentRetentionState(PP->getCommentRetentionState()); -} - /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, const char *BufStart, const char *BufPtr, const char *BufEnd) - : FileLoc(fileloc), LangOpts(langOpts) { - + : FileLoc(fileloc), LangOpts(langOpts) { InitLexer(BufStart, BufPtr, BufEnd); // We *are* in raw mode. @@ -159,6 +161,14 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile, : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile->getBufferStart(), FromFile->getBufferStart(), FromFile->getBufferEnd()) {} +void Lexer::resetExtendedTokenMode() { + assert(PP && "Cannot reset token mode without a preprocessor"); + if (LangOpts.TraditionalCPP) + SetKeepWhitespaceMode(true); + else + SetCommentRetentionState(PP->getCommentRetentionState()); +} + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method /// sets up. It returns a new'd Lexer that must be delete'd when done. @@ -209,30 +219,39 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc, return L; } -/// Stringify - Convert the specified string into a C string, with surrounding -/// ""'s, and with escaped \ and " characters. +template <typename T> static void StringifyImpl(T &Str, char Quote) { + typename T::size_type i = 0, e = Str.size(); + while (i < e) { + if (Str[i] == '\\' || Str[i] == Quote) { + Str.insert(Str.begin() + i, '\\'); + i += 2; + ++e; + } else if (Str[i] == '\n' || Str[i] == '\r') { + // Replace '\r\n' and '\n\r' to '\\' followed by 'n'. + if ((i < e - 1) && (Str[i + 1] == '\n' || Str[i + 1] == '\r') && + Str[i] != Str[i + 1]) { + Str[i] = '\\'; + Str[i + 1] = 'n'; + } else { + // Replace '\n' and '\r' to '\\' followed by 'n'. + Str[i] = '\\'; + Str.insert(Str.begin() + i + 1, 'n'); + ++e; + } + i += 2; + } else + ++i; + } +} + std::string Lexer::Stringify(StringRef Str, bool Charify) { std::string Result = Str; char Quote = Charify ? '\'' : '"'; - for (unsigned i = 0, e = Result.size(); i != e; ++i) { - if (Result[i] == '\\' || Result[i] == Quote) { - Result.insert(Result.begin()+i, '\\'); - ++i; ++e; - } - } + StringifyImpl(Result, Quote); return Result; } -/// Stringify - Convert the specified string into a C string by escaping '\' -/// and " characters. This does not add surrounding ""'s to the string. -void Lexer::Stringify(SmallVectorImpl<char> &Str) { - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - if (Str[i] == '\\' || Str[i] == '"') { - Str.insert(Str.begin()+i, '\\'); - ++i; ++e; - } - } -} +void Lexer::Stringify(SmallVectorImpl<char> &Str) { StringifyImpl(Str, '"'); } //===----------------------------------------------------------------------===// // Token Spelling @@ -307,7 +326,7 @@ StringRef Lexer::getSpelling(SourceLocation loc, StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) { if (invalid) *invalid = true; - return StringRef(); + return {}; } const char *tokenBegin = file.data() + locInfo.second; @@ -345,7 +364,7 @@ std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr, if (Invalid) *Invalid = CharDataInvalid; if (CharDataInvalid) - return std::string(); + return {}; // If this token contains nothing interesting, return it directly. if (!Tok.needsCleaning()) @@ -367,7 +386,7 @@ std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr, /// to point to a constant buffer with the data already in it (avoiding a /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. -unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer, +unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); @@ -463,19 +482,15 @@ static const char *findBeginningOfLine(StringRef Buffer, unsigned Offset) { const char *BufStart = Buffer.data(); if (Offset >= Buffer.size()) return nullptr; - const char *StrData = BufStart + Offset; - - if (StrData[0] == '\n' || StrData[0] == '\r') - return StrData; - const char *LexStart = StrData; - while (LexStart != BufStart) { - if (LexStart[0] == '\n' || LexStart[0] == '\r') { + const char *LexStart = BufStart + Offset; + for (; LexStart != BufStart; --LexStart) { + if (isVerticalWhitespace(LexStart[0]) && + !Lexer::isNewLineEscaped(BufStart, LexStart)) { + // LexStart should point at first character of logical line. ++LexStart; break; } - - --LexStart; } return LexStart; } @@ -487,7 +502,7 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc, std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); if (LocInfo.first.isInvalid()) return Loc; - + bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) @@ -499,31 +514,31 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc, const char *LexStart = findBeginningOfLine(Buffer, LocInfo.second); if (!LexStart || LexStart == StrData) return Loc; - + // Create a lexer starting at the beginning of this token. SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second); Lexer TheLexer(LexerStartLoc, LangOpts, Buffer.data(), LexStart, Buffer.end()); TheLexer.SetCommentRetentionState(true); - + // Lex tokens until we find the token that contains the source location. Token TheTok; do { TheLexer.LexFromRawLexer(TheTok); - + if (TheLexer.getBufferLocation() > StrData) { // Lexing this token has taken the lexer past the source location we're // looking for. If the current token encompasses our source location, // return the beginning of that token. if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData) return TheTok.getLocation(); - + // We ended up skipping over the source location entirely, which means // that it points into whitespace. We're done here. break; } } while (TheTok.getKind() != tok::eof); - + // We've passed our source location; just return the original source location. return Loc; } @@ -531,34 +546,34 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc, SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { - if (Loc.isFileID()) - return getBeginningOfFileToken(Loc, SM, LangOpts); - - if (!SM.isMacroArgExpansion(Loc)) - return Loc; + if (Loc.isFileID()) + return getBeginningOfFileToken(Loc, SM, LangOpts); + + if (!SM.isMacroArgExpansion(Loc)) + return Loc; - SourceLocation FileLoc = SM.getSpellingLoc(Loc); - SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts); - std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc); - std::pair<FileID, unsigned> BeginFileLocInfo - = SM.getDecomposedLoc(BeginFileLoc); - assert(FileLocInfo.first == BeginFileLocInfo.first && - FileLocInfo.second >= BeginFileLocInfo.second); - return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second); + SourceLocation FileLoc = SM.getSpellingLoc(Loc); + SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts); + std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc); + std::pair<FileID, unsigned> BeginFileLocInfo = + SM.getDecomposedLoc(BeginFileLoc); + assert(FileLocInfo.first == BeginFileLocInfo.first && + FileLocInfo.second >= BeginFileLocInfo.second); + return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second); } namespace { - enum PreambleDirectiveKind { - PDK_Skipped, - PDK_Unknown - }; +enum PreambleDirectiveKind { + PDK_Skipped, + PDK_Unknown +}; -} // end anonymous namespace +} // namespace -std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, - const LangOptions &LangOpts, - unsigned MaxLines) { +PreambleBounds Lexer::ComputePreamble(StringRef Buffer, + const LangOptions &LangOpts, + unsigned MaxLines) { // Create a lexer starting at the beginning of the file. Note that we use a // "fake" file source location at offset 1 so that the lexer will track our // position within the file. @@ -568,9 +583,6 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, Buffer.end()); TheLexer.SetCommentRetentionState(true); - // StartLoc will differ from FileLoc if there is a BOM that was skipped. - SourceLocation StartLoc = TheLexer.getSourceLocation(); - bool InPreprocessorDirective = false; Token TheTok; SourceLocation ActiveCommentLoc; @@ -599,17 +611,17 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, if (TheTok.getKind() == tok::eof) { break; } - + // If we haven't hit the end of the preprocessor directive, skip this // token. if (!TheTok.isAtStartOfLine()) continue; - + // We've passed the end of the preprocessor directive, and will look // at this token again below. InPreprocessorDirective = false; } - + // Keep track of the # of lines in the preamble. if (TheTok.isAtStartOfLine()) { unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset; @@ -626,13 +638,13 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, ActiveCommentLoc = TheTok.getLocation(); continue; } - + if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) { - // This is the start of a preprocessor directive. + // This is the start of a preprocessor directive. Token HashTok = TheTok; InPreprocessorDirective = true; ActiveCommentLoc = SourceLocation(); - + // Figure out which directive this is. Since we're lexing raw tokens, // we don't have an identifier table available. Instead, just look at // the raw identifier to recognize and categorize preprocessor directives. @@ -672,7 +684,7 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, break; } } - + // We only end up here if we didn't recognize the preprocessor // directive or it was one that can't occur in the preamble at this // point. Roll back the current token to the location of the '#'. @@ -685,14 +697,14 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer, // the preamble. break; } while (true); - + SourceLocation End; if (ActiveCommentLoc.isValid()) End = ActiveCommentLoc; // don't truncate a decl comment. else End = TheTok.getLocation(); - return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(), + return PreambleBounds(End.getRawEncoding() - FileLoc.getRawEncoding(), TheTok.isAtStartOfLine()); } @@ -707,13 +719,13 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, // trigraphs. bool Invalid = false; const char *TokPtr = SM.getCharacterData(TokStart, &Invalid); - + // If they request the first char of the token, we're trivially done. if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))) return TokStart; - + unsigned PhysOffset = 0; - + // The usual case is that tokens don't contain anything interesting. Skip // over the uninteresting characters. If a token only consists of simple // chars, this method is extremely fast. @@ -724,7 +736,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, --CharNo; ++PhysOffset; } - + // If we have a character that may be a trigraph or escaped newline, use a // lexer to parse it correctly. for (; CharNo; --CharNo) { @@ -733,14 +745,14 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, TokPtr += Size; PhysOffset += Size; } - + // Final detail: if we end up on an escaped newline, we want to return the // location of the actual byte of the token. For example foo\<newline>bar // advanced by 3 should return the location of b, not of \\. One compounding // detail of this is that the escape may be made by a trigraph. if (!Lexer::isObviouslySimpleCharacter(*TokPtr)) PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; - + return TokStart.getLocWithOffset(PhysOffset); } @@ -763,11 +775,11 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts) { if (Loc.isInvalid()) - return SourceLocation(); + return {}; if (Loc.isMacroID()) { if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc)) - return SourceLocation(); // Points inside the macro expansion. + return {}; // Points inside the macro expansion. } unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts); @@ -775,7 +787,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, Len = Len - Offset; else return Loc; - + return Loc.getLocWithOffset(Len); } @@ -838,7 +850,7 @@ static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range, if (Range.isTokenRange()) { End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts); if (End.isInvalid()) - return CharSourceRange(); + return {}; } // Break down the source locations. @@ -846,12 +858,12 @@ static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range, unsigned BeginOffs; std::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin); if (FID.isInvalid()) - return CharSourceRange(); + return {}; unsigned EndOffs; if (!SM.isInFileID(End, FID, &EndOffs) || BeginOffs > EndOffs) - return CharSourceRange(); + return {}; return CharSourceRange::getCharRange(Begin, End); } @@ -862,14 +874,14 @@ CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range, SourceLocation Begin = Range.getBegin(); SourceLocation End = Range.getEnd(); if (Begin.isInvalid() || End.isInvalid()) - return CharSourceRange(); + return {}; if (Begin.isFileID() && End.isFileID()) return makeRangeFromFileLocs(Range, SM, LangOpts); if (Begin.isMacroID() && End.isFileID()) { if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin)) - return CharSourceRange(); + return {}; Range.setBegin(Begin); return makeRangeFromFileLocs(Range, SM, LangOpts); } @@ -879,7 +891,7 @@ CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range, &End)) || (Range.isCharRange() && !isAtStartOfMacroExpansion(End, SM, LangOpts, &End))) - return CharSourceRange(); + return {}; Range.setEnd(End); return makeRangeFromFileLocs(Range, SM, LangOpts); } @@ -900,13 +912,13 @@ CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range, const SrcMgr::SLocEntry &BeginEntry = SM.getSLocEntry(SM.getFileID(Begin), &Invalid); if (Invalid) - return CharSourceRange(); + return {}; if (BeginEntry.getExpansion().isMacroArgExpansion()) { const SrcMgr::SLocEntry &EndEntry = SM.getSLocEntry(SM.getFileID(End), &Invalid); if (Invalid) - return CharSourceRange(); + return {}; if (EndEntry.getExpansion().isMacroArgExpansion() && BeginEntry.getExpansion().getExpansionLocStart() == @@ -917,7 +929,7 @@ CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range, } } - return CharSourceRange(); + return {}; } StringRef Lexer::getSourceText(CharSourceRange Range, @@ -927,21 +939,21 @@ StringRef Lexer::getSourceText(CharSourceRange Range, Range = makeFileCharRange(Range, SM, LangOpts); if (Range.isInvalid()) { if (Invalid) *Invalid = true; - return StringRef(); + return {}; } // Break down the source location. std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin()); if (beginInfo.first.isInvalid()) { if (Invalid) *Invalid = true; - return StringRef(); + return {}; } unsigned EndOffs; if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) || beginInfo.second > EndOffs) { if (Invalid) *Invalid = true; - return StringRef(); + return {}; } // Try to the load the file buffer. @@ -949,7 +961,7 @@ StringRef Lexer::getSourceText(CharSourceRange Range, StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp); if (invalidTemp) { if (Invalid) *Invalid = true; - return StringRef(); + return {}; } if (Invalid) *Invalid = false; @@ -972,7 +984,7 @@ StringRef Lexer::getImmediateMacroName(SourceLocation Loc, // For macro arguments we need to check that the argument did not come // from an inner macro, e.g: "MAC1( MAC2(foo) )" - + // Loc points to the argument id of the macro definition, move to the // macro expansion. Loc = SM.getImmediateExpansionRange(Loc).first; @@ -1013,7 +1025,7 @@ StringRef Lexer::getImmediateMacroNameForDiagnostics( // If the macro's spelling has no FileID, then it's actually a token paste // or stringization (or similar) and not a macro at all. if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc)))) - return StringRef(); + return {}; // Find the spelling location of the start of the non-argument expansion // range. This is where the macro name was spelled in order to begin @@ -1032,20 +1044,40 @@ bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) { return isIdentifierBody(c, LangOpts.DollarIdents); } +bool Lexer::isNewLineEscaped(const char *BufferStart, const char *Str) { + assert(isVerticalWhitespace(Str[0])); + if (Str - 1 < BufferStart) + return false; + + if ((Str[0] == '\n' && Str[-1] == '\r') || + (Str[0] == '\r' && Str[-1] == '\n')) { + if (Str - 2 < BufferStart) + return false; + --Str; + } + --Str; + + // Rewind to first non-space character: + while (Str > BufferStart && isHorizontalWhitespace(*Str)) + --Str; + + return *Str == '\\'; +} + StringRef Lexer::getIndentationForLine(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid() || Loc.isMacroID()) - return ""; + return {}; std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); if (LocInfo.first.isInvalid()) - return ""; + return {}; bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) - return ""; + return {}; const char *Line = findBeginningOfLine(Buffer, LocInfo.second); if (!Line) - return ""; + return {}; StringRef Rest = Buffer.substr(Line - Buffer.data()); size_t NumWhitespaceChars = Rest.find_first_not_of(" \t"); return NumWhitespaceChars == StringRef::npos @@ -1199,18 +1231,12 @@ const char *Lexer::SkipEscapedNewLines(const char *P) { } } -/// \brief Checks that the given token is the first token that occurs after the -/// given location (this excludes comments and whitespace). Returns the location -/// immediately after the specified token. If the token is not found or the -/// location is inside a macro, the returned source location will be invalid. -SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, - tok::TokenKind TKind, - const SourceManager &SM, - const LangOptions &LangOpts, - bool SkipTrailingWhitespaceAndNewLine) { +Optional<Token> Lexer::findNextToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { if (Loc.isMacroID()) { if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc)) - return SourceLocation(); + return None; } Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); @@ -1221,7 +1247,7 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, bool InvalidTemp = false; StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp); if (InvalidTemp) - return SourceLocation(); + return None; const char *TokenBegin = File.data() + LocInfo.second; @@ -1231,15 +1257,25 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, // Find the token. Token Tok; lexer.LexFromRawLexer(Tok); - if (Tok.isNot(TKind)) - return SourceLocation(); - SourceLocation TokenLoc = Tok.getLocation(); + return Tok; +} + +/// \brief Checks that the given token is the first token that occurs after the +/// given location (this excludes comments and whitespace). Returns the location +/// immediately after the specified token. If the token is not found or the +/// location is inside a macro, the returned source location will be invalid. +SourceLocation Lexer::findLocationAfterToken( + SourceLocation Loc, tok::TokenKind TKind, const SourceManager &SM, + const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine) { + Optional<Token> Tok = findNextToken(Loc, SM, LangOpts); + if (!Tok || Tok->isNot(TKind)) + return {}; + SourceLocation TokenLoc = Tok->getLocation(); // Calculate how much whitespace needs to be skipped if any. unsigned NumWhitespaceChars = 0; if (SkipTrailingWhitespaceAndNewLine) { - const char *TokenEnd = SM.getCharacterData(TokenLoc) + - Tok.getLength(); + const char *TokenEnd = SM.getCharacterData(TokenLoc) + Tok->getLength(); unsigned char C = *TokenEnd; while (isHorizontalWhitespace(C)) { C = *(++TokenEnd); @@ -1256,7 +1292,7 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, } } - return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars); + return TokenLoc.getLocWithOffset(Tok->getLength() + NumWhitespaceChars); } /// getCharAndSizeSlow - Peek a single 'character' from the specified buffer, @@ -1274,7 +1310,6 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, /// /// NOTE: When this method is updated, getCharAndSizeSlowNoWarn (below) should /// be updated to match. -/// char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok) { // If we have a slash, look for an escaped newline. @@ -1378,9 +1413,9 @@ Slash: // Helper methods for lexing. //===----------------------------------------------------------------------===// -/// \brief Routine that indiscriminately skips bytes in the source file. -void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) { - BufferPtr += Bytes; +/// \brief Routine that indiscriminately sets the offset into the source file. +void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) { + BufferPtr = BufferStart + Offset; if (BufferPtr > BufferEnd) BufferPtr = BufferEnd; // FIXME: What exactly does the StartOfLine bit mean? There are two @@ -1466,6 +1501,75 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C, } } +/// After encountering UTF-8 character C and interpreting it as an identifier +/// character, check whether it's a homoglyph for a common non-identifier +/// source character that is unlikely to be an intentional identifier +/// character and warn if so. +static void maybeDiagnoseUTF8Homoglyph(DiagnosticsEngine &Diags, uint32_t C, + CharSourceRange Range) { + // FIXME: Handle Unicode quotation marks (smart quotes, fullwidth quotes). + struct HomoglyphPair { + uint32_t Character; + char LooksLike; + bool operator<(HomoglyphPair R) const { return Character < R.Character; } + }; + static constexpr HomoglyphPair SortedHomoglyphs[] = { + {U'\u01c3', '!'}, // LATIN LETTER RETROFLEX CLICK + {U'\u037e', ';'}, // GREEK QUESTION MARK + {U'\u2212', '-'}, // MINUS SIGN + {U'\u2215', '/'}, // DIVISION SLASH + {U'\u2216', '\\'}, // SET MINUS + {U'\u2217', '*'}, // ASTERISK OPERATOR + {U'\u2223', '|'}, // DIVIDES + {U'\u2227', '^'}, // LOGICAL AND + {U'\u2236', ':'}, // RATIO + {U'\u223c', '~'}, // TILDE OPERATOR + {U'\ua789', ':'}, // MODIFIER LETTER COLON + {U'\uff01', '!'}, // FULLWIDTH EXCLAMATION MARK + {U'\uff03', '#'}, // FULLWIDTH NUMBER SIGN + {U'\uff04', '$'}, // FULLWIDTH DOLLAR SIGN + {U'\uff05', '%'}, // FULLWIDTH PERCENT SIGN + {U'\uff06', '&'}, // FULLWIDTH AMPERSAND + {U'\uff08', '('}, // FULLWIDTH LEFT PARENTHESIS + {U'\uff09', ')'}, // FULLWIDTH RIGHT PARENTHESIS + {U'\uff0a', '*'}, // FULLWIDTH ASTERISK + {U'\uff0b', '+'}, // FULLWIDTH ASTERISK + {U'\uff0c', ','}, // FULLWIDTH COMMA + {U'\uff0d', '-'}, // FULLWIDTH HYPHEN-MINUS + {U'\uff0e', '.'}, // FULLWIDTH FULL STOP + {U'\uff0f', '/'}, // FULLWIDTH SOLIDUS + {U'\uff1a', ':'}, // FULLWIDTH COLON + {U'\uff1b', ';'}, // FULLWIDTH SEMICOLON + {U'\uff1c', '<'}, // FULLWIDTH LESS-THAN SIGN + {U'\uff1d', '='}, // FULLWIDTH EQUALS SIGN + {U'\uff1e', '>'}, // FULLWIDTH GREATER-THAN SIGN + {U'\uff1f', '?'}, // FULLWIDTH QUESTION MARK + {U'\uff20', '@'}, // FULLWIDTH COMMERCIAL AT + {U'\uff3b', '['}, // FULLWIDTH LEFT SQUARE BRACKET + {U'\uff3c', '\\'}, // FULLWIDTH REVERSE SOLIDUS + {U'\uff3d', ']'}, // FULLWIDTH RIGHT SQUARE BRACKET + {U'\uff3e', '^'}, // FULLWIDTH CIRCUMFLEX ACCENT + {U'\uff5b', '{'}, // FULLWIDTH LEFT CURLY BRACKET + {U'\uff5c', '|'}, // FULLWIDTH VERTICAL LINE + {U'\uff5d', '}'}, // FULLWIDTH RIGHT CURLY BRACKET + {U'\uff5e', '~'}, // FULLWIDTH TILDE + {0, 0} + }; + auto Homoglyph = + std::lower_bound(std::begin(SortedHomoglyphs), + std::end(SortedHomoglyphs) - 1, HomoglyphPair{C, '\0'}); + if (Homoglyph->Character == C) { + llvm::SmallString<5> CharBuf; + { + llvm::raw_svector_ostream CharOS(CharBuf); + llvm::write_hex(CharOS, C, llvm::HexPrintStyle::Upper, 4); + } + const char LooksLikeStr[] = {Homoglyph->LooksLike, 0}; + Diags.Report(Range.getBegin(), diag::warn_utf8_symbol_homoglyph) + << Range << CharBuf << LooksLikeStr; + } +} + bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, Token &Result) { const char *UCNPtr = CurPtr + Size; @@ -1500,10 +1604,13 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { !isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts)) return false; - if (!isLexingRawMode()) + if (!isLexingRawMode()) { maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); + maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), CodePoint, + makeCharRange(*this, CurPtr, UnicodePtr)); + } CurPtr = UnicodePtr; return true; @@ -1569,7 +1676,6 @@ FinishIdentifier: CurPtr = ConsumeChar(CurPtr, Size, Result); C = getCharAndSize(CurPtr, Size); continue; - } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { C = getCharAndSize(CurPtr, Size); continue; @@ -1632,7 +1738,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { if (!LangOpts.C99) { if (!isHexaLiteral(BufferPtr, LangOpts)) IsHexFloat = false; - else if (!getLangOpts().CPlusPlus1z && + else if (!getLangOpts().CPlusPlus17 && std::find(BufferPtr, CurPtr, '_') != CurPtr) IsHexFloat = false; } @@ -1778,7 +1884,7 @@ bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr, // getAndAdvanceChar. if (C == '\\') C = getAndAdvanceChar(CurPtr, Result); - + if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. if (!isLexingRawMode() && !LangOpts.AsmPreprocessor) @@ -1786,7 +1892,7 @@ bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr, FormTokenWithChars(Result, CurPtr-1, tok::unknown); return true; } - + if (C == 0) { if (isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); @@ -2000,7 +2106,6 @@ bool Lexer::LexCharConstant(Token &Result, const char *CurPtr, /// Update BufferPtr to point to the next non-whitespace character and return. /// /// This method forms a token and returns true if KeepWhitespaceMode is enabled. -/// bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr, bool &TokAtPhysicalStartOfLine) { // Whitespace - Skip it, then return the token after the whitespace. @@ -2131,7 +2236,8 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, // If we read multiple characters, and one of those characters was a \r or // \n, then we had an escaped newline within the comment. Emit diagnostic // unless the next line is also a // comment. - if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') { + if (CurPtr != OldPtr + 1 && C != '/' && + (CurPtr == BufferEnd + 1 || CurPtr[0] != '/')) { for (; OldPtr != CurPtr; ++OldPtr) if (OldPtr[0] == '\n' || OldPtr[0] == '\r') { // Okay, we found a // comment that ends in a newline, if the next @@ -2214,7 +2320,7 @@ bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) { std::string Spelling = PP->getSpelling(Result, &Invalid); if (Invalid) return true; - + assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?"); Spelling[1] = '*'; // Change prefix to "/*". Spelling += "*/"; // add suffix. @@ -2540,7 +2646,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { resetExtendedTokenMode(); return true; // Have a token. } - + // If we are in raw mode, return this event as an EOF token. Let the caller // that put us in raw mode handle the event. if (isLexingRawMode()) { @@ -2549,7 +2655,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { FormTokenWithChars(Result, BufferEnd, tok::eof); return true; } - + if (PP->isRecordingPreamble() && PP->isInPrimaryFile()) { PP->setRecordedPreambleConditionalStack(ConditionalStack); ConditionalStack.clear(); @@ -2661,7 +2767,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { if (CurPtr != BufferStart && CurPtr[-1] != '\n' && CurPtr[-1] != '\r') return false; - + // Check to see if we have <<<<<<< or >>>>. if (!StringRef(CurPtr, BufferEnd - CurPtr).startswith("<<<<<<<") && !StringRef(CurPtr, BufferEnd - CurPtr).startswith(">>>> ")) @@ -2671,7 +2777,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { // it. if (CurrentConflictMarkerState || isLexingRawMode()) return false; - + ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce; // Check to see if there is an ending marker somewhere in the buffer at the @@ -2681,7 +2787,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { // Diagnose this, and ignore to the end of line. Diag(CurPtr, diag::err_conflict_marker); CurrentConflictMarkerState = Kind; - + // Skip ahead to the end of line. We know this exists because the // end-of-conflict marker starts with \r or \n. while (*CurPtr != '\r' && *CurPtr != '\n') { @@ -2691,7 +2797,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { BufferPtr = CurPtr; return true; } - + // No end of conflict marker found. return false; } @@ -2705,35 +2811,35 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { if (CurPtr != BufferStart && CurPtr[-1] != '\n' && CurPtr[-1] != '\r') return false; - + // If we have a situation where we don't care about conflict markers, ignore // it. if (!CurrentConflictMarkerState || isLexingRawMode()) return false; - + // Check to see if we have the marker (4 characters in a row). for (unsigned i = 1; i != 4; ++i) if (CurPtr[i] != CurPtr[0]) return false; - + // If we do have it, search for the end of the conflict marker. This could // fail if it got skipped with a '#if 0' or something. Note that CurPtr might // be the end of conflict marker. if (const char *End = FindConflictEnd(CurPtr, BufferEnd, CurrentConflictMarkerState)) { CurPtr = End; - + // Skip ahead to the end of line. while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n') ++CurPtr; - + BufferPtr = CurPtr; - + // No longer in the conflict marker. CurrentConflictMarkerState = CMK_None; return true; } - + return false; } @@ -2872,7 +2978,6 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, } return 0; - } else if (CodePoint >= 0xD800 && CodePoint <= 0xDFFF) { // C++03 allows UCNs representing surrogate characters. C99 and C++11 don't. // We don't use isLexingRawMode() here because we need to diagnose bad @@ -3042,7 +3147,7 @@ LexNextToken: // We know the lexer hasn't changed, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; - + case 26: // DOS & CP/M EOF: "^Z". // If we're in Microsoft extensions mode, treat this as end of file. if (LangOpts.MicrosoftExt) { @@ -3054,9 +3159,12 @@ LexNextToken: // If Microsoft extensions are disabled, this is just random garbage. Kind = tok::unknown; break; - - case '\n': + case '\r': + if (CurPtr[0] == '\n') + Char = getAndAdvanceChar(CurPtr, Result); + LLVM_FALLTHROUGH; + case '\n': // If we are inside a preprocessor directive and we see the end of line, // we know we are done with the directive, so return an EOD token. if (ParsingPreprocessorDirective) { @@ -3114,7 +3222,7 @@ LexNextToken: // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; - + // C99 6.4.4.1: Integer Constants. // C99 6.4.4.2: Floating Constants. case '0': case '1': case '2': case '3': case '4': @@ -3157,7 +3265,7 @@ LexNextToken: ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::utf8_string_literal); - if (Char2 == '\'' && LangOpts.CPlusPlus1z) + if (Char2 == '\'' && LangOpts.CPlusPlus17) return LexCharConstant( Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), @@ -3501,6 +3609,24 @@ LexNextToken: Kind = tok::lessless; } } else if (Char == '=') { + char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); + if (After == '>') { + if (getLangOpts().CPlusPlus2a) { + if (!isLexingRawMode()) + Diag(BufferPtr, diag::warn_cxx17_compat_spaceship); + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + Kind = tok::spaceship; + break; + } + // Suggest adding a space between the '<=' and the '>' to avoid a + // change in semantics if this turns up in C++ <=17 mode. + if (getLangOpts().CPlusPlus && !isLexingRawMode()) { + Diag(BufferPtr, diag::warn_cxx2a_compat_spaceship) + << FixItHint::CreateInsertion( + getSourceLocation(CurPtr + SizeTmp, SizeTmp2), " "); + } + } CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessequal; } else if (LangOpts.Digraphs && Char == ':') { // '<:' -> '[' @@ -3526,7 +3652,8 @@ LexNextToken: } else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::l_brace; - } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) { + } else if (Char == '#' && /*Not a trigraph*/ SizeTmp == 1 && + lexEditorPlaceholder(Result, CurPtr)) { return true; } else { Kind = tok::less; @@ -3594,7 +3721,9 @@ LexNextToken: if (LangOpts.Digraphs && Char == '>') { Kind = tok::r_square; // ':>' -> ']' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (LangOpts.CPlusPlus && Char == ':') { + } else if ((LangOpts.CPlusPlus || + LangOpts.DoubleSquareBracketAttributes) && + Char == ':') { Kind = tok::coloncolon; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { @@ -3610,7 +3739,7 @@ LexNextToken: // If this is '====' and we're in a conflict marker, ignore it. if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1)) goto LexNextToken; - + Kind = tok::equalequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { @@ -3681,6 +3810,7 @@ LexNextToken: // We can't just reset CurPtr to BufferPtr because BufferPtr may point to // an escaped newline. --CurPtr; + const char *UTF8StartPtr = CurPtr; llvm::ConversionResult Status = llvm::convertUTF8Sequence((const llvm::UTF8 **)&CurPtr, (const llvm::UTF8 *)BufferEnd, @@ -3695,9 +3825,12 @@ LexNextToken: // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } + if (!isLexingRawMode()) + maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), CodePoint, + makeCharRange(*this, UTF8StartPtr, CurPtr)); return LexUnicode(Result, CodePoint, CurPtr); } - + if (isLexingRawMode() || ParsingPreprocessorDirective || PP->isPreprocessedOutput()) { ++CurPtr; diff --git a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp index a598a467816a8..cbec5e6b63856 100644 --- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp @@ -544,6 +544,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isHalf = false; isFloat = false; isImaginary = false; + isFloat16 = false; isFloat128 = false; MicrosoftInteger = 0; hadError = false; @@ -588,6 +589,13 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, if (!isFPConstant) break; // Error for integer constant. if (isHalf || isFloat || isLong || isFloat128) break; // HF, FF, LF, QF invalid. + + if (s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') { + s += 2; // success, eat up 2 characters. + isFloat16 = true; + continue; + } + isFloat = true; continue; // Success. case 'q': // FP Suffix for "__float128" @@ -658,9 +666,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, break; } } - // "i", "if", and "il" are user-defined suffixes in C++1y. - if (*s == 'i' && PP.getLangOpts().CPlusPlus14) - break; // fall through. case 'j': case 'J': @@ -672,35 +677,35 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, break; } - if (s != ThisTokEnd) { + // "i", "if", and "il" are user-defined suffixes in C++1y. + if (s != ThisTokEnd || isImaginary) { // FIXME: Don't bother expanding UCNs if !tok.hasUCN(). expandUCNs(UDSuffixBuf, StringRef(SuffixBegin, ThisTokEnd - SuffixBegin)); if (isValidUDSuffix(PP.getLangOpts(), UDSuffixBuf)) { - // Any suffix pieces we might have parsed are actually part of the - // ud-suffix. - isLong = false; - isUnsigned = false; - isLongLong = false; - isFloat = false; - isHalf = false; - isImaginary = false; - MicrosoftInteger = 0; + if (!isImaginary) { + // Any suffix pieces we might have parsed are actually part of the + // ud-suffix. + isLong = false; + isUnsigned = false; + isLongLong = false; + isFloat = false; + isFloat16 = false; + isHalf = false; + isImaginary = false; + MicrosoftInteger = 0; + } saw_ud_suffix = true; return; } - // Report an error if there are any. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), - diag::err_invalid_suffix_constant) - << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin) << isFPConstant; - hadError = true; - return; - } - - if (isImaginary) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), - diag::ext_imaginary_constant); + if (s != ThisTokEnd) { + // Report an error if there are any. + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), + diag::err_invalid_suffix_constant) + << StringRef(SuffixBegin, ThisTokEnd - SuffixBegin) << isFPConstant; + hadError = true; + } } } @@ -850,8 +855,8 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { PP.Diag(TokLoc, PP.getLangOpts().CPlusPlus ? diag::ext_hex_literal_invalid : diag::ext_hex_constant_invalid); - else if (PP.getLangOpts().CPlusPlus1z) - PP.Diag(TokLoc, diag::warn_cxx1z_hex_literal); + else if (PP.getLangOpts().CPlusPlus17) + PP.Diag(TokLoc, diag::warn_cxx17_hex_literal); } else if (saw_period) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), diag::err_hex_constant_requires) diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp index f791d8d4bacc2..5c0f0623c3e17 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp @@ -33,7 +33,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, // See if we have an entry with a big enough argument list to reuse on the // free list. If so, reuse it. for (MacroArgs **Entry = &PP.MacroArgCache; *Entry; - Entry = &(*Entry)->ArgCache) + Entry = &(*Entry)->ArgCache) { if ((*Entry)->NumUnexpArgTokens >= UnexpArgTokens.size() && (*Entry)->NumUnexpArgTokens < ClosestMatch) { ResultEnt = Entry; @@ -44,14 +44,12 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, // Otherwise, use the best fit. ClosestMatch = (*Entry)->NumUnexpArgTokens; } - + } MacroArgs *Result; if (!ResultEnt) { - // Allocate memory for a MacroArgs object with the lexer tokens at the end. - Result = (MacroArgs *)malloc(sizeof(MacroArgs) + - UnexpArgTokens.size() * sizeof(Token)); - // Construct the MacroArgs object. - new (Result) + // Allocate memory for a MacroArgs object with the lexer tokens at the end, + // and construct the MacroArgs object. + Result = new (std::malloc(totalSizeToAlloc<Token>(UnexpArgTokens.size()))) MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumParams()); } else { Result = *ResultEnt; @@ -63,9 +61,14 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, } // Copy the actual unexpanded tokens to immediately after the result ptr. - if (!UnexpArgTokens.empty()) - std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(), - const_cast<Token*>(Result->getUnexpArgument(0))); + if (!UnexpArgTokens.empty()) { + static_assert(std::is_trivial<Token>::value, + "assume trivial copyability if copying into the " + "uninitialized array (as opposed to reusing a cached " + "MacroArgs)"); + std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(), + Result->getTrailingObjects<Token>()); + } return Result; } @@ -93,6 +96,8 @@ MacroArgs *MacroArgs::deallocate() { // Run the dtor to deallocate the vectors. this->~MacroArgs(); // Release the memory for the object. + static_assert(std::is_trivially_destructible<Token>::value, + "assume trivially destructible and forego destructors"); free(this); return Next; @@ -113,10 +118,13 @@ unsigned MacroArgs::getArgLength(const Token *ArgPtr) { /// getUnexpArgument - Return the unexpanded tokens for the specified formal. /// const Token *MacroArgs::getUnexpArgument(unsigned Arg) const { + + assert(Arg < getNumMacroArguments() && "Invalid arg #"); // The unexpanded argument tokens start immediately after the MacroArgs object // in memory. - const Token *Start = (const Token *)(this+1); + const Token *Start = getTrailingObjects<Token>(); const Token *Result = Start; + // Scan to find Arg. for (; Arg; ++Result) { assert(Result < Start+NumUnexpArgTokens && "Invalid arg #"); @@ -127,6 +135,16 @@ const Token *MacroArgs::getUnexpArgument(unsigned Arg) const { return Result; } +// This function assumes that the variadic arguments are the tokens +// corresponding to the last parameter (ellipsis) - and since tokens are +// separated by the 'eof' token, if that is the only token corresponding to that +// last parameter, we know no variadic arguments were supplied. +bool MacroArgs::invokedWithVariadicArgument(const MacroInfo *const MI) const { + if (!MI->isVariadic()) + return false; + const int VariadicArgIndex = getNumMacroArguments() - 1; + return getUnexpArgument(VariadicArgIndex)->isNot(tok::eof); +} /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected /// by pre-expansion, return false. Otherwise, conservatively return true. @@ -145,14 +163,13 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok, /// getPreExpArgument - Return the pre-expanded form of the specified /// argument. -const std::vector<Token> & -MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI, - Preprocessor &PP) { - assert(Arg < MI->getNumParams() && "Invalid argument number!"); +const std::vector<Token> &MacroArgs::getPreExpArgument(unsigned Arg, + Preprocessor &PP) { + assert(Arg < getNumMacroArguments() && "Invalid argument number!"); // If we have already computed this, return it. - if (PreExpArgTokens.size() < MI->getNumParams()) - PreExpArgTokens.resize(MI->getNumParams()); + if (PreExpArgTokens.size() < getNumMacroArguments()) + PreExpArgTokens.resize(getNumMacroArguments()); std::vector<Token> &Result = PreExpArgTokens[Arg]; if (!Result.empty()) return Result; diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp index 6dc7841bc160b..b13767aa1d673 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp @@ -1,4 +1,4 @@ -//===--- MacroInfo.cpp - Information about #defined identifiers -----------===// +//===- MacroInfo.cpp - Information about #defined identifiers -------------===// // // The LLVM Compiler Infrastructure // @@ -12,25 +12,29 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/MacroInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <utility> + using namespace clang; MacroInfo::MacroInfo(SourceLocation DefLoc) - : Location(DefLoc), - ParameterList(nullptr), - NumParameters(0), - IsDefinitionLengthCached(false), - IsFunctionLike(false), - IsC99Varargs(false), - IsGNUVarargs(false), - IsBuiltinMacro(false), - HasCommaPasting(false), - IsDisabled(false), - IsUsed(false), - IsAllowRedefinitionsWithoutWarning(false), - IsWarnIfUnused(false), - UsedForHeaderGuard(false) { -} + : Location(DefLoc), IsDefinitionLengthCached(false), IsFunctionLike(false), + IsC99Varargs(false), IsGNUVarargs(false), IsBuiltinMacro(false), + HasCommaPasting(false), IsDisabled(false), IsUsed(false), + IsAllowRedefinitionsWithoutWarning(false), IsWarnIfUnused(false), + UsedForHeaderGuard(false) {} unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const { assert(!IsDefinitionLengthCached); diff --git a/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp b/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp index 40f78ce25ceb3..fbbae7a095203 100644 --- a/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp @@ -1,4 +1,4 @@ -//===--- ModuleMap.cpp - Describe the layout of modules ---------*- C++ -*-===// +//===- ModuleMap.cpp - Describe the layout of modules ---------------------===// // // The LLVM Compiler Infrastructure // @@ -11,29 +11,47 @@ // of a module as it relates to headers. // //===----------------------------------------------------------------------===// + #include "clang/Lex/ModuleMap.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include <stdlib.h> -#if defined(LLVM_ON_UNIX) -#include <limits.h> -#endif +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <string> +#include <system_error> +#include <utility> + using namespace clang; Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) { @@ -80,7 +98,7 @@ ModuleMap::resolveExport(Module *Mod, // Resolve the module-id. Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain); if (!Context) - return Module::ExportDecl(); + return {}; return Module::ExportDecl(Context, Unresolved.Wildcard); } @@ -256,8 +274,7 @@ ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo) : SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target), - HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr), - SourceModule(nullptr), NumCreatedModules(0) { + HeaderInfo(HeaderInfo) { MMapLangOpts.LineComment = true; } @@ -345,7 +362,7 @@ ModuleMap::KnownHeader ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File, SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) { if (UmbrellaDirs.empty()) - return KnownHeader(); + return {}; const DirectoryEntry *Dir = File->getDir(); assert(Dir && "file in no directory"); @@ -373,7 +390,7 @@ ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File, // Resolve the parent path to a directory entry. Dir = SourceMgr.getFileManager().getDirectory(DirName); } while (Dir); - return KnownHeader(); + return {}; } static bool violatesPrivateInclude(Module *RequestingModule, @@ -503,7 +520,7 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File, bool AllowTextual) { auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader { if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader) - return ModuleMap::KnownHeader(); + return {}; return R; }; @@ -593,7 +610,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) { return Header; } - return KnownHeader(); + return {}; } ArrayRef<ModuleMap::KnownHeader> @@ -746,8 +763,18 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name, return std::make_pair(Result, true); } +Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) { + assert(!PendingGlobalModule && "created multiple global modules"); + PendingGlobalModule.reset( + new Module("<global>", Loc, nullptr, /*IsFramework*/ false, + /*IsExplicit*/ true, NumCreatedModules++)); + PendingGlobalModule->Kind = Module::GlobalModuleFragment; + return PendingGlobalModule.get(); +} + Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, - StringRef Name) { + StringRef Name, + Module *GlobalModule) { assert(LangOpts.CurrentModule == Name && "module name mismatch"); assert(!Modules[Name] && "redefining existing module"); @@ -757,6 +784,12 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, Result->Kind = Module::ModuleInterfaceUnit; Modules[Name] = SourceModule = Result; + // Reparent the current global module fragment as a submodule of this module. + assert(GlobalModule == PendingGlobalModule.get() && + "unexpected global module"); + GlobalModule->setParent(Result); + PendingGlobalModule.release(); // now owned by parent + // Mark the main source file as being within the newly-created module so that // declarations and macros are properly visibility-restricted to it. auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); @@ -1173,6 +1206,7 @@ bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) { //----------------------------------------------------------------------------// namespace clang { + /// \brief A token in a module map file. struct MMToken { enum TokenKind { @@ -1186,6 +1220,7 @@ namespace clang { ExcludeKeyword, ExplicitKeyword, ExportKeyword, + ExportAsKeyword, ExternKeyword, FrameworkKeyword, LinkKeyword, @@ -1210,6 +1245,7 @@ namespace clang { union { // If Kind != IntegerLiteral. const char *StringData; + // If Kind == IntegerLiteral. uint64_t IntegerValue; }; @@ -1259,7 +1295,7 @@ namespace clang { bool IsSystem; /// \brief Whether an error occurred. - bool HadError; + bool HadError = false; /// \brief Stores string data for the various string literals referenced /// during parsing. @@ -1269,7 +1305,7 @@ namespace clang { MMToken Tok; /// \brief The active module. - Module *ActiveModule; + Module *ActiveModule = nullptr; /// \brief Whether a module uses the 'requires excluded' hack to mark its /// contents as 'textual'. @@ -1288,22 +1324,24 @@ namespace clang { /// (or the end of the file). void skipUntil(MMToken::TokenKind K); - typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId; + using ModuleId = SmallVector<std::pair<std::string, SourceLocation>, 2>; + bool parseModuleId(ModuleId &Id); void parseModuleDecl(); void parseExternModuleDecl(); void parseRequiresDecl(); - void parseHeaderDecl(clang::MMToken::TokenKind, - SourceLocation LeadingLoc); + void parseHeaderDecl(MMToken::TokenKind, SourceLocation LeadingLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); + void parseExportAsDecl(); void parseUseDecl(); void parseLinkDecl(); void parseConfigMacros(); void parseConflict(); void parseInferredModuleDecl(bool Framework, bool Explicit); - typedef ModuleMap::Attributes Attributes; + using Attributes = ModuleMap::Attributes; + bool parseOptionalAttributes(Attributes &Attrs); public: @@ -1314,10 +1352,9 @@ namespace clang { const FileEntry *ModuleMapFile, const DirectoryEntry *Directory, bool IsSystem) - : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), - ModuleMapFile(ModuleMapFile), Directory(Directory), - IsSystem(IsSystem), HadError(false), ActiveModule(nullptr) - { + : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), + ModuleMapFile(ModuleMapFile), Directory(Directory), + IsSystem(IsSystem) { Tok.clear(); consumeToken(); } @@ -1327,7 +1364,8 @@ namespace clang { bool terminatedByDirective() { return false; } SourceLocation getLocation() { return Tok.getLocation(); } }; -} + +} // namespace clang SourceLocation ModuleMapParser::consumeToken() { SourceLocation Result = Tok.getLocation(); @@ -1348,6 +1386,7 @@ retry: .Case("exclude", MMToken::ExcludeKeyword) .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) + .Case("export_as", MMToken::ExportAsKeyword) .Case("extern", MMToken::ExternKeyword) .Case("framework", MMToken::FrameworkKeyword) .Case("header", MMToken::HeaderKeyword) @@ -1548,20 +1587,26 @@ bool ModuleMapParser::parseModuleId(ModuleId &Id) { } namespace { + /// \brief Enumerates the known attributes. enum AttributeKind { /// \brief An unknown attribute. AT_unknown, + /// \brief The 'system' attribute. AT_system, + /// \brief The 'extern_c' attribute. AT_extern_c, + /// \brief The 'exhaustive' attribute. AT_exhaustive, + /// \brief The 'no_undeclared_includes' attribute. AT_no_undeclared_includes }; -} + +} // namespace /// \brief Parse a module declaration. /// @@ -1575,6 +1620,7 @@ namespace { /// header-declaration /// submodule-declaration /// export-declaration +/// export-as-declaration /// link-declaration /// /// submodule-declaration: @@ -1683,7 +1729,6 @@ void ModuleMapParser::parseModuleDecl() { if (parseOptionalAttributes(Attrs)) return; - // Parse the opening brace. if (!Tok.is(MMToken::LBrace)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace) @@ -1809,6 +1854,10 @@ void ModuleMapParser::parseModuleDecl() { parseExportDecl(); break; + case MMToken::ExportAsKeyword: + parseExportAsDecl(); + break; + case MMToken::UseKeyword: parseUseDecl(); break; @@ -2269,6 +2318,41 @@ void ModuleMapParser::parseExportDecl() { ActiveModule->UnresolvedExports.push_back(Unresolved); } +/// \brief Parse a module export_as declaration. +/// +/// export-as-declaration: +/// 'export_as' identifier +void ModuleMapParser::parseExportAsDecl() { + assert(Tok.is(MMToken::ExportAsKeyword)); + consumeToken(); + + if (!Tok.is(MMToken::Identifier)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_module_id); + HadError = true; + return; + } + + if (ActiveModule->Parent) { + Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as); + consumeToken(); + return; + } + + if (!ActiveModule->ExportAsModule.empty()) { + if (ActiveModule->ExportAsModule == Tok.getString()) { + Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as) + << ActiveModule->Name << Tok.getString(); + } else { + Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as) + << ActiveModule->Name << ActiveModule->ExportAsModule + << Tok.getString(); + } + } + + ActiveModule->ExportAsModule = Tok.getString(); + consumeToken(); +} + /// \brief Parse a module use declaration. /// /// use-declaration: @@ -2516,7 +2600,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { Done = true; break; - case MMToken::ExcludeKeyword: { + case MMToken::ExcludeKeyword: if (ActiveModule) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) << (ActiveModule != nullptr); @@ -2535,7 +2619,6 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { .push_back(Tok.getString()); consumeToken(); break; - } case MMToken::ExportKeyword: if (!ActiveModule) { @@ -2674,6 +2757,7 @@ bool ModuleMapParser::parseModuleMapFile() { case MMToken::Exclaim: case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: + case MMToken::ExportAsKeyword: case MMToken::HeaderKeyword: case MMToken::Identifier: case MMToken::LBrace: diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index b2450f516ba2a..ca3e70fd1060e 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -33,6 +33,7 @@ #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/PTHLexer.h" #include "clang/Lex/Token.h" +#include "clang/Lex/VariadicMacroSupport.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -349,15 +350,19 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { /// If ElseOk is true, then \#else directives are ok, if not, then we have /// already seen one so a \#else directive is a duplicate. When this returns, /// the caller can lex the first valid token. -void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, +void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, + SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, SourceLocation ElseLoc) { ++NumSkipped; assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?"); - CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, - FoundNonSkipPortion, FoundElse); + if (PreambleConditionalStack.reachedEOFWhileSkipping()) + PreambleConditionalStack.clearSkipInfo(); + else + CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/ false, + FoundNonSkipPortion, FoundElse); if (CurPTHLexer) { PTHSkipExcludedConditionalBlock(); @@ -380,16 +385,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // If this is the end of the buffer, we have an error. if (Tok.is(tok::eof)) { - // Emit errors for each unterminated conditional on the stack, including - // the current one. - while (!CurPPLexer->ConditionalStack.empty()) { - if (CurLexer->getFileLoc() != CodeCompletionFileLoc) - Diag(CurPPLexer->ConditionalStack.back().IfLoc, - diag::err_pp_unterminated_conditional); - CurPPLexer->ConditionalStack.pop_back(); - } - + // We don't emit errors for unterminated conditionals here, + // Lexer::LexEndOfFile can do that propertly. // Just return and let the caller lex after this #include. + if (PreambleConditionalStack.isRecording()) + PreambleConditionalStack.SkipInfo.emplace( + HashTokenLoc, IfTokenLoc, FoundNonSkipPortion, FoundElse, ElseLoc); break; } @@ -557,10 +558,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // the #if block. CurPPLexer->LexingRawMode = false; - if (Callbacks) { - SourceLocation BeginLoc = ElseLoc.isValid() ? ElseLoc : IfTokenLoc; - Callbacks->SourceRangeSkipped(SourceRange(BeginLoc, Tok.getLocation())); - } + if (Callbacks) + Callbacks->SourceRangeSkipped( + SourceRange(HashTokenLoc, CurPPLexer->getSourceLocation()), + Tok.getLocation()); } void Preprocessor::PTHSkipExcludedConditionalBlock() { @@ -948,15 +949,17 @@ void Preprocessor::HandleDirective(Token &Result) { default: break; // C99 6.10.1 - Conditional Inclusion. case tok::pp_if: - return HandleIfDirective(Result, ReadAnyTokensBeforeDirective); + return HandleIfDirective(Result, SavedHash, ReadAnyTokensBeforeDirective); case tok::pp_ifdef: - return HandleIfdefDirective(Result, false, true/*not valid for miopt*/); + return HandleIfdefDirective(Result, SavedHash, false, + true /*not valid for miopt*/); case tok::pp_ifndef: - return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective); + return HandleIfdefDirective(Result, SavedHash, true, + ReadAnyTokensBeforeDirective); case tok::pp_elif: - return HandleElifDirective(Result); + return HandleElifDirective(Result, SavedHash); case tok::pp_else: - return HandleElseDirective(Result); + return HandleElseDirective(Result, SavedHash); case tok::pp_endif: return HandleEndifDirective(Result); @@ -2135,19 +2138,19 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc, // Preprocessor Macro Directive Handling. //===----------------------------------------------------------------------===// -/// ReadMacroParameterList - The ( starting an argument list of a macro -/// definition has just been read. Lex the rest of the arguments and the +/// ReadMacroParameterList - The ( starting a parameter list of a macro +/// definition has just been read. Lex the rest of the parameters and the /// closing ), updating MI with what we learn. Return true if an error occurs -/// parsing the arg list. +/// parsing the param list. bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { - SmallVector<IdentifierInfo*, 32> Arguments; + SmallVector<IdentifierInfo*, 32> Parameters; while (true) { LexUnexpandedToken(Tok); switch (Tok.getKind()) { case tok::r_paren: - // Found the end of the argument list. - if (Arguments.empty()) // #define FOO() + // Found the end of the parameter list. + if (Parameters.empty()) // #define FOO() return false; // Otherwise we have #define FOO(A,) Diag(Tok, diag::err_pp_expected_ident_in_arg_list); @@ -2170,10 +2173,10 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); return true; } - // Add the __VA_ARGS__ identifier as an argument. - Arguments.push_back(Ident__VA_ARGS__); + // Add the __VA_ARGS__ identifier as a parameter. + Parameters.push_back(Ident__VA_ARGS__); MI->setIsC99Varargs(); - MI->setParameterList(Arguments, BP); + MI->setParameterList(Parameters, BP); return false; case tok::eod: // #define X( Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); @@ -2188,16 +2191,16 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { return true; } - // If this is already used as an argument, it is used multiple times (e.g. + // If this is already used as a parameter, it is used multiple times (e.g. // #define X(A,A. - if (std::find(Arguments.begin(), Arguments.end(), II) != - Arguments.end()) { // C99 6.10.3p6 + if (std::find(Parameters.begin(), Parameters.end(), II) != + Parameters.end()) { // C99 6.10.3p6 Diag(Tok, diag::err_pp_duplicate_name_in_arg_list) << II; return true; } - // Add the argument to the macro info. - Arguments.push_back(II); + // Add the parameter to the macro info. + Parameters.push_back(II); // Lex the token after the identifier. LexUnexpandedToken(Tok); @@ -2207,7 +2210,7 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { Diag(Tok, diag::err_pp_expected_comma_in_arg_list); return true; case tok::r_paren: // #define X(A) - MI->setParameterList(Arguments, BP); + MI->setParameterList(Parameters, BP); return false; case tok::comma: // #define X(A, break; @@ -2223,7 +2226,7 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { } MI->setIsGNUVarargs(); - MI->setParameterList(Arguments, BP); + MI->setParameterList(Parameters, BP); return false; } } @@ -2290,6 +2293,10 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( Token Tok; LexUnexpandedToken(Tok); + // Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk + // within their appropriate context. + VariadicMacroScopeGuard VariadicMacroScopeGuard(*this); + // If this is a function-like macro definition, parse the argument list, // marking each of the identifiers as being used as macro arguments. Also, // check other constraints on the first token of the macro body. @@ -2314,14 +2321,14 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( return nullptr; } - // If this is a definition of a variadic C99 function-like macro, not using - // the GNU named varargs extension, enabled __VA_ARGS__. + // If this is a definition of an ISO C/C++ variadic function-like macro (not + // using the GNU named varargs extension) inform our variadic scope guard + // which un-poisons and re-poisons certain identifiers (e.g. __VA_ARGS__) + // allowed only within the definition of a variadic macro. - // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. - // This gets unpoisoned where it is allowed. - assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!"); - if (MI->isC99Varargs()) - Ident__VA_ARGS__->setIsPoisoned(false); + if (MI->isC99Varargs()) { + VariadicMacroScopeGuard.enterScope(); + } // Read the first token after the arg list for down below. LexUnexpandedToken(Tok); @@ -2367,12 +2374,50 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( // Otherwise, read the body of a function-like macro. While we are at it, // check C99 6.10.3.2p1: ensure that # operators are followed by macro // parameters in function-like macro expansions. + + VAOptDefinitionContext VAOCtx(*this); + while (Tok.isNot(tok::eod)) { LastTok = Tok; if (!Tok.isOneOf(tok::hash, tok::hashat, tok::hashhash)) { MI->AddTokenToBody(Tok); + if (VAOCtx.isVAOptToken(Tok)) { + // If we're already within a VAOPT, emit an error. + if (VAOCtx.isInVAOpt()) { + Diag(Tok, diag::err_pp_vaopt_nested_use); + return nullptr; + } + // Ensure VAOPT is followed by a '(' . + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_pp_missing_lparen_in_vaopt_use); + return nullptr; + } + MI->AddTokenToBody(Tok); + VAOCtx.sawVAOptFollowedByOpeningParens(Tok.getLocation()); + LexUnexpandedToken(Tok); + if (Tok.is(tok::hashhash)) { + Diag(Tok, diag::err_vaopt_paste_at_start); + return nullptr; + } + continue; + } else if (VAOCtx.isInVAOpt()) { + if (Tok.is(tok::r_paren)) { + if (VAOCtx.sawClosingParen()) { + const unsigned NumTokens = MI->getNumTokens(); + assert(NumTokens >= 3 && "Must have seen at least __VA_OPT__( " + "and a subsequent tok::r_paren"); + if (MI->getReplacementToken(NumTokens - 2).is(tok::hashhash)) { + Diag(Tok, diag::err_vaopt_paste_at_end); + return nullptr; + } + } + } else if (Tok.is(tok::l_paren)) { + VAOCtx.sawOpeningParen(Tok.getLocation()); + } + } // Get the next token of the macro. LexUnexpandedToken(Tok); continue; @@ -2413,12 +2458,14 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( continue; } + // Our Token is a stringization operator. // Get the next token of the macro. LexUnexpandedToken(Tok); - // Check for a valid macro arg identifier. - if (Tok.getIdentifierInfo() == nullptr || - MI->getParameterNum(Tok.getIdentifierInfo()) == -1) { + // Check for a valid macro arg identifier or __VA_OPT__. + if (!VAOCtx.isVAOptToken(Tok) && + (Tok.getIdentifierInfo() == nullptr || + MI->getParameterNum(Tok.getIdentifierInfo()) == -1)) { // If this is assembler-with-cpp mode, we accept random gibberish after // the '#' because '#' is often a comment character. However, change @@ -2431,26 +2478,33 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( } else { Diag(Tok, diag::err_pp_stringize_not_parameter) << LastTok.is(tok::hashat); - - // Disable __VA_ARGS__ again. - Ident__VA_ARGS__->setIsPoisoned(true); return nullptr; } } // Things look ok, add the '#' and param name tokens to the macro. MI->AddTokenToBody(LastTok); - MI->AddTokenToBody(Tok); - LastTok = Tok; - // Get the next token of the macro. - LexUnexpandedToken(Tok); + // If the token following '#' is VAOPT, let the next iteration handle it + // and check it for correctness, otherwise add the token and prime the + // loop with the next one. + if (!VAOCtx.isVAOptToken(Tok)) { + MI->AddTokenToBody(Tok); + LastTok = Tok; + + // Get the next token of the macro. + LexUnexpandedToken(Tok); + } + } + if (VAOCtx.isInVAOpt()) { + assert(Tok.is(tok::eod) && "Must be at End Of preprocessing Directive"); + Diag(Tok, diag::err_pp_expected_after) + << LastTok.getKind() << tok::r_paren; + Diag(VAOCtx.getUnmatchedOpeningParenLoc(), diag::note_matching) << tok::l_paren; + return nullptr; } } MI->setDefinitionEndLoc(LastTok.getLocation()); - // Disable __VA_ARGS__ again. - Ident__VA_ARGS__->setIsPoisoned(true); - return MI; } /// HandleDefineDirective - Implements \#define. This consumes the entire macro @@ -2614,7 +2668,9 @@ void Preprocessor::HandleUndefDirective() { /// true if any tokens have been returned or pp-directives activated before this /// \#ifndef has been lexed. /// -void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, +void Preprocessor::HandleIfdefDirective(Token &Result, + const Token &HashToken, + bool isIfndef, bool ReadAnyTokensBeforeDirective) { ++NumIf; Token DirectiveTok = Result; @@ -2626,8 +2682,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, if (MacroNameTok.is(tok::eod)) { // Skip code until we get to #endif. This helps with recovery by not // emitting an error when the #endif is reached. - SkipExcludedConditionalBlock(DirectiveTok.getLocation(), - /*Foundnonskip*/false, /*FoundElse*/false); + SkipExcludedConditionalBlock(HashToken.getLocation(), + DirectiveTok.getLocation(), + /*Foundnonskip*/ false, /*FoundElse*/ false); return; } @@ -2675,15 +2732,17 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, /*foundelse*/false); } else { // No, skip the contents of this block. - SkipExcludedConditionalBlock(DirectiveTok.getLocation(), - /*Foundnonskip*/false, - /*FoundElse*/false); + SkipExcludedConditionalBlock(HashToken.getLocation(), + DirectiveTok.getLocation(), + /*Foundnonskip*/ false, + /*FoundElse*/ false); } } /// HandleIfDirective - Implements the \#if directive. /// void Preprocessor::HandleIfDirective(Token &IfToken, + const Token &HashToken, bool ReadAnyTokensBeforeDirective) { ++NumIf; @@ -2721,8 +2780,9 @@ void Preprocessor::HandleIfDirective(Token &IfToken, /*foundnonskip*/true, /*foundelse*/false); } else { // No, skip the contents of this block. - SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false, - /*FoundElse*/false); + SkipExcludedConditionalBlock(HashToken.getLocation(), IfToken.getLocation(), + /*Foundnonskip*/ false, + /*FoundElse*/ false); } } @@ -2754,7 +2814,7 @@ void Preprocessor::HandleEndifDirective(Token &EndifToken) { /// HandleElseDirective - Implements the \#else directive. /// -void Preprocessor::HandleElseDirective(Token &Result) { +void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) { ++NumElse; // #else directive in a non-skipping conditional... start skipping. @@ -2785,13 +2845,15 @@ void Preprocessor::HandleElseDirective(Token &Result) { } // Finally, skip the rest of the contents of this block. - SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/true, Result.getLocation()); + SkipExcludedConditionalBlock(HashToken.getLocation(), CI.IfLoc, + /*Foundnonskip*/ true, + /*FoundElse*/ true, Result.getLocation()); } /// HandleElifDirective - Implements the \#elif directive. /// -void Preprocessor::HandleElifDirective(Token &ElifToken) { +void Preprocessor::HandleElifDirective(Token &ElifToken, + const Token &HashToken) { ++NumElse; // #elif directive in a non-skipping conditional... start skipping. @@ -2828,7 +2890,7 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) { } // Finally, skip the rest of the contents of this block. - SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/CI.FoundElse, - ElifToken.getLocation()); + SkipExcludedConditionalBlock( + HashToken.getLocation(), CI.IfLoc, /*Foundnonskip*/ true, + /*FoundElse*/ CI.FoundElse, ElifToken.getLocation()); } diff --git a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp index 36d7028da6886..e484e9c4c3a38 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp @@ -40,10 +40,9 @@ bool Preprocessor::isInPrimaryFile() const { // If there are any stacked lexers, we're in a #include. assert(IsFileLexer(IncludeMacroStack[0]) && "Top level include stack isn't our primary lexer?"); - return std::none_of(IncludeMacroStack.begin() + 1, IncludeMacroStack.end(), - [this](const IncludeStackInfo &ISI) -> bool { - return IsFileLexer(ISI); - }); + return std::none_of( + IncludeMacroStack.begin() + 1, IncludeMacroStack.end(), + [&](const IncludeStackInfo &ISI) -> bool { return IsFileLexer(ISI); }); } /// getCurrentLexer - Return the current file lexer being lexed from. Note diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp index 3f8ede23da563..41633f90c34da 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -369,11 +369,17 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); + Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute"); Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); Ident__is_identifier = RegisterBuiltinMacro(*this, "__is_identifier"); + Ident__is_target_arch = RegisterBuiltinMacro(*this, "__is_target_arch"); + Ident__is_target_vendor = RegisterBuiltinMacro(*this, "__is_target_vendor"); + Ident__is_target_os = RegisterBuiltinMacro(*this, "__is_target_os"); + Ident__is_target_environment = + RegisterBuiltinMacro(*this, "__is_target_environment"); // Modules. Ident__building_module = RegisterBuiltinMacro(*this, "__building_module"); @@ -1023,7 +1029,7 @@ Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer, size_t newIndex = MacroExpandedTokens.size(); bool cacheNeedsToGrow = tokens.size() > - MacroExpandedTokens.capacity()-MacroExpandedTokens.size(); + MacroExpandedTokens.capacity()-MacroExpandedTokens.size(); MacroExpandedTokens.append(tokens.begin(), tokens.end()); if (cacheNeedsToGrow) { @@ -1098,6 +1104,8 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) { .Case("address_sanitizer", LangOpts.Sanitize.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress)) + .Case("hwaddress_sanitizer", + LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress)) .Case("assume_nonnull", true) .Case("attribute_analyzer_noreturn", true) .Case("attribute_availability", true) @@ -1135,9 +1143,11 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) { .Case("nullability_on_arrays", true) .Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory)) .Case("thread_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Thread)) - .Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow)) + .Case("dataflow_sanitizer", + LangOpts.Sanitize.has(SanitizerKind::DataFlow)) .Case("efficiency_sanitizer", LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency)) + .Case("scudo", LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) // Objective-C features .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE? .Case("objc_arc", LangOpts.ObjCAutoRefCount) @@ -1588,6 +1598,56 @@ static IdentifierInfo *ExpectFeatureIdentifierInfo(Token &Tok, return nullptr; } +/// Implements the __is_target_arch builtin macro. +static bool isTargetArch(const TargetInfo &TI, const IdentifierInfo *II) { + std::string ArchName = II->getName().lower() + "--"; + llvm::Triple Arch(ArchName); + const llvm::Triple &TT = TI.getTriple(); + if (TT.isThumb()) { + // arm matches thumb or thumbv7. armv7 matches thumbv7. + if ((Arch.getSubArch() == llvm::Triple::NoSubArch || + Arch.getSubArch() == TT.getSubArch()) && + ((TT.getArch() == llvm::Triple::thumb && + Arch.getArch() == llvm::Triple::arm) || + (TT.getArch() == llvm::Triple::thumbeb && + Arch.getArch() == llvm::Triple::armeb))) + return true; + } + // Check the parsed arch when it has no sub arch to allow Clang to + // match thumb to thumbv7 but to prohibit matching thumbv6 to thumbv7. + return (Arch.getSubArch() == llvm::Triple::NoSubArch || + Arch.getSubArch() == TT.getSubArch()) && + Arch.getArch() == TT.getArch(); +} + +/// Implements the __is_target_vendor builtin macro. +static bool isTargetVendor(const TargetInfo &TI, const IdentifierInfo *II) { + StringRef VendorName = TI.getTriple().getVendorName(); + if (VendorName.empty()) + VendorName = "unknown"; + return VendorName.equals_lower(II->getName()); +} + +/// Implements the __is_target_os builtin macro. +static bool isTargetOS(const TargetInfo &TI, const IdentifierInfo *II) { + std::string OSName = + (llvm::Twine("unknown-unknown-") + II->getName().lower()).str(); + llvm::Triple OS(OSName); + if (OS.getOS() == llvm::Triple::Darwin) { + // Darwin matches macos, ios, etc. + return TI.getTriple().isOSDarwin(); + } + return TI.getTriple().getOS() == OS.getOS(); +} + +/// Implements the __is_target_environment builtin macro. +static bool isTargetEnvironment(const TargetInfo &TI, + const IdentifierInfo *II) { + std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str(); + llvm::Triple Env(EnvName); + return TI.getTriple().getEnvironment() == Env.getEnvironment(); +} + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1750,6 +1810,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { .Case("__make_integer_seq", LangOpts.CPlusPlus) .Case("__type_pack_element", LangOpts.CPlusPlus) .Case("__builtin_available", true) + .Case("__is_target_arch", true) + .Case("__is_target_vendor", true) + .Case("__is_target_os", true) + .Case("__is_target_environment", true) .Default(false); } }); @@ -1774,30 +1838,34 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II, getTargetInfo(), getLangOpts()) : 0; }); - } else if (II == Ident__has_cpp_attribute) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, - [this](Token &Tok, bool &HasLexedNextToken) -> int { - IdentifierInfo *ScopeII = nullptr; - IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, - diag::err_feature_check_malformed); - if (!II) - return false; + } else if (II == Ident__has_cpp_attribute || + II == Ident__has_c_attribute) { + bool IsCXX = II == Ident__has_cpp_attribute; + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, [&](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *ScopeII = nullptr; + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + if (!II) + return false; - // It is possible to receive a scope token. Read the "::", if it is - // available, and the subsequent identifier. - LexUnexpandedToken(Tok); - if (Tok.isNot(tok::coloncolon)) - HasLexedNextToken = true; - else { - ScopeII = II; + // It is possible to receive a scope token. Read the "::", if it is + // available, and the subsequent identifier. LexUnexpandedToken(Tok); - II = ExpectFeatureIdentifierInfo(Tok, *this, - diag::err_feature_check_malformed); - } + if (Tok.isNot(tok::coloncolon)) + HasLexedNextToken = true; + else { + ScopeII = II; + LexUnexpandedToken(Tok); + II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + } - return II ? hasAttribute(AttrSyntax::CXX, ScopeII, II, - getTargetInfo(), getLangOpts()) : 0; - }); + AttrSyntax Syntax = IsCXX ? AttrSyntax::CXX : AttrSyntax::C; + return II ? hasAttribute(Syntax, ScopeII, II, getTargetInfo(), + getLangOpts()) + : 0; + }); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized @@ -1897,6 +1965,34 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Diag(LParenLoc, diag::note_matching) << tok::l_paren; } return; + } else if (II == Ident__is_target_arch) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetArch(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_vendor) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVendor(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_os) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetOS(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_environment) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetEnvironment(getTargetInfo(), II); + }); } else { llvm_unreachable("Unknown identifier!"); } diff --git a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp index ec806e8445311..d6c20a13d27be 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp @@ -1,4 +1,4 @@ -//===--- PTHLexer.cpp - Lex from a token stream ---------------------------===// +//===- PTHLexer.cpp - Lex from a token stream -----------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,19 +12,32 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/PTHLexer.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/PTHManager.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/Token.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/EndianStream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <ctime> #include <memory> -#include <system_error> +#include <utility> + using namespace clang; static const unsigned StoredTokenSize = 1 + 1 + 2 + 4 + 4; @@ -35,9 +48,8 @@ static const unsigned StoredTokenSize = 1 + 1 + 2 + 4 + 4; PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D, const unsigned char *ppcond, PTHManager &PM) - : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(nullptr), - PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) { - + : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), PPCond(ppcond), + CurPPCondPtr(ppcond), PTHMgr(PM) { FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID); } @@ -167,7 +179,7 @@ void PTHLexer::DiscardToEndOfLine() { // We don't need to actually reconstruct full tokens from the token buffer. // This saves some copies and it also reduces IdentifierInfo* lookup. const unsigned char* p = CurPtr; - while (1) { + while (true) { // Read the token kind. Are we at the end of the file? tok::TokenKind x = (tok::TokenKind) (uint8_t) *p; if (x == tok::eof) break; @@ -186,6 +198,7 @@ void PTHLexer::DiscardToEndOfLine() { /// SkipBlock - Used by Preprocessor to skip the current conditional block. bool PTHLexer::SkipBlock() { using namespace llvm::support; + assert(CurPPCondPtr && "No cached PP conditional information."); assert(LastHashTokPtr && "No known '#' token."); @@ -303,23 +316,24 @@ SourceLocation PTHLexer::getSourceLocation() { /// to map from FileEntry objects managed by FileManager to offsets within /// the PTH file. namespace { + class PTHFileData { const uint32_t TokenOff; const uint32_t PPCondOff; + public: PTHFileData(uint32_t tokenOff, uint32_t ppCondOff) - : TokenOff(tokenOff), PPCondOff(ppCondOff) {} + : TokenOff(tokenOff), PPCondOff(ppCondOff) {} uint32_t getTokenOffset() const { return TokenOff; } uint32_t getPPCondOffset() const { return PPCondOff; } }; - class PTHFileLookupCommonTrait { public: - typedef std::pair<unsigned char, StringRef> internal_key_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using internal_key_type = std::pair<unsigned char, StringRef>; + using hash_value_type = unsigned; + using offset_type = unsigned; static hash_value_type ComputeHash(internal_key_type x) { return llvm::HashString(x.second); @@ -328,6 +342,7 @@ public: static std::pair<unsigned, unsigned> ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; + unsigned keyLen = (unsigned)endian::readNext<uint16_t, little, unaligned>(d); unsigned dataLen = (unsigned) *(d++); @@ -340,12 +355,12 @@ public: } }; -} // end anonymous namespace +} // namespace class PTHManager::PTHFileLookupTrait : public PTHFileLookupCommonTrait { public: - typedef const FileEntry* external_key_type; - typedef PTHFileData data_type; + using external_key_type = const FileEntry *; + using data_type = PTHFileData; static internal_key_type GetInternalKey(const FileEntry* FE) { return std::make_pair((unsigned char) 0x1, FE->getName()); @@ -357,8 +372,9 @@ public: static PTHFileData ReadData(const internal_key_type& k, const unsigned char* d, unsigned) { - assert(k.first == 0x1 && "Only file lookups can match!"); using namespace llvm::support; + + assert(k.first == 0x1 && "Only file lookups can match!"); uint32_t x = endian::readNext<uint32_t, little, unaligned>(d); uint32_t y = endian::readNext<uint32_t, little, unaligned>(d); return PTHFileData(x, y); @@ -367,11 +383,11 @@ public: class PTHManager::PTHStringLookupTrait { public: - typedef uint32_t data_type; - typedef const std::pair<const char*, unsigned> external_key_type; - typedef external_key_type internal_key_type; - typedef uint32_t hash_value_type; - typedef unsigned offset_type; + using data_type = uint32_t; + using external_key_type = const std::pair<const char *, unsigned>; + using internal_key_type = external_key_type; + using hash_value_type = uint32_t; + using offset_type = unsigned; static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { @@ -390,6 +406,7 @@ public: static std::pair<unsigned, unsigned> ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; + return std::make_pair( (unsigned)endian::readNext<uint16_t, little, unaligned>(d), sizeof(uint32_t)); @@ -404,6 +421,7 @@ public: static uint32_t ReadData(const internal_key_type& k, const unsigned char* d, unsigned) { using namespace llvm::support; + return endian::readNext<uint32_t, little, unaligned>(d); } }; @@ -420,11 +438,10 @@ PTHManager::PTHManager( const unsigned char *spellingBase, const char *originalSourceFile) : Buf(std::move(buf)), PerIDCache(std::move(perIDCache)), FileLookup(std::move(fileLookup)), IdDataTable(idDataTable), - StringIdLookup(std::move(stringIdLookup)), NumIds(numIds), PP(nullptr), + StringIdLookup(std::move(stringIdLookup)), NumIds(numIds), SpellingBase(spellingBase), OriginalSourceFile(originalSourceFile) {} -PTHManager::~PTHManager() { -} +PTHManager::~PTHManager() = default; static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) { Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) << Msg; @@ -557,6 +574,7 @@ PTHManager *PTHManager::Create(StringRef file, DiagnosticsEngine &Diags) { IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { using namespace llvm::support; + // Look in the PTH file for the string data for the IdentifierInfo object. const unsigned char* TableEntry = IdDataTable + sizeof(uint32_t)*PersistentID; const unsigned char *IDData = @@ -566,7 +584,7 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { // Allocate the object. std::pair<IdentifierInfo,const unsigned char*> *Mem = - Alloc.Allocate<std::pair<IdentifierInfo,const unsigned char*> >(); + Alloc.Allocate<std::pair<IdentifierInfo, const unsigned char *>>(); Mem->second = IDData; assert(IDData[0] != '\0'); @@ -626,26 +644,26 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) { //===----------------------------------------------------------------------===// namespace { + class PTHStatData { public: uint64_t Size; time_t ModTime; llvm::sys::fs::UniqueID UniqueID; - const bool HasData; + const bool HasData = false; bool IsDirectory; + PTHStatData() = default; PTHStatData(uint64_t Size, time_t ModTime, llvm::sys::fs::UniqueID UniqueID, bool IsDirectory) : Size(Size), ModTime(ModTime), UniqueID(UniqueID), HasData(true), IsDirectory(IsDirectory) {} - - PTHStatData() : HasData(false) {} }; class PTHStatLookupTrait : public PTHFileLookupCommonTrait { public: - typedef StringRef external_key_type; // const char* - typedef PTHStatData data_type; + using external_key_type = StringRef; // const char* + using data_type = PTHStatData; static internal_key_type GetInternalKey(StringRef path) { // The key 'kind' doesn't matter here because it is ignored in EqualKey. @@ -660,7 +678,6 @@ public: static data_type ReadData(const internal_key_type& k, const unsigned char* d, unsigned) { - if (k.first /* File or Directory */) { bool IsDirectory = true; if (k.first == 0x1 /* File */) { @@ -682,11 +699,14 @@ public: return data_type(); } }; -} // end anonymous namespace + +} // namespace namespace clang { + class PTHStatCache : public FileSystemStatCache { - typedef llvm::OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy; + using CacheTy = llvm::OnDiskChainedHashTable<PTHStatLookupTrait>; + CacheTy Cache; public: @@ -720,7 +740,8 @@ public: return CacheExists; } }; -} + +} // namespace clang std::unique_ptr<FileSystemStatCache> PTHManager::createStatCache() { return llvm::make_unique<PTHStatCache>(*FileLookup); diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index bf2363a0a6f45..b8acd92521fb5 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -1,4 +1,4 @@ -//===--- Pragma.cpp - Pragma registration and handling --------------------===// +//===- Pragma.cpp - Pragma registration and handling ----------------------===// // // The LLVM Compiler Infrastructure // @@ -13,15 +13,21 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Pragma.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" @@ -30,25 +36,27 @@ #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> +#include <cstddef> #include <cstdint> #include <limits> #include <string> +#include <utility> #include <vector> using namespace clang; // Out-of-line destructor to provide a home for the class. -PragmaHandler::~PragmaHandler() { -} +PragmaHandler::~PragmaHandler() = default; //===----------------------------------------------------------------------===// // EmptyPragmaHandler Implementation. @@ -144,15 +152,14 @@ namespace { class LexingFor_PragmaRAII { Preprocessor &PP; bool InMacroArgPreExpansion; - bool Failed; + bool Failed = false; Token &OutTok; Token PragmaTok; public: LexingFor_PragmaRAII(Preprocessor &PP, bool InMacroArgPreExpansion, Token &Tok) - : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion), - Failed(false), OutTok(Tok) { + : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion), OutTok(Tok) { if (InMacroArgPreExpansion) { PragmaTok = OutTok; PP.EnableBacktrackAtThisPos(); @@ -186,13 +193,12 @@ public: } }; -} // end anonymous namespace +} // namespace /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Preprocessor::Handle_Pragma(Token &Tok) { - // This works differently if we are pre-expanding a macro argument. // In that case we don't actually "activate" the pragma now, we only lex it // until we are sure it is lexically correct and then we backtrack so that @@ -381,7 +387,6 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { } /// HandlePragmaOnce - Handle \#pragma once. OnceTok is the 'once'. -/// void Preprocessor::HandlePragmaOnce(Token &OnceTok) { // Don't honor the 'once' when handling the primary source file, unless // this is a prefix to a TU, which indicates we're generating a PCH file, or @@ -406,7 +411,6 @@ void Preprocessor::HandlePragmaMark() { } /// HandlePragmaPoison - Handle \#pragma GCC poison. PoisonTok is the 'poison'. -/// void Preprocessor::HandlePragmaPoison() { Token Tok; @@ -461,7 +465,6 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { // Mark the file as a system header. HeaderInfo.MarkFileSystemHeader(TheLexer->getFileEntry()); - PresumedLoc PLoc = SourceMgr.getPresumedLoc(SysHeaderTok.getLocation()); if (PLoc.isInvalid()) return; @@ -482,7 +485,6 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. -/// void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { Token FilenameTok; CurPPLexer->LexIncludeFilename(FilenameTok); @@ -623,7 +625,7 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { if (!IdentInfo) return; // Find the vector<MacroInfo*> associated with the macro. - llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> >::iterator iter = + llvm::DenseMap<IdentifierInfo *, std::vector<MacroInfo *>>::iterator iter = PragmaPushMacroInfo.find(IdentInfo); if (iter != PragmaPushMacroInfo.end()) { // Forget the MacroInfo currently associated with IdentInfo. @@ -962,6 +964,7 @@ namespace { /// PragmaOnceHandler - "\#pragma once" marks the file as atomically included. struct PragmaOnceHandler : public PragmaHandler { PragmaOnceHandler() : PragmaHandler("once") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &OnceTok) override { PP.CheckEndOfDirective("pragma once"); @@ -1116,7 +1119,6 @@ struct PragmaDebugHandler : public PragmaHandler { #ifdef _MSC_VER #pragma warning(default : 4717) #endif - }; /// PragmaDiagnosticHandler - e.g. '\#pragma GCC diagnostic ignored "-Wformat"' @@ -1125,8 +1127,8 @@ private: const char *Namespace; public: - explicit PragmaDiagnosticHandler(const char *NS) : - PragmaHandler("diagnostic"), Namespace(NS) {} + explicit PragmaDiagnosticHandler(const char *NS) + : PragmaHandler("diagnostic"), Namespace(NS) {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &DiagToken) override { @@ -1330,6 +1332,7 @@ struct PragmaWarningHandler : public PragmaHandler { /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &IncludeAliasTok) override { PP.HandlePragmaIncludeAlias(IncludeAliasTok); @@ -1370,7 +1373,8 @@ private: public: PragmaMessageHandler(PPCallbacks::PragmaMessageKind Kind, StringRef Namespace = StringRef()) - : PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {} + : PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), + Namespace(Namespace) {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) override { @@ -1615,8 +1619,7 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { /// PragmaSTDC_CX_LIMITED_RANGEHandler - "\#pragma STDC CX_LIMITED_RANGE ...". struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { - PragmaSTDC_CX_LIMITED_RANGEHandler() - : PragmaHandler("CX_LIMITED_RANGE") {} + PragmaSTDC_CX_LIMITED_RANGEHandler() : PragmaHandler("CX_LIMITED_RANGE") {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) override { @@ -1627,7 +1630,7 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { /// PragmaSTDC_UnknownHandler - "\#pragma STDC ...". struct PragmaSTDC_UnknownHandler : public PragmaHandler { - PragmaSTDC_UnknownHandler() {} + PragmaSTDC_UnknownHandler() = default; void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &UnknownTok) override { @@ -1725,6 +1728,7 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler { // The start location we want after processing this. SourceLocation NewLoc; + PPCallbacks *Callbacks = PP.getPPCallbacks(); if (IsBegin) { // Complain about attempts to re-enter an audit. @@ -1733,6 +1737,8 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler { PP.Diag(BeginLoc, diag::note_pragma_entered_here); } NewLoc = Loc; + if (Callbacks) + Callbacks->PragmaAssumeNonNullBegin(NewLoc); } else { // Complain about attempts to leave an audit that doesn't exist. if (!BeginLoc.isValid()) { @@ -1740,6 +1746,8 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler { return; } NewLoc = SourceLocation(); + if (Callbacks) + Callbacks->PragmaAssumeNonNullEnd(NewLoc); } PP.setPragmaAssumeNonNullLoc(NewLoc); @@ -1758,7 +1766,7 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler { /// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a> /// pragma, just skipped by compiler. struct PragmaRegionHandler : public PragmaHandler { - PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { } + PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &NameTok) override { @@ -1769,7 +1777,7 @@ struct PragmaRegionHandler : public PragmaHandler { } }; -} // end anonymous namespace +} // namespace /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 03c4cbe589d50..af439dbfa5842 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -1,4 +1,4 @@ -//===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===// +//===- PreprocessingRecord.cpp - Record of Preprocessing ------------------===// // // The LLVM Compiler Infrastructure // @@ -11,15 +11,34 @@ // of what occurred during preprocessing, and its helpers. // //===----------------------------------------------------------------------===// + #include "clang/Lex/PreprocessingRecord.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Token.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Capacity.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <iterator> +#include <utility> +#include <vector> using namespace clang; -ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } +ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() = + default; InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, StringRef FileName, @@ -33,10 +52,7 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, this->FileName = StringRef(Memory, FileName.size()); } -PreprocessingRecord::PreprocessingRecord(SourceManager &SM) - : SourceMgr(SM), - ExternalSource(nullptr) { -} +PreprocessingRecord::PreprocessingRecord(SourceManager &SM) : SourceMgr(SM) {} /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities /// that source range \p Range encompasses. @@ -166,7 +182,7 @@ template <SourceLocation (SourceRange::*getRangeLoc)() const> struct PPEntityComp { const SourceManager &SM; - explicit PPEntityComp(const SourceManager &SM) : SM(SM) { } + explicit PPEntityComp(const SourceManager &SM) : SM(SM) {} bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const { SourceLocation LHS = getLoc(L); @@ -190,7 +206,7 @@ struct PPEntityComp { } }; -} +} // namespace unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity( SourceLocation Loc) const { @@ -271,7 +287,7 @@ PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { // FM(M1, M2) // \endcode - typedef std::vector<PreprocessedEntity *>::iterator pp_iter; + using pp_iter = std::vector<PreprocessedEntity *>::iterator; // Usually there are few macro expansions when defining the filename, do a // linear search for a few entities. @@ -400,8 +416,9 @@ void PreprocessingRecord::Defined(const Token &MacroNameTok, MacroNameTok.getLocation()); } -void PreprocessingRecord::SourceRangeSkipped(SourceRange Range) { - SkippedRanges.push_back(Range); +void PreprocessingRecord::SourceRangeSkipped(SourceRange Range, + SourceLocation EndifLoc) { + SkippedRanges.emplace_back(Range.getBegin(), EndifLoc); } void PreprocessingRecord::MacroExpands(const Token &Id, @@ -429,7 +446,7 @@ void PreprocessingRecord::MacroUndefined(const Token &Id, void PreprocessingRecord::InclusionDirective( SourceLocation HashLoc, - const clang::Token &IncludeTok, + const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, @@ -469,10 +486,10 @@ void PreprocessingRecord::InclusionDirective( EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects // a token range. } - clang::InclusionDirective *ID - = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, - (bool)Imported, - File, SourceRange(HashLoc, EndLoc)); + clang::InclusionDirective *ID = + new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, + (bool)Imported, File, + SourceRange(HashLoc, EndLoc)); addPreprocessedEntity(ID); } diff --git a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp index 7979be773aa13..c291a4b99d101 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp @@ -1,4 +1,4 @@ -//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===// +//===- Preprocess.cpp - C Language Family Preprocessor Implementation -----===// // // The LLVM Compiler Infrastructure // @@ -28,22 +28,33 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroArgs.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/PTHLexer.h" #include "clang/Lex/PTHManager.h" #include "clang/Lex/Pragma.h" #include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/PreprocessorLexer.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/ScratchBuffer.h" +#include "clang/Lex/Token.h" +#include "clang/Lex/TokenLexer.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -65,8 +76,7 @@ using namespace clang; LLVM_INSTANTIATE_REGISTRY(PragmaHandlerRegistry) -//===----------------------------------------------------------------------===// -ExternalPreprocessorSource::~ExternalPreprocessorSource() { } +ExternalPreprocessorSource::~ExternalPreprocessorSource() = default; Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, DiagnosticsEngine &diags, LangOptions &opts, @@ -74,34 +84,16 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, HeaderSearch &Headers, ModuleLoader &TheModuleLoader, IdentifierInfoLookup *IILookup, bool OwnsHeaders, TranslationUnitKind TUKind) - : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), Target(nullptr), - AuxTarget(nullptr), FileMgr(Headers.getFileMgr()), SourceMgr(SM), + : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), ExternalSource(nullptr), Identifiers(opts, IILookup), - PragmaHandlers(new PragmaNamespace(StringRef())), - IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr), - CodeCompletionFile(nullptr), CodeCompletionOffset(0), - LastTokenWasAt(false), ModuleImportExpectsIdentifier(false), - CodeCompletionReached(false), CodeCompletionII(nullptr), - MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr), - CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), - CurLexerSubmodule(nullptr), Callbacks(nullptr), - CurSubmoduleState(&NullSubmoduleState), MacroArgCache(nullptr), - Record(nullptr), MIChainHead(nullptr) { + PragmaHandlers(new PragmaNamespace(StringRef())), TUKind(TUKind), + SkipMainFilePreamble(0, true), + CurSubmoduleState(&NullSubmoduleState) { OwnsHeaderSearch = OwnsHeaders; - CounterValue = 0; // __COUNTER__ starts at 0. - - // Clear stats. - NumDirectives = NumDefined = NumUndefined = NumPragma = 0; - NumIf = NumElse = NumEndif = 0; - NumEnteredSourceFiles = 0; - NumMacroExpanded = NumFnMacroExpanded = NumBuiltinMacroExpanded = 0; - NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0; - MaxIncludeStackDepth = 0; - NumSkipped = 0; - // Default to discarding comments. KeepComments = false; KeepMacroComments = false; @@ -117,16 +109,20 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, ParsingIfOrElifDirective = false; PreprocessedOutput = false; - CachedLexPos = 0; - // We haven't read anything from the external source. ReadMacrosFromExternalSource = false; - - // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. - // This gets unpoisoned where it is allowed. + + // "Poison" __VA_ARGS__, __VA_OPT__ which can only appear in the expansion of + // a macro. They get unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use); - + if (getLangOpts().CPlusPlus2a) { + (Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned(); + SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use); + } else { + Ident__VA_OPT__ = nullptr; + } + // Initialize the pragma handlers. RegisterBuiltinPragmas(); @@ -516,9 +512,9 @@ void Preprocessor::EnterMainSourceFile() { // If we've been asked to skip bytes in the main file (e.g., as part of a // precompiled preamble), do so now. if (SkipMainFilePreamble.first > 0) - CurLexer->SkipBytes(SkipMainFilePreamble.first, - SkipMainFilePreamble.second); - + CurLexer->SetByteOffset(SkipMainFilePreamble.first, + SkipMainFilePreamble.second); + // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) @@ -544,6 +540,13 @@ void Preprocessor::replayPreambleConditionalStack() { "CurPPLexer is null when calling replayPreambleConditionalStack."); CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack()); PreambleConditionalStack.doneReplaying(); + if (PreambleConditionalStack.reachedEOFWhileSkipping()) + SkipExcludedConditionalBlock( + PreambleConditionalStack.SkipInfo->HashTokenLoc, + PreambleConditionalStack.SkipInfo->IfTokenLoc, + PreambleConditionalStack.SkipInfo->FoundNonSkipPortion, + PreambleConditionalStack.SkipInfo->FoundElse, + PreambleConditionalStack.SkipInfo->ElseLoc); } } @@ -586,7 +589,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const { Identifier.setIdentifierInfo(II); if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() && getSourceManager().isInSystemHeader(Identifier.getLocation())) - Identifier.setKind(clang::tok::identifier); + Identifier.setKind(tok::identifier); else Identifier.setKind(II->getTokenID()); @@ -632,6 +635,8 @@ static diag::kind getFutureCompatDiagKind(const IdentifierInfo &II, return llvm::StringSwitch<diag::kind>(II.getName()) #define CXX11_KEYWORD(NAME, FLAGS) \ .Case(#NAME, diag::warn_cxx11_keyword) +#define CXX2A_KEYWORD(NAME, FLAGS) \ + .Case(#NAME, diag::warn_cxx2a_keyword) #include "clang/Basic/TokenKinds.def" ; @@ -665,13 +670,15 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { // unpoisoned it if we're defining a C99 macro. if (II.isOutOfDate()) { bool CurrentIsPoisoned = false; - if (&II == Ident__VA_ARGS__) - CurrentIsPoisoned = Ident__VA_ARGS__->isPoisoned(); + const bool IsSpecialVariadicMacro = + &II == Ident__VA_ARGS__ || &II == Ident__VA_OPT__; + if (IsSpecialVariadicMacro) + CurrentIsPoisoned = II.isPoisoned(); updateOutOfDateIdentifier(II); Identifier.setKind(II.getTokenID()); - if (&II == Ident__VA_ARGS__) + if (IsSpecialVariadicMacro) II.setIsPoisoned(CurrentIsPoisoned); } @@ -924,8 +931,8 @@ void Preprocessor::addCommentHandler(CommentHandler *Handler) { } void Preprocessor::removeCommentHandler(CommentHandler *Handler) { - std::vector<CommentHandler *>::iterator Pos - = std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler); + std::vector<CommentHandler *>::iterator Pos = + std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler); assert(Pos != CommentHandlers.end() && "Comment handler not registered"); CommentHandlers.erase(Pos); } @@ -944,11 +951,11 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { return true; } -ModuleLoader::~ModuleLoader() { } +ModuleLoader::~ModuleLoader() = default; -CommentHandler::~CommentHandler() { } +CommentHandler::~CommentHandler() = default; -CodeCompletionHandler::~CodeCompletionHandler() { } +CodeCompletionHandler::~CodeCompletionHandler() = default; void Preprocessor::createPreprocessingRecord() { if (Record) diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp index 33ccbc0cfc941..2e85f46f52c59 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp @@ -1,4 +1,4 @@ -//===--- PreprocessorLexer.cpp - C Language Family Lexer ------------------===// +//===- PreprocessorLexer.cpp - C Language Family Lexer --------------------===// // // The LLVM Compiler Infrastructure // @@ -15,14 +15,15 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/Token.h" +#include <cassert> + using namespace clang; -void PreprocessorLexer::anchor() { } +void PreprocessorLexer::anchor() {} PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid) - : PP(pp), FID(fid), InitialNumSLocEntries(0), - ParsingPreprocessorDirective(false), - ParsingFilename(false), LexingRawMode(false) { + : PP(pp), FID(fid) { if (pp) InitialNumSLocEntries = pp->getSourceManager().local_sloc_entry_size(); } diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp index d1facd9c68796..ec73479cb54f1 100644 --- a/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp @@ -99,10 +99,14 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { TokenInfo[tok::utf32_char_constant ] |= aci_custom; } - // These tokens have custom code in C++1z mode. - if (PP.getLangOpts().CPlusPlus1z) + // These tokens have custom code in C++17 mode. + if (PP.getLangOpts().CPlusPlus17) TokenInfo[tok::utf8_char_constant] |= aci_custom; + // These tokens have custom code in C++2a mode. + if (PP.getLangOpts().CPlusPlus2a) + TokenInfo[tok::lessequal ] |= aci_custom_firstchar; + // These tokens change behavior if followed by an '='. TokenInfo[tok::amp ] |= aci_avoid_equal; // &= TokenInfo[tok::plus ] |= aci_avoid_equal; // += @@ -283,5 +287,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, return FirstChar == '#' || FirstChar == '@' || FirstChar == '%'; case tok::arrow: // ->* return PP.getLangOpts().CPlusPlus && FirstChar == '*'; + case tok::lessequal: // <=> (C++2a) + return PP.getLangOpts().CPlusPlus2a && FirstChar == '>'; } } diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp index c2e49ba919a93..d7f1c7a93fdae 100644 --- a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp @@ -1,4 +1,4 @@ -//===--- TokenLexer.cpp - Lex from a token stream -------------------------===// +//===- TokenLexer.cpp - Lex from a token stream ---------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,12 +12,25 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/TokenLexer.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/Lexer.h" #include "clang/Lex/MacroArgs.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/Token.h" +#include "clang/Lex/VariadicMacroSupport.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include <cassert> +#include <cstring> using namespace clang; @@ -31,7 +44,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, Macro = MI; ActualArgs = Actuals; - CurToken = 0; + CurTokenIdx = 0; ExpandLocStart = Tok.getLocation(); ExpandLocEnd = ELEnd; @@ -90,7 +103,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks, OwnsTokens = ownsTokens; DisableMacroExpansion = disableMacroExpansion; NumTokens = NumToks; - CurToken = 0; + CurTokenIdx = 0; ExpandLocStart = ExpandLocEnd = SourceLocation(); AtStartOfLine = false; HasLeadingSpace = false; @@ -168,6 +181,59 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs( return true; } +void TokenLexer::stringifyVAOPTContents( + SmallVectorImpl<Token> &ResultToks, const VAOptExpansionContext &VCtx, + const SourceLocation VAOPTClosingParenLoc) { + const int NumToksPriorToVAOpt = VCtx.getNumberOfTokensPriorToVAOpt(); + const unsigned int NumVAOptTokens = ResultToks.size() - NumToksPriorToVAOpt; + Token *const VAOPTTokens = + NumVAOptTokens ? &ResultToks[NumToksPriorToVAOpt] : nullptr; + + SmallVector<Token, 64> ConcatenatedVAOPTResultToks; + // FIXME: Should we keep track within VCtx that we did or didnot + // encounter pasting - and only then perform this loop. + + // Perform token pasting (concatenation) prior to stringization. + for (unsigned int CurTokenIdx = 0; CurTokenIdx != NumVAOptTokens; + ++CurTokenIdx) { + if (VAOPTTokens[CurTokenIdx].is(tok::hashhash)) { + assert(CurTokenIdx != 0 && + "Can not have __VAOPT__ contents begin with a ##"); + Token &LHS = VAOPTTokens[CurTokenIdx - 1]; + pasteTokens(LHS, llvm::makeArrayRef(VAOPTTokens, NumVAOptTokens), + CurTokenIdx); + // Replace the token prior to the first ## in this iteration. + ConcatenatedVAOPTResultToks.back() = LHS; + if (CurTokenIdx == NumVAOptTokens) + break; + } + ConcatenatedVAOPTResultToks.push_back(VAOPTTokens[CurTokenIdx]); + } + + ConcatenatedVAOPTResultToks.push_back(VCtx.getEOFTok()); + // Get the SourceLocation that represents the start location within + // the macro definition that marks where this string is substituted + // into: i.e. the __VA_OPT__ and the ')' within the spelling of the + // macro definition, and use it to indicate that the stringified token + // was generated from that location. + const SourceLocation ExpansionLocStartWithinMacro = + getExpansionLocForMacroDefLoc(VCtx.getVAOptLoc()); + const SourceLocation ExpansionLocEndWithinMacro = + getExpansionLocForMacroDefLoc(VAOPTClosingParenLoc); + + Token StringifiedVAOPT = MacroArgs::StringifyArgument( + &ConcatenatedVAOPTResultToks[0], PP, VCtx.hasCharifyBefore() /*Charify*/, + ExpansionLocStartWithinMacro, ExpansionLocEndWithinMacro); + + if (VCtx.getLeadingSpaceForStringifiedToken()) + StringifiedVAOPT.setFlag(Token::LeadingSpace); + + StringifiedVAOPT.setFlag(Token::StringifiedInMacro); + // Resize (shrink) the token stream to just capture this stringified token. + ResultToks.resize(NumToksPriorToVAOpt + 1); + ResultToks.back() = StringifiedVAOPT; +} + /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. void TokenLexer::ExpandFunctionArguments() { @@ -178,28 +244,117 @@ void TokenLexer::ExpandFunctionArguments() { // we install the newly expanded sequence as the new 'Tokens' list. bool MadeChange = false; - for (unsigned i = 0, e = NumTokens; i != e; ++i) { - // If we found the stringify operator, get the argument stringified. The - // preprocessor already verified that the following token is a macro name - // when the #define was parsed. - const Token &CurTok = Tokens[i]; + const bool CalledWithVariadicArguments = + ActualArgs->invokedWithVariadicArgument(Macro); + + VAOptExpansionContext VCtx(PP); + + for (unsigned I = 0, E = NumTokens; I != E; ++I) { + const Token &CurTok = Tokens[I]; // We don't want a space for the next token after a paste // operator. In valid code, the token will get smooshed onto the // preceding one anyway. In assembler-with-cpp mode, invalid // pastes are allowed through: in this case, we do not want the // extra whitespace to be added. For example, we want ". ## foo" // -> ".foo" not ". foo". - if (i != 0 && !Tokens[i-1].is(tok::hashhash) && CurTok.hasLeadingSpace()) + if (I != 0 && !Tokens[I-1].is(tok::hashhash) && CurTok.hasLeadingSpace()) NextTokGetsSpace = true; - if (CurTok.isOneOf(tok::hash, tok::hashat)) { - int ArgNo = Macro->getParameterNum(Tokens[i+1].getIdentifierInfo()); - assert(ArgNo != -1 && "Token following # is not an argument?"); + if (VCtx.isVAOptToken(CurTok)) { + MadeChange = true; + assert(Tokens[I + 1].is(tok::l_paren) && + "__VA_OPT__ must be followed by '('"); + + ++I; // Skip the l_paren + VCtx.sawVAOptFollowedByOpeningParens(CurTok.getLocation(), + ResultToks.size()); + + continue; + } + + // We have entered into the __VA_OPT__ context, so handle tokens + // appropriately. + if (VCtx.isInVAOpt()) { + // If we are about to process a token that is either an argument to + // __VA_OPT__ or its closing rparen, then: + // 1) If the token is the closing rparen that exits us out of __VA_OPT__, + // perform any necessary stringification or placemarker processing, + // and/or skip to the next token. + // 2) else if macro was invoked without variadic arguments skip this + // token. + // 3) else (macro was invoked with variadic arguments) process the token + // normally. + if (Tokens[I].is(tok::l_paren)) + VCtx.sawOpeningParen(Tokens[I].getLocation()); + // Continue skipping tokens within __VA_OPT__ if the macro was not + // called with variadic arguments, else let the rest of the loop handle + // this token. Note sawClosingParen() returns true only if the r_paren matches + // the closing r_paren of the __VA_OPT__. + if (!Tokens[I].is(tok::r_paren) || !VCtx.sawClosingParen()) { + if (!CalledWithVariadicArguments) { + // Skip this token. + continue; + } + // ... else the macro was called with variadic arguments, and we do not + // have a closing rparen - so process this token normally. + } else { + // Current token is the closing r_paren which marks the end of the + // __VA_OPT__ invocation, so handle any place-marker pasting (if + // empty) by removing hashhash either before (if exists) or after. And + // also stringify the entire contents if VAOPT was preceded by a hash, + // but do so only after any token concatenation that needs to occur + // within the contents of VAOPT. + + if (VCtx.hasStringifyOrCharifyBefore()) { + // Replace all the tokens just added from within VAOPT into a single + // stringified token. This requires token-pasting to eagerly occur + // within these tokens. If either the contents of VAOPT were empty + // or the macro wasn't called with any variadic arguments, the result + // is a token that represents an empty string. + stringifyVAOPTContents(ResultToks, VCtx, + /*ClosingParenLoc*/ Tokens[I].getLocation()); + + } else if (/*No tokens within VAOPT*/ !( + ResultToks.size() - VCtx.getNumberOfTokensPriorToVAOpt())) { + // Treat VAOPT as a placemarker token. Eat either the '##' before the + // RHS/VAOPT (if one exists, suggesting that the LHS (if any) to that + // hashhash was not a placemarker) or the '##' + // after VAOPT, but not both. + + if (ResultToks.size() && ResultToks.back().is(tok::hashhash)) { + ResultToks.pop_back(); + } else if ((I + 1 != E) && Tokens[I + 1].is(tok::hashhash)) { + ++I; // Skip the following hashhash. + } + } + VCtx.reset(); + // We processed __VA_OPT__'s closing paren (and the exit out of + // __VA_OPT__), so skip to the next token. + continue; + } + } + + // If we found the stringify operator, get the argument stringified. The + // preprocessor already verified that the following token is a macro + // parameter or __VA_OPT__ when the #define was lexed. + + if (CurTok.isOneOf(tok::hash, tok::hashat)) { + int ArgNo = Macro->getParameterNum(Tokens[I+1].getIdentifierInfo()); + assert((ArgNo != -1 || VCtx.isVAOptToken(Tokens[I + 1])) && + "Token following # is not an argument or __VA_OPT__!"); + + if (ArgNo == -1) { + // Handle the __VA_OPT__ case. + VCtx.sawHashOrHashAtBefore(NextTokGetsSpace, + CurTok.is(tok::hashat)); + continue; + } + // Else handle the simple argument case. SourceLocation ExpansionLocStart = getExpansionLocForMacroDefLoc(CurTok.getLocation()); SourceLocation ExpansionLocEnd = - getExpansionLocForMacroDefLoc(Tokens[i+1].getLocation()); + getExpansionLocForMacroDefLoc(Tokens[I+1].getLocation()); Token Res; if (CurTok.is(tok::hash)) // Stringify @@ -222,7 +377,7 @@ void TokenLexer::ExpandFunctionArguments() { ResultToks.push_back(Res); MadeChange = true; - ++i; // Skip arg name. + ++I; // Skip arg name. NextTokGetsSpace = false; continue; } @@ -230,9 +385,11 @@ void TokenLexer::ExpandFunctionArguments() { // Find out if there is a paste (##) operator before or after the token. bool NonEmptyPasteBefore = !ResultToks.empty() && ResultToks.back().is(tok::hashhash); - bool PasteBefore = i != 0 && Tokens[i-1].is(tok::hashhash); - bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash); - assert(!NonEmptyPasteBefore || PasteBefore); + bool PasteBefore = I != 0 && Tokens[I-1].is(tok::hashhash); + bool PasteAfter = I+1 != E && Tokens[I+1].is(tok::hashhash); + + assert((!NonEmptyPasteBefore || PasteBefore || VCtx.isInVAOpt()) && + "unexpected ## in ResultToks"); // Otherwise, if this is not an argument token, just add the token to the // output buffer. @@ -275,7 +432,7 @@ void TokenLexer::ExpandFunctionArguments() { // avoids some work in common cases. const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo); if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP)) - ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, Macro, PP)[0]; + ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0]; else ResultArgToks = ArgTok; // Use non-preexpanded tokens. @@ -374,7 +531,7 @@ void TokenLexer::ExpandFunctionArguments() { if (PasteAfter) { // Discard the argument token and skip (don't copy to the expansion // buffer) the paste operator after it. - ++i; + ++I; continue; } @@ -384,7 +541,13 @@ void TokenLexer::ExpandFunctionArguments() { assert(PasteBefore); if (NonEmptyPasteBefore) { assert(ResultToks.back().is(tok::hashhash)); - ResultToks.pop_back(); + // Do not remove the paste operator if it is the one before __VA_OPT__ + // (and we are still processing tokens within VA_OPT). We handle the case + // of removing the paste operator if __VA_OPT__ reduces to the notional + // placemarker above when we encounter the closing paren of VA_OPT. + if (!VCtx.isInVAOpt() || + ResultToks.size() > VCtx.getNumberOfTokensPriorToVAOpt()) + ResultToks.pop_back(); } // If this is the __VA_ARGS__ token, and if the argument wasn't provided, @@ -420,7 +583,6 @@ static bool isWideStringLiteralFromMacro(const Token &FirstTok, } /// Lex - Lex and return a token from this macro stream. -/// bool TokenLexer::Lex(Token &Tok) { // Lexing off the end of the macro, pop this macro off the expansion stack. if (isAtEnd()) { @@ -431,7 +593,7 @@ bool TokenLexer::Lex(Token &Tok) { Tok.startToken(); Tok.setFlagValue(Token::StartOfLine , AtStartOfLine); Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace || NextTokGetsSpace); - if (CurToken == 0) + if (CurTokenIdx == 0) Tok.setFlag(Token::LeadingEmptyMacro); return PP.HandleEndOfTokenLexer(Tok); } @@ -440,25 +602,25 @@ bool TokenLexer::Lex(Token &Tok) { // If this is the first token of the expanded result, we inherit spacing // properties later. - bool isFirstToken = CurToken == 0; + bool isFirstToken = CurTokenIdx == 0; // Get the next token to return. - Tok = Tokens[CurToken++]; + Tok = Tokens[CurTokenIdx++]; bool TokenIsFromPaste = false; // If this token is followed by a token paste (##) operator, paste the tokens! // Note that ## is a normal token when not expanding a macro. if (!isAtEnd() && Macro && - (Tokens[CurToken].is(tok::hashhash) || + (Tokens[CurTokenIdx].is(tok::hashhash) || // Special processing of L#x macros in -fms-compatibility mode. // Microsoft compiler is able to form a wide string literal from // 'L#macro_arg' construct in a function-like macro. (PP.getLangOpts().MSVCCompat && - isWideStringLiteralFromMacro(Tok, Tokens[CurToken])))) { + isWideStringLiteralFromMacro(Tok, Tokens[CurTokenIdx])))) { // When handling the microsoft /##/ extension, the final token is - // returned by PasteTokens, not the pasted token. - if (PasteTokens(Tok)) + // returned by pasteTokens, not the pasted token. + if (pasteTokens(Tok)) return true; TokenIsFromPaste = true; @@ -521,40 +683,57 @@ bool TokenLexer::Lex(Token &Tok) { return true; } -/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## +bool TokenLexer::pasteTokens(Token &Tok) { + return pasteTokens(Tok, llvm::makeArrayRef(Tokens, NumTokens), CurTokenIdx); +} + +/// LHSTok is the LHS of a ## operator, and CurTokenIdx is the ## /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there -/// are more ## after it, chomp them iteratively. Return the result as Tok. +/// are more ## after it, chomp them iteratively. Return the result as LHSTok. /// If this returns true, the caller should immediately return the token. -bool TokenLexer::PasteTokens(Token &Tok) { +bool TokenLexer::pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream, + unsigned int &CurIdx) { + assert(CurIdx > 0 && "## can not be the first token within tokens"); + assert((TokenStream[CurIdx].is(tok::hashhash) || + (PP.getLangOpts().MSVCCompat && + isWideStringLiteralFromMacro(LHSTok, TokenStream[CurIdx]))) && + "Token at this Index must be ## or part of the MSVC 'L " + "#macro-arg' pasting pair"); + // MSVC: If previous token was pasted, this must be a recovery from an invalid // paste operation. Ignore spaces before this token to mimic MSVC output. // Required for generating valid UUID strings in some MS headers. - if (PP.getLangOpts().MicrosoftExt && (CurToken >= 2) && - Tokens[CurToken - 2].is(tok::hashhash)) - Tok.clearFlag(Token::LeadingSpace); + if (PP.getLangOpts().MicrosoftExt && (CurIdx >= 2) && + TokenStream[CurIdx - 2].is(tok::hashhash)) + LHSTok.clearFlag(Token::LeadingSpace); SmallString<128> Buffer; const char *ResultTokStrPtr = nullptr; - SourceLocation StartLoc = Tok.getLocation(); + SourceLocation StartLoc = LHSTok.getLocation(); SourceLocation PasteOpLoc; + + auto IsAtEnd = [&TokenStream, &CurIdx] { + return TokenStream.size() == CurIdx; + }; + do { // Consume the ## operator if any. - PasteOpLoc = Tokens[CurToken].getLocation(); - if (Tokens[CurToken].is(tok::hashhash)) - ++CurToken; - assert(!isAtEnd() && "No token on the RHS of a paste operator!"); + PasteOpLoc = TokenStream[CurIdx].getLocation(); + if (TokenStream[CurIdx].is(tok::hashhash)) + ++CurIdx; + assert(!IsAtEnd() && "No token on the RHS of a paste operator!"); // Get the RHS token. - const Token &RHS = Tokens[CurToken]; + const Token &RHS = TokenStream[CurIdx]; // Allocate space for the result token. This is guaranteed to be enough for // the two tokens. - Buffer.resize(Tok.getLength() + RHS.getLength()); + Buffer.resize(LHSTok.getLength() + RHS.getLength()); // Get the spelling of the LHS token in Buffer. const char *BufPtr = &Buffer[0]; bool Invalid = false; - unsigned LHSLen = PP.getSpelling(Tok, BufPtr, &Invalid); + unsigned LHSLen = PP.getSpelling(LHSTok, BufPtr, &Invalid); if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer! memcpy(&Buffer[0], BufPtr, LHSLen); if (Invalid) @@ -586,7 +765,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { // Lex the resultant pasted token into Result. Token Result; - if (Tok.isAnyIdentifier() && RHS.isAnyIdentifier()) { + if (LHSTok.isAnyIdentifier() && RHS.isAnyIdentifier()) { // Common paste case: identifier+identifier = identifier. Avoid creating // a lexer and other overhead. PP.IncrementPasteCounter(true); @@ -626,7 +805,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { isInvalid |= Result.is(tok::eof); // If pasting the two tokens didn't form a full new token, this is an - // error. This occurs with "x ## +" and other stuff. Return with Tok + // error. This occurs with "x ## +" and other stuff. Return with LHSTok // unmodified and with RHS as the next token to lex. if (isInvalid) { // Explicitly convert the token location to have proper expansion @@ -637,9 +816,9 @@ bool TokenLexer::PasteTokens(Token &Tok) { // Test for the Microsoft extension of /##/ turning into // here on the // error path. - if (PP.getLangOpts().MicrosoftExt && Tok.is(tok::slash) && + if (PP.getLangOpts().MicrosoftExt && LHSTok.is(tok::slash) && RHS.is(tok::slash)) { - HandleMicrosoftCommentPaste(Tok, Loc); + HandleMicrosoftCommentPaste(LHSTok, Loc); return true; } @@ -664,15 +843,15 @@ bool TokenLexer::PasteTokens(Token &Tok) { } // Transfer properties of the LHS over the Result. - Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine()); - Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace()); + Result.setFlagValue(Token::StartOfLine , LHSTok.isAtStartOfLine()); + Result.setFlagValue(Token::LeadingSpace, LHSTok.hasLeadingSpace()); // Finally, replace LHS with the result, consume the RHS, and iterate. - ++CurToken; - Tok = Result; - } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)); + ++CurIdx; + LHSTok = Result; + } while (!IsAtEnd() && TokenStream[CurIdx].is(tok::hashhash)); - SourceLocation EndLoc = Tokens[CurToken - 1].getLocation(); + SourceLocation EndLoc = TokenStream[CurIdx - 1].getLocation(); // The token's current location indicate where the token was lexed from. We // need this information to compute the spelling of the token, but any @@ -690,16 +869,16 @@ bool TokenLexer::PasteTokens(Token &Tok) { while (SM.getFileID(EndLoc) != MacroFID) EndLoc = SM.getImmediateExpansionRange(EndLoc).second; - Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc, - Tok.getLength())); + LHSTok.setLocation(SM.createExpansionLoc(LHSTok.getLocation(), StartLoc, EndLoc, + LHSTok.getLength())); // Now that we got the result token, it will be subject to expansion. Since // token pasting re-lexes the result token in raw mode, identifier information // isn't looked up. As such, if the result is an identifier, look up id info. - if (Tok.is(tok::raw_identifier)) { + if (LHSTok.is(tok::raw_identifier)) { // Look up the identifier info for the token. We disabled identifier lookup // by saying we're skipping contents, so we need to do this manually. - PP.LookUpIdentifierInfo(Tok); + PP.LookUpIdentifierInfo(LHSTok); } return false; } @@ -711,7 +890,7 @@ unsigned TokenLexer::isNextTokenLParen() const { // Out of tokens? if (isAtEnd()) return 2; - return Tokens[CurToken].is(tok::l_paren); + return Tokens[CurTokenIdx].is(tok::l_paren); } /// isParsingPreprocessorDirective - Return true if we are in the middle of a @@ -831,9 +1010,8 @@ static void updateConsecutiveMacroArgTokens(SourceManager &SM, /// \brief Creates SLocEntries and updates the locations of macro argument /// tokens to their new expanded locations. /// -/// \param ArgIdDefLoc the location of the macro argument id inside the macro +/// \param ArgIdSpellLoc the location of the macro argument id inside the macro /// definition. -/// \param Tokens the macro argument tokens to update. void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc, Token *begin_tokens, Token *end_tokens) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index 27651c9ca85cb..2b3d4ba85bd8d 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -509,7 +509,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index a4610698c46d0..9fe4309ca1244 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -912,13 +912,18 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } IdentifierLoc *Platform = ParseIdentifierLoc(); - // Canonicalize platform name from "macosx" to "macos". - if (Platform->Ident && Platform->Ident->getName() == "macosx") - Platform->Ident = PP.getIdentifierInfo("macos"); - // Canonicalize platform name from "macosx_app_extension" to - // "macos_app_extension". - if (Platform->Ident && Platform->Ident->getName() == "macosx_app_extension") - Platform->Ident = PP.getIdentifierInfo("macos_app_extension"); + if (const IdentifierInfo *const Ident = Platform->Ident) { + // Canonicalize platform name from "macosx" to "macos". + if (Ident->getName() == "macosx") + Platform->Ident = PP.getIdentifierInfo("macos"); + // Canonicalize platform name from "macosx_app_extension" to + // "macos_app_extension". + else if (Ident->getName() == "macosx_app_extension") + Platform->Ident = PP.getIdentifierInfo("macos_app_extension"); + else + Platform->Ident = PP.getIdentifierInfo( + AvailabilityAttr::canonicalizePlatformName(Ident->getName())); + } // Parse the ',' following the platform name. if (ExpectAndConsume(tok::comma)) { @@ -1388,7 +1393,9 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // If the Decl is on a function, add function parameters to the scope. bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate(); - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope); + ParseScope FnScope( + this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, + HasFunScope); if (HasFunScope) Actions.ActOnReenterFunctionContext(Actions.CurScope, D); @@ -1555,7 +1562,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, unsigned DiagID) { for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) { - if (!Attr->isCXX11Attribute()) + if (!Attr->isCXX11Attribute() && !Attr->isC2xAttribute()) continue; if (Attr->getKind() == AttributeList::UnknownAttribute) Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored) @@ -2124,6 +2131,37 @@ Decl *Parser::ParseDeclarationAfterDeclarator( Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { + // RAII type used to track whether we're inside an initializer. + struct InitializerScopeRAII { + Parser &P; + Declarator &D; + Decl *ThisDecl; + + InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl) + : P(P), D(D), ThisDecl(ThisDecl) { + if (ThisDecl && P.getLangOpts().CPlusPlus) { + Scope *S = nullptr; + if (D.getCXXScopeSpec().isSet()) { + P.EnterScope(0); + S = P.getCurScope(); + } + P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl); + } + } + ~InitializerScopeRAII() { pop(); } + void pop() { + if (ThisDecl && P.getLangOpts().CPlusPlus) { + Scope *S = nullptr; + if (D.getCXXScopeSpec().isSet()) + S = P.getCurScope(); + P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl); + if (S) + P.ExitScope(); + } + ThisDecl = nullptr; + } + }; + // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = nullptr; switch (TemplateInfo.Kind) { @@ -2201,10 +2239,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( else Diag(ConsumeToken(), diag::err_default_special_members); } else { - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + InitializerScopeRAII InitScope(*this, D, ThisDecl); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); @@ -2227,10 +2262,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( FRI->RangeExpr = Init; } - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); if (Init.isInvalid()) { SmallVector<tok::TokenKind, 2> StopTokens; @@ -2252,23 +2284,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( ExprVector Exprs; CommaLocsTy CommaLocs; - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + InitializerScopeRAII InitScope(*this, D, ThisDecl); + + llvm::function_ref<void()> ExprListCompleter; + auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl); + auto ConstructorCompleter = [&, ThisVarDecl] { + Actions.CodeCompleteConstructor( + getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs); + }; + if (ThisVarDecl) { + // ParseExpressionList can sometimes succeed even when ThisDecl is not + // VarDecl. This is an error and it is reported in a call to + // Actions.ActOnInitializerError(). However, we call + // CodeCompleteConstructor only on VarDecls, falling back to default + // completer in other cases. + ExprListCompleter = ConstructorCompleter; } - if (ParseExpressionList(Exprs, CommaLocs, [&] { - Actions.CodeCompleteConstructor(getCurScope(), - cast<VarDecl>(ThisDecl)->getType()->getCanonicalTypeInternal(), - ThisDecl->getLocation(), Exprs); - })) { + if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) { Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); - - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } } else { // Match the ')'. T.consumeClose(); @@ -2276,10 +2312,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), @@ -2292,17 +2325,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( // Parse C++0x braced-init-list. Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); - if (D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + InitializerScopeRAII InitScope(*this, D, ThisDecl); ExprResult Init(ParseBraceInitializer()); - if (D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); @@ -2898,7 +2925,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::l_square: case tok::kw_alignas: - if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier()) + if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier()) goto DoneWithDeclSpec; ProhibitAttributes(attrs); @@ -3201,7 +3228,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Likewise, if this is a context where the identifier could be a template // name, check whether this is a deduction guide declaration. - if (getLangOpts().CPlusPlus1z && + if (getLangOpts().CPlusPlus17 && (DSContext == DSC_class || DSContext == DSC_top_level) && Actions.isDeductionGuideName(getCurScope(), *Tok.getIdentifierInfo(), Tok.getLocation()) && @@ -3437,11 +3464,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); break; - // concept - case tok::kw_concept: - isInvalid = DS.SetConceptSpec(Loc, PrevSpec, DiagID); - break; - // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, @@ -3503,6 +3525,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw__Float16: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw___float128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); @@ -3747,7 +3773,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// semicolon. /// /// struct-declaration: -/// specifier-qualifier-list struct-declarator-list +/// [C2x] attributes-specifier-seq[opt] +/// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list /// struct-declarator-list: @@ -3771,6 +3798,11 @@ void Parser::ParseStructDeclaration( return ParseStructDeclaration(DS, FieldsCallback); } + // Parse leading attributes. + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + DS.takeAttributesFrom(Attrs); + // Parse the common specifier-qualifiers-list piece. ParseSpecifierQualifierList(DS); @@ -4381,9 +4413,11 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); ProhibitAttributes(attrs); // GNU-style attributes are prohibited. - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { - if (!getLangOpts().CPlusPlus1z) - Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute) + if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { + if (getLangOpts().CPlusPlus) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 + ? diag::warn_cxx14_compat_ns_enum_attribute + : diag::ext_ns_enum_attribute) << 1 /*enumerator*/; ParseCXX11Attributes(attrs); } @@ -4506,6 +4540,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: @@ -4581,6 +4616,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: @@ -4737,6 +4773,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: @@ -4783,9 +4820,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: - // C++ Concepts TS - concept - case tok::kw_concept: - // C11 _Atomic case tok::kw__Atomic: return true; @@ -4990,7 +5024,7 @@ void Parser::ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, Optional<llvm::function_ref<void()>> CodeCompletionHandler) { - if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) && + if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); ParseCXX11Attributes(attrs); @@ -5927,7 +5961,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; CachedTokens *ExceptionSpecTokens = nullptr; - ParsedAttributes FnAttrs(AttrFactory); + ParsedAttributesWithRange FnAttrs(AttrFactory); TypeResult TrailingReturnType; /* LocalEndLoc is the end location for the local FunctionTypeLoc. @@ -5948,6 +5982,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D, RParenLoc = Tracker.getCloseLocation(); LocalEndLoc = RParenLoc; EndLoc = RParenLoc; + + // If there are attributes following the identifier list, parse them and + // prohibit them. + MaybeParseCXX11Attributes(FnAttrs); + ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, @@ -5955,7 +5994,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - HasProto = ParamInfo.size() || getLangOpts().CPlusPlus; + HasProto = ParamInfo.size() || getLangOpts().CPlusPlus + || getLangOpts().OpenCL; // If we have the closing ')', eat it. Tracker.consumeClose(); @@ -6053,6 +6093,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, TrailingReturnType = ParseTrailingReturnType(Range); EndLoc = Range.getEnd(); } + } else if (standardAttributesAllowed()) { + MaybeParseCXX11Attributes(FnAttrs); } } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 2301284b7f43b..44e7a3512098b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -77,9 +77,10 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, ParsedAttributesWithRange attrs(AttrFactory); SourceLocation attrLoc; if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { - if (!getLangOpts().CPlusPlus1z) - Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute) - << 0 /*namespace*/; + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 + ? diag::warn_cxx14_compat_ns_enum_attribute + : diag::ext_ns_enum_attribute) + << 0 /*namespace*/; attrLoc = Tok.getLocation(); ParseCXX11Attributes(attrs); } @@ -141,7 +142,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, // Normal namespace definition, not a nested-namespace-definition. } else if (InlineLoc.isValid()) { Diag(InlineLoc, diag::err_inline_nested_namespace_definition); - } else if (getLangOpts().CPlusPlus1z) { + } else if (getLangOpts().CPlusPlus17) { Diag(ExtraNamespaceLoc[0], diag::warn_cxx14_compat_nested_namespace_definition); } else { @@ -604,8 +605,8 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) { } if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc)) - Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? - diag::warn_cxx1z_compat_using_declaration_pack : + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? + diag::warn_cxx17_compat_using_declaration_pack : diag::ext_using_declaration_pack); return false; @@ -722,8 +723,8 @@ Parser::ParseUsingDeclaration(unsigned Context, } if (DeclsInGroup.size() > 1) - Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? - diag::warn_cxx1z_compat_multi_using_declaration : + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? + diag::warn_cxx17_compat_multi_using_declaration : diag::ext_multi_using_declaration); // Eat ';'. @@ -850,10 +851,10 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ ExprResult AssertMessage; if (Tok.is(tok::r_paren)) { - Diag(Tok, getLangOpts().CPlusPlus1z + Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_static_assert_no_message : diag::ext_static_assert_no_message) - << (getLangOpts().CPlusPlus1z + << (getLangOpts().CPlusPlus17 ? FixItHint() : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\"")); } else { @@ -2720,10 +2721,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, InClassInitStyle HasInClassInit = ICIS_NoInit; bool HasStaticInitializer = false; if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) { - if (BitfieldSize.get()) { - Diag(Tok, diag::err_bitfield_member_init); - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - } else if (DeclaratorInfo.isDeclarationOfFunction()) { + if (DeclaratorInfo.isDeclarationOfFunction()) { // It's a pure-specifier. if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false)) // Parse it as an expression so that Sema can diagnose it. @@ -2734,6 +2732,10 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclSpec::SCS_typedef && !DS.isFriendSpecified()) { // It's a default member initializer. + if (BitfieldSize.get()) + Diag(Tok, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_bitfield_member_init + : diag::ext_bitfield_member_init); HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } else { HasStaticInitializer = true; @@ -3193,6 +3195,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } if (Tok.is(tok::colon)) { + ParseScope InheritanceScope(this, getCurScope()->getFlags() | + Scope::ClassInheritanceScope); + ParseBaseClause(TagDecl); if (!Tok.is(tok::l_brace)) { bool SuggestFixIt = false; @@ -3620,7 +3625,7 @@ static void diagnoseDynamicExceptionSpecification( if (P.getLangOpts().CPlusPlus11) { const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)"; P.Diag(Range.getBegin(), - P.getLangOpts().CPlusPlus1z && !IsNoexcept + P.getLangOpts().CPlusPlus17 && !IsNoexcept ? diag::ext_dynamic_exception_spec : diag::warn_exception_spec_deprecated) << Range; @@ -3812,7 +3817,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { } static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, - IdentifierInfo *ScopeName) { + IdentifierInfo *ScopeName) { switch (AttributeList::getKind(AttrName, ScopeName, AttributeList::AS_CXX11)) { case AttributeList::AT_CarriesDependency: @@ -3851,11 +3856,14 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, SourceLocation ScopeLoc) { assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list"); SourceLocation LParenLoc = Tok.getLocation(); + const LangOptions &LO = getLangOpts(); + AttributeList::Syntax Syntax = + LO.CPlusPlus ? AttributeList::AS_CXX11 : AttributeList::AS_C2x; // If the attribute isn't known, we will not attempt to parse any // arguments. - if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName, - getTargetInfo(), getLangOpts())) { + if (!hasAttribute(LO.CPlusPlus ? AttrSyntax::CXX : AttrSyntax::C, ScopeName, + AttrName, getTargetInfo(), getLangOpts())) { // Eat the left paren, then skip to the ending right paren. ConsumeParen(); SkipUntil(tok::r_paren); @@ -3866,7 +3874,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, // GNU-scoped attributes have some special cases to handle GNU-specific // behaviors. ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, - ScopeLoc, AttributeList::AS_CXX11, nullptr); + ScopeLoc, Syntax, nullptr); return true; } @@ -3875,11 +3883,11 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, if (ScopeName && ScopeName->getName() == "clang") NumArgs = ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, - ScopeLoc, AttributeList::AS_CXX11); + ScopeLoc, Syntax); else NumArgs = ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, - ScopeName, ScopeLoc, AttributeList::AS_CXX11); + ScopeName, ScopeLoc, Syntax); const AttributeList *Attr = Attrs.getList(); if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) { @@ -3905,7 +3913,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, return true; } -/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. +/// ParseCXX11AttributeSpecifier - Parse a C++11 or C2x attribute-specifier. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' @@ -3937,8 +3945,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, return; } - assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) - && "Not a C++11 attribute list"); + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && + "Not a double square bracket attribute list"); Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); @@ -3948,7 +3956,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation CommonScopeLoc; IdentifierInfo *CommonScopeName = nullptr; if (Tok.is(tok::kw_using)) { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_using_attribute_ns : diag::ext_using_attribute_ns); ConsumeToken(); @@ -4014,10 +4022,12 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, ScopeName, ScopeLoc); if (!AttrParsed) - attrs.addNew(AttrName, - SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, - AttrLoc), - ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11); + attrs.addNew( + AttrName, + SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), + ScopeName, ScopeLoc, nullptr, 0, + getLangOpts().CPlusPlus ? AttributeList::AS_CXX11 + : AttributeList::AS_C2x); if (TryConsumeToken(tok::ellipsis)) Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) @@ -4032,13 +4042,13 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_square); } -/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++11 or C2x attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { - assert(getLangOpts().CPlusPlus11); + assert(standardAttributesAllowed()); SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index 44b87af01abd0..bc587628c954d 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -66,12 +66,16 @@ using namespace clang; /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// -/// relational-expression: [C99 6.5.8] +/// compare-expression: [C++20 expr.spaceship] /// shift-expression -/// relational-expression '<' shift-expression -/// relational-expression '>' shift-expression -/// relational-expression '<=' shift-expression -/// relational-expression '>=' shift-expression +/// compare-expression '<=>' shift-expression +/// +/// relational-expression: [C99 6.5.8] +/// compare-expression +/// relational-expression '<' compare-expression +/// relational-expression '>' compare-expression +/// relational-expression '<=' compare-expression +/// relational-expression '>=' compare-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression @@ -266,11 +270,13 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) { return false; } -static bool isFoldOperator(prec::Level Level) { - return Level > prec::Unknown && Level != prec::Conditional; +bool Parser::isFoldOperator(prec::Level Level) const { + return Level > prec::Unknown && Level != prec::Conditional && + Level != prec::Spaceship; } -static bool isFoldOperator(tok::TokenKind Kind) { - return isFoldOperator(getBinOpPrecedence(Kind, false, true)); + +bool Parser::isFoldOperator(tok::TokenKind Kind) const { + return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true)); } /// \brief Parse a binary expression that starts with \p LHS and has a @@ -716,6 +722,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' +/// '__has_unique_object_representations' /// /// [Clang] unary-type-trait: /// '__is_aggregate' @@ -798,7 +805,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_true: case tok::kw_false: - return ParseCXXBoolLiteral(); + Res = ParseCXXBoolLiteral(); + break; case tok::kw___objc_yes: case tok::kw___objc_no: @@ -1229,6 +1237,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_void: case tok::kw_typename: @@ -2729,7 +2738,7 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, } } - Diag(EllipsisLoc, getLangOpts().CPlusPlus1z + Diag(EllipsisLoc, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_fold_expression : diag::ext_fold_expression); @@ -2762,7 +2771,7 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, /// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, - std::function<void()> Completer) { + llvm::function_ref<void()> Completer) { bool SawError = false; while (1) { if (Tok.is(tok::code_completion)) { @@ -2881,7 +2890,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | - Scope::DeclScope); + Scope::CompoundStmtScope | Scope::DeclScope); // Inform sema that we are starting a block. Actions.ActOnBlockStart(CaretLoc, getCurScope()); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index dcafbadae5c08..959cb7a61d3a7 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -249,7 +249,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code - // code completion token follows the '::'. + // completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion @@ -966,6 +966,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // that would be an error. ParsedType InitCaptureType; + if (!Init.isInvalid()) + Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Init.isUsable()) { // Get the pointer and store it in an lvalue, so we can use it as an // out argument. @@ -989,27 +991,34 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, /// /// Returns true if it hit something unexpected. bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { - TentativeParsingAction PA(*this); + { + bool SkippedInits = false; + TentativeParsingAction PA1(*this); - bool SkippedInits = false; - Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits)); + if (ParseLambdaIntroducer(Intro, &SkippedInits)) { + PA1.Revert(); + return true; + } - if (DiagID) { - PA.Revert(); - return true; + if (!SkippedInits) { + PA1.Commit(); + return false; + } + + PA1.Revert(); } - if (SkippedInits) { - // Parse it again, but this time parse the init-captures too. - PA.Revert(); - Intro = LambdaIntroducer(); - DiagID = ParseLambdaIntroducer(Intro); - assert(!DiagID && "parsing lambda-introducer failed on reparse"); + // Try to parse it again, but this time parse the init-captures too. + Intro = LambdaIntroducer(); + TentativeParsingAction PA2(*this); + + if (!ParseLambdaIntroducer(Intro)) { + PA2.Commit(); return false; } - PA.Commit(); - return false; + PA2.Revert(); + return true; } static void @@ -1053,8 +1062,8 @@ static void addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, DeclSpec &DS) { if (ConstexprLoc.isValid()) { - P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z - ? diag::ext_constexpr_on_lambda_cxx1z + P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus17 + ? diag::ext_constexpr_on_lambda_cxx17 : diag::warn_cxx14_compat_constexpr_on_lambda); const char *PrevSpec = nullptr; unsigned DiagID = 0; @@ -1281,7 +1290,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. - unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; + unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope; ParseScope BodyScope(this, ScopeFlags); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); @@ -1351,7 +1361,6 @@ ExprResult Parser::ParseCXXCasts() { if (ExpectAndConsume(tok::greater)) return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less); - SourceLocation LParenLoc, RParenLoc; BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, CastName)) @@ -1706,6 +1715,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list +/// [Clang] type-specifier-seq ref-qualifier[opt] '[' identifier-list ']' +/// brace-or-equal-initializer /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// @@ -1751,7 +1762,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, } case ConditionOrInitStatement::InitStmtDecl: { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z + Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_init_statement : diag::ext_init_statement) << (CK == Sema::ConditionKind::Switch); @@ -1925,6 +1936,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_double: DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw__Float16: + DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw___float128: DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); break; @@ -2172,7 +2186,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, /// ! = < > += -= *= /= %= /// ^= &= |= << >> >>= <<= == != /// <= >= && || ++ -- , ->* -> -/// () [] +/// () [] <=> /// /// conversion-function-id: [C++ 12.3.2] /// operator conversion-type-id @@ -2468,7 +2482,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /*IsCtorOrDtorName=*/true, /*NonTrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, IdLoc, IdLoc); - } else if (getLangOpts().CPlusPlus1z && + } else if (getLangOpts().CPlusPlus17 && AllowDeductionGuide && SS.isEmpty() && Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc, &TemplateName)) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index 01b1bf48e4738..fb8624a324b93 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -81,8 +81,10 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { SingleDecl = ParseObjCPropertyDynamic(AtLoc); break; case tok::objc_import: - if (getLangOpts().Modules || getLangOpts().DebuggerSupport) - return ParseModuleImport(AtLoc); + if (getLangOpts().Modules || getLangOpts().DebuggerSupport) { + SingleDecl = ParseModuleImport(AtLoc); + break; + } Diag(AtLoc, diag::err_atimport); SkipUntil(tok::semi); return Actions.ConvertDeclToDeclGroup(nullptr); @@ -2478,7 +2480,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get()); // Parse the compound statement within a new scope. - ParseScope bodyScope(this, Scope::DeclScope); + ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult body(ParseCompoundStatementBody()); bodyScope.Exit(); @@ -2514,7 +2516,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { } StmtVector CatchStmts; StmtResult FinallyStmt; - ParseScope TryScope(this, Scope::DeclScope); + ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult TryBody(ParseCompoundStatementBody()); TryScope.Exit(); if (TryBody.isInvalid()) @@ -2535,7 +2537,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { ConsumeToken(); // consume catch if (Tok.is(tok::l_paren)) { ConsumeParen(); - ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope); + ParseScope CatchScope(this, Scope::DeclScope | + Scope::CompoundStmtScope | + Scope::AtCatchScope); if (Tok.isNot(tok::ellipsis)) { DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); @@ -2579,7 +2583,8 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { } else { assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); ConsumeToken(); // consume finally - ParseScope FinallyScope(this, Scope::DeclScope); + ParseScope FinallyScope(this, + Scope::DeclScope | Scope::CompoundStmtScope); StmtResult FinallyBody(true); if (Tok.is(tok::l_brace)) @@ -2616,7 +2621,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { } // Enter a scope to hold everything within the compound stmt. Compound // statements can always hold declarations. - ParseScope BodyScope(this, Scope::DeclScope); + ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope); StmtResult AutoreleasePoolBody(ParseCompoundStatementBody()); @@ -3650,11 +3655,10 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) && "Inline objective-c method not starting with '{' or 'try' or ':'"); // Enter a scope for the method or c-function body. - ParseScope BodyScope(this, - parseMethod - ? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope - : Scope::FnScope|Scope::DeclScope); - + ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) | + Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + // Tell the actions module that we have entered a method or c-function definition // with the specified Declarator for the method/function. if (parseMethod) diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp index d9a088595ab73..a67a5bbe0deaa 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp @@ -302,6 +302,7 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { for (auto *D : DRD.get()) { TentativeParsingAction TPA(*this); ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope); // Parse <combiner> expression. Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); @@ -337,14 +338,24 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { IsCorrect; if (Tok.isNot(tok::annot_pragma_openmp_end)) { ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope); // Parse expression. - Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D); - InitializerResult = Actions.ActOnFinishFullExpr( - ParseAssignmentExpression().get(), D->getLocation(), - /*DiscardedValue=*/true); + VarDecl *OmpPrivParm = + Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), + D); + // Check if initializer is omp_priv <init_expr> or something else. + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->isStr("omp_priv")) { + ConsumeToken(); + ParseOpenMPReductionInitializerForDecl(OmpPrivParm); + } else { + InitializerResult = Actions.ActOnFinishFullExpr( + ParseAssignmentExpression().get(), D->getLocation(), + /*DiscardedValue=*/true); + } Actions.ActOnOpenMPDeclareReductionInitializerEnd( - D, InitializerResult.get()); + D, InitializerResult.get(), OmpPrivParm); if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { TPA.Commit(); @@ -368,6 +379,72 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { IsCorrect); } +void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { + // Parse declarator '=' initializer. + // If a '==' or '+=' is found, suggest a fixit to '='. + if (isTokenEqualOrEqualTypo()) { + ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm); + Actions.FinalizeDeclaration(OmpPrivParm); + cutOffParsing(); + return; + } + + ExprResult Init(ParseInitializer()); + + if (Init.isInvalid()) { + SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); + Actions.ActOnInitializerError(OmpPrivParm); + } else { + Actions.AddInitializerToDecl(OmpPrivParm, Init.get(), + /*DirectInit=*/false); + } + } else if (Tok.is(tok::l_paren)) { + // Parse C++ direct initializer: '(' expression-list ')' + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprVector Exprs; + CommaLocsTy CommaLocs; + + if (ParseExpressionList(Exprs, CommaLocs, [this, OmpPrivParm, &Exprs] { + Actions.CodeCompleteConstructor( + getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), + OmpPrivParm->getLocation(), Exprs); + })) { + Actions.ActOnInitializerError(OmpPrivParm); + SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); + } else { + // Match the ')'. + T.consumeClose(); + + assert(!Exprs.empty() && Exprs.size() - 1 == CommaLocs.size() && + "Unexpected number of commas!"); + + ExprResult Initializer = Actions.ActOnParenListExpr( + T.getOpenLocation(), T.getCloseLocation(), Exprs); + Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(), + /*DirectInit=*/true); + } + } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { + // Parse C++0x braced-init-list. + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + + ExprResult Init(ParseBraceInitializer()); + + if (Init.isInvalid()) { + Actions.ActOnInitializerError(OmpPrivParm); + } else { + Actions.AddInitializerToDecl(OmpPrivParm, Init.get(), + /*DirectInit=*/true); + } + } else { + Actions.ActOnUninitializedDecl(OmpPrivParm); + } +} + namespace { /// RAII that recreates function context for correct parsing of clauses of /// 'declare simd' construct. @@ -405,8 +482,9 @@ public: // If the Decl is on a function, add function parameters to the scope. HasFunScope = D->isFunctionOrFunctionTemplate(); - FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope, - HasFunScope); + FnScope = new Parser::ParseScope( + &P, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, + HasFunScope); if (HasFunScope) Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); } @@ -682,9 +760,17 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( DKind = ParseOpenMPDirectiveKind(*this); while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - ParseExternalDeclaration(attrs); + DeclGroupPtrTy Ptr; + // Here we expect to see some function declaration. + if (AS == AS_none) { + assert(TagType == DeclSpec::TST_unspecified); + MaybeParseCXX11Attributes(Attrs); + ParsingDeclSpec PDS(*this); + Ptr = ParseExternalDeclaration(Attrs, &PDS); + } else { + Ptr = + ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); + } if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { TentativeParsingAction TPA(*this); ConsumeAnnotationToken(); @@ -813,8 +899,8 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); - unsigned ScopeFlags = - Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope; + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ConsumeAnnotationToken(), EndLoc; auto DKind = ParseOpenMPDirectiveKind(*this); OpenMPDirectiveKind CancelRegion = OMPD_unknown; @@ -1000,6 +1086,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( AssociatedStmt = ParseStatement(); Actions.ActOnFinishOfCompoundStmt(); AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || + DKind == OMPD_target_exit_data) { + Sema::CompoundScopeRAII CompoundScope(Actions); + Actions.ActOnOpenMPRegionStart(DKind, getCurScope()); + Actions.ActOnStartOfCompoundStmt(); + AssociatedStmt = + Actions.ActOnCompoundStmt(Loc, Loc, llvm::None, /*isStmtExpr=*/false); + Actions.ActOnFinishOfCompoundStmt(); + AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); } Directive = Actions.ActOnOpenMPExecutableDirective( DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, @@ -1102,7 +1197,8 @@ bool Parser::ParseOpenMPSimpleVarList( /// simdlen-clause | threads-clause | simd-clause | num_teams-clause | /// thread_limit-clause | priority-clause | grainsize-clause | /// nogroup-clause | num_tasks-clause | hint-clause | to-clause | -/// from-clause | is_device_ptr-clause | task_reduction-clause +/// from-clause | is_device_ptr-clause | task_reduction-clause | +/// in_reduction-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -1221,6 +1317,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -1586,7 +1683,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, BalancedDelimiterTracker LinearT(*this, tok::l_paren, tok::annot_pragma_openmp_end); // Handle reduction-identifier for reduction clause. - if (Kind == OMPC_reduction || Kind == OMPC_task_reduction) { + if (Kind == OMPC_reduction || Kind == OMPC_task_reduction || + Kind == OMPC_in_reduction) { ColonProtectionRAIIObject ColonRAII(*this); if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec, @@ -1734,13 +1832,14 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Diag(Tok, diag::warn_pragma_expected_colon) << "map type"; } - bool IsComma = (Kind != OMPC_reduction && Kind != OMPC_task_reduction && - Kind != OMPC_depend && Kind != OMPC_map) || - (Kind == OMPC_reduction && !InvalidReductionId) || - (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown && - (!MapTypeModifierSpecified || - Data.MapTypeModifier == OMPC_MAP_always)) || - (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); + bool IsComma = + (Kind != OMPC_reduction && Kind != OMPC_task_reduction && + Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || + (Kind == OMPC_reduction && !InvalidReductionId) || + (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown && + (!MapTypeModifierSpecified || + Data.MapTypeModifier == OMPC_MAP_always)) || + (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -1796,7 +1895,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, } /// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', -/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction' or 'task_reduction'. +/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction' or +/// 'in_reduction'. /// /// private-clause: /// 'private' '(' list ')' @@ -1814,6 +1914,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'reduction' '(' reduction-identifier ':' list ')' /// task_reduction-clause: /// 'task_reduction' '(' reduction-identifier ':' list ')' +/// in_reduction-clause: +/// 'in_reduction' '(' reduction-identifier ':' list ')' /// copyprivate-clause: /// 'copyprivate' '(' list ')' /// flush-clause: diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 262743756a6b8..198d5c6e9cb03 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -422,15 +422,20 @@ void Parser::HandlePragmaPack() { assert(Tok.is(tok::annot_pragma_pack)); PragmaPackInfo *Info = static_cast<PragmaPackInfo *>(Tok.getAnnotationValue()); - SourceLocation PragmaLoc = ConsumeAnnotationToken(); + SourceLocation PragmaLoc = Tok.getLocation(); ExprResult Alignment; if (Info->Alignment.is(tok::numeric_constant)) { Alignment = Actions.ActOnNumericConstant(Info->Alignment); - if (Alignment.isInvalid()) + if (Alignment.isInvalid()) { + ConsumeAnnotationToken(); return; + } } Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel, Alignment.get()); + // Consume the token after processing the pragma to enable pragma-specific + // #include warnings. + ConsumeAnnotationToken(); } void Parser::HandlePragmaMSStruct() { @@ -528,7 +533,8 @@ StmtResult Parser::HandlePragmaCaptured() SourceLocation Loc = Tok.getLocation(); - ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); + ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, /*NumParams=*/1); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index b1fbb20c721bd..3f25610f4471f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -453,9 +453,10 @@ StmtResult Parser::ParseSEHTryBlock() { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); - StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope | Scope::SEHTryScope)); - if(TryBlock.isInvalid()) + StmtResult TryBlock(ParseCompoundStatement( + /*isStmtExpr=*/false, + Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope)); + if (TryBlock.isInvalid()) return TryBlock; StmtResult Handler; @@ -840,7 +841,8 @@ StmtResult Parser::ParseDefaultStatement() { } StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { - return ParseCompoundStatement(isStmtExpr, Scope::DeclScope); + return ParseCompoundStatement(isStmtExpr, + Scope::DeclScope | Scope::CompoundStmtScope); } /// ParseCompoundStatement - Parse a "{}" block. @@ -1126,7 +1128,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { bool IsConstexpr = false; if (Tok.is(tok::kw_constexpr)) { - Diag(Tok, getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_constexpr_if + Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if : diag::ext_constexpr_if); IsConstexpr = true; ConsumeToken(); @@ -1477,6 +1479,9 @@ StmtResult Parser::ParseDoStatement() { DiagnoseAndSkipCXX11Attributes(); ExprResult Cond = ParseExpression(); + // Correct the typos in condition before closing the scope. + if (Cond.isUsable()) + Cond = Actions.CorrectDelayedTyposInExpr(Cond); T.consumeClose(); DoScope.Exit(); @@ -1608,7 +1613,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ForRangeInit.RangeExpr = ParseExpression(); Diag(Loc, diag::err_for_range_identifier) - << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus1z) + << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17) ? FixItHint::CreateInsertion(Loc, "auto &&") : FixItHint()); @@ -2085,9 +2090,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); - StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope | Scope::TryScope | - (FnTry ? Scope::FnTryCatchScope : 0))); + StmtResult TryBlock(ParseCompoundStatement( + /*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope | + Scope::CompoundStmtScope | + (FnTry ? Scope::FnTryCatchScope : 0))); if (TryBlock.isInvalid()) return TryBlock; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp index d6f16bb0cb79e..d81029e279740 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp @@ -54,54 +54,13 @@ public: assert(AsmToks.size() == AsmTokOffsets.size()); } - void *LookupInlineAsmIdentifier(StringRef &LineBuf, - llvm::InlineAsmIdentifierInfo &Info, - bool IsUnevaluatedContext) override { - // Collect the desired tokens. - SmallVector<Token, 16> LineToks; - const Token *FirstOrigToken = nullptr; - findTokensForString(LineBuf, LineToks, FirstOrigToken); - - unsigned NumConsumedToks; - ExprResult Result = TheParser.ParseMSAsmIdentifier( - LineToks, NumConsumedToks, &Info, IsUnevaluatedContext); - - // If we consumed the entire line, tell MC that. - // Also do this if we consumed nothing as a way of reporting failure. - if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { - // By not modifying LineBuf, we're implicitly consuming it all. - - // Otherwise, consume up to the original tokens. - } else { - assert(FirstOrigToken && "not using original tokens?"); - - // Since we're using original tokens, apply that offset. - assert(FirstOrigToken[NumConsumedToks].getLocation() == - LineToks[NumConsumedToks].getLocation()); - unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); - unsigned LastIndex = FirstIndex + NumConsumedToks - 1; - - // The total length we've consumed is the relative offset - // of the last token we consumed plus its length. - unsigned TotalOffset = - (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() - - AsmTokOffsets[FirstIndex]); - LineBuf = LineBuf.substr(0, TotalOffset); - } - - // Initialize the "decl" with the lookup result. - Info.OpDecl = static_cast<void *>(Result.get()); - return Info.OpDecl; - } + void LookupInlineAsmIdentifier(StringRef &LineBuf, + llvm::InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) override; StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, llvm::SMLoc Location, - bool Create) override { - SourceLocation Loc = translateLocation(LSM, Location); - LabelDecl *Label = - TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); - return Label->getMSAsmLabel(); - } + bool Create) override; bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset) override { @@ -116,78 +75,133 @@ public: private: /// Collect the appropriate tokens for the given string. void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks, - const Token *&FirstOrigToken) const { - // For now, assert that the string we're working with is a substring - // of what we gave to MC. This lets us use the original tokens. - assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) && - !std::less<const char *>()(AsmString.end(), Str.end())); + const Token *&FirstOrigToken) const; - // Try to find a token whose offset matches the first token. - unsigned FirstCharOffset = Str.begin() - AsmString.begin(); - const unsigned *FirstTokOffset = std::lower_bound( - AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset); + SourceLocation translateLocation(const llvm::SourceMgr &LSM, + llvm::SMLoc SMLoc); - // For now, assert that the start of the string exactly - // corresponds to the start of a token. - assert(*FirstTokOffset == FirstCharOffset); + void handleDiagnostic(const llvm::SMDiagnostic &D); +}; +} - // Use all the original tokens for this line. (We assume the - // end of the line corresponds cleanly to a token break.) - unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); - FirstOrigToken = &AsmToks[FirstTokIndex]; - unsigned LastCharOffset = Str.end() - AsmString.begin(); - for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { - if (AsmTokOffsets[i] >= LastCharOffset) - break; - TempToks.push_back(AsmToks[i]); - } +void ClangAsmParserCallback::LookupInlineAsmIdentifier( + StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) { + // Collect the desired tokens. + SmallVector<Token, 16> LineToks; + const Token *FirstOrigToken = nullptr; + findTokensForString(LineBuf, LineToks, FirstOrigToken); + + unsigned NumConsumedToks; + ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, + IsUnevaluatedContext); + + // If we consumed the entire line, tell MC that. + // Also do this if we consumed nothing as a way of reporting failure. + if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { + // By not modifying LineBuf, we're implicitly consuming it all. + + // Otherwise, consume up to the original tokens. + } else { + assert(FirstOrigToken && "not using original tokens?"); + + // Since we're using original tokens, apply that offset. + assert(FirstOrigToken[NumConsumedToks].getLocation() == + LineToks[NumConsumedToks].getLocation()); + unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); + unsigned LastIndex = FirstIndex + NumConsumedToks - 1; + + // The total length we've consumed is the relative offset + // of the last token we consumed plus its length. + unsigned TotalOffset = + (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() - + AsmTokOffsets[FirstIndex]); + LineBuf = LineBuf.substr(0, TotalOffset); } - SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) { - // Compute an offset into the inline asm buffer. - // FIXME: This isn't right if .macro is involved (but hopefully, no - // real-world code does that). - const llvm::MemoryBuffer *LBuf = - LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc)); - unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); + // Initialize Info with the lookup result. + if (!Result.isUsable()) + return; + TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info); +} - // Figure out which token that offset points into. - const unsigned *TokOffsetPtr = - std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); - unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); - unsigned TokOffset = *TokOffsetPtr; +StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier, + llvm::SourceMgr &LSM, + llvm::SMLoc Location, + bool Create) { + SourceLocation Loc = translateLocation(LSM, Location); + LabelDecl *Label = + TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); + return Label->getMSAsmLabel(); +} - // If we come up with an answer which seems sane, use it; otherwise, - // just point at the __asm keyword. - // FIXME: Assert the answer is sane once we handle .macro correctly. - SourceLocation Loc = AsmLoc; - if (TokIndex < AsmToks.size()) { - const Token &Tok = AsmToks[TokIndex]; - Loc = Tok.getLocation(); - Loc = Loc.getLocWithOffset(Offset - TokOffset); - } - return Loc; +void ClangAsmParserCallback::findTokensForString( + StringRef Str, SmallVectorImpl<Token> &TempToks, + const Token *&FirstOrigToken) const { + // For now, assert that the string we're working with is a substring + // of what we gave to MC. This lets us use the original tokens. + assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) && + !std::less<const char *>()(AsmString.end(), Str.end())); + + // Try to find a token whose offset matches the first token. + unsigned FirstCharOffset = Str.begin() - AsmString.begin(); + const unsigned *FirstTokOffset = std::lower_bound( + AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset); + + // For now, assert that the start of the string exactly + // corresponds to the start of a token. + assert(*FirstTokOffset == FirstCharOffset); + + // Use all the original tokens for this line. (We assume the + // end of the line corresponds cleanly to a token break.) + unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); + FirstOrigToken = &AsmToks[FirstTokIndex]; + unsigned LastCharOffset = Str.end() - AsmString.begin(); + for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { + if (AsmTokOffsets[i] >= LastCharOffset) + break; + TempToks.push_back(AsmToks[i]); } +} + +SourceLocation +ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM, + llvm::SMLoc SMLoc) { + // Compute an offset into the inline asm buffer. + // FIXME: This isn't right if .macro is involved (but hopefully, no + // real-world code does that). + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc)); + unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); - void handleDiagnostic(const llvm::SMDiagnostic &D) { - const llvm::SourceMgr &LSM = *D.getSourceMgr(); - SourceLocation Loc = translateLocation(LSM, D.getLoc()); - TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); + // Figure out which token that offset points into. + const unsigned *TokOffsetPtr = + std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); + unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); + unsigned TokOffset = *TokOffsetPtr; + + // If we come up with an answer which seems sane, use it; otherwise, + // just point at the __asm keyword. + // FIXME: Assert the answer is sane once we handle .macro correctly. + SourceLocation Loc = AsmLoc; + if (TokIndex < AsmToks.size()) { + const Token &Tok = AsmToks[TokIndex]; + Loc = Tok.getLocation(); + Loc = Loc.getLocWithOffset(Offset - TokOffset); } -}; + return Loc; +} + +void ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) { + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + SourceLocation Loc = translateLocation(LSM, D.getLoc()); + TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); } /// Parse an identifier in an MS-style inline assembly block. -/// -/// \param CastInfo - a void* so that we don't have to teach Parser.h -/// about the actual type. ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, unsigned &NumLineToksConsumed, - void *CastInfo, bool IsUnevaluatedContext) { - llvm::InlineAsmIdentifierInfo &Info = - *(llvm::InlineAsmIdentifierInfo *)CastInfo; - // Push a fake token on the end so that we don't overrun the token // stream. We use ';' because it expression-parsing should never // overrun it. @@ -227,7 +241,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, /*AllowDeductionGuide=*/false, /*ObjectType=*/nullptr, TemplateKWLoc, Id); // Perform the lookup. - Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, + Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, IsUnevaluatedContext); } // While the next two tokens are 'period' 'identifier', repeatedly parse it as @@ -241,7 +255,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, IdentifierInfo *Id = Tok.getIdentifierInfo(); ConsumeToken(); // Consume the identifier. Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(), - Info, Tok.getLocation()); + Tok.getLocation()); } // Figure out how many tokens we are into LineToks. @@ -564,7 +578,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); - TargetOptions TO = Actions.Context.getTargetInfo().getTargetOpts(); + const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts(); std::string FeaturesStr = llvm::join(TO.Features.begin(), TO.Features.end(), ","); @@ -578,8 +592,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { llvm::SourceMgr TempSrcMgr; llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); - MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, llvm::CodeModel::Default, - Ctx); + MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx); std::unique_ptr<llvm::MemoryBuffer> Buffer = llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 944cd775d52a4..6df9df804fd7e 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -112,7 +112,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; - SmallVector<Decl*, 4> TemplateParams; + SmallVector<NamedDecl*, 4> TemplateParams; if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a '}'. @@ -197,10 +197,11 @@ Parser::ParseSingleDeclarationAfterTemplate( MaybeParseCXX11Attributes(prefixAttrs); if (Tok.is(tok::kw_using)) { - // FIXME: We should return the DeclGroup to the caller. - ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, - prefixAttrs); - return nullptr; + auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, + prefixAttrs); + if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl()) + return nullptr; + return usingDeclPtr.get().getSingleDecl(); } // Parse the declaration specifiers, stealing any diagnostics from @@ -329,10 +330,9 @@ Parser::ParseSingleDeclarationAfterTemplate( /// that enclose this template parameter list. /// /// \returns true if an error occurred, false otherwise. -bool Parser::ParseTemplateParameters(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams, - SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc) { +bool Parser::ParseTemplateParameters( + unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams, + SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { // Get the template parameter list. if (!TryConsumeToken(tok::less, LAngleLoc)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; @@ -370,11 +370,12 @@ bool Parser::ParseTemplateParameters(unsigned Depth, /// template-parameter-list ',' template-parameter bool Parser::ParseTemplateParameterList(unsigned Depth, - SmallVectorImpl<Decl*> &TemplateParams) { + SmallVectorImpl<NamedDecl*> &TemplateParams) { while (1) { + // FIXME: ParseTemplateParameter should probably just return a NamedDecl. if (Decl *TmpParam = ParseTemplateParameter(Depth, TemplateParams.size())) { - TemplateParams.push_back(TmpParam); + TemplateParams.push_back(dyn_cast<NamedDecl>(TmpParam)); } else { // If we failed to parse a template parameter, skip until we find // a comma or closing brace. @@ -569,7 +570,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); - SmallVector<Decl*,8> TemplateParams; + SmallVector<NamedDecl*,8> TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { ParseScope TemplateParmScope(this, Scope::TemplateParamScope); @@ -589,10 +590,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; if (Tok.is(tok::kw_typename)) { Diag(Tok.getLocation(), - getLangOpts().CPlusPlus1z + getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_template_template_param_typename : diag::ext_template_template_param_typename) - << (!getLangOpts().CPlusPlus1z + << (!getLangOpts().CPlusPlus17 ? FixItHint::CreateReplacement(Tok.getLocation(), "class") : FixItHint()); } else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater, @@ -1023,8 +1024,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, ? OO_None : TemplateName.OperatorFunctionId.Operator; - TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
- SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( + SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); Tok.setAnnotationValue(TemplateId); @@ -1380,7 +1381,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); // Recreate the containing function DeclContext. Sema::ContextRAII FunctionSavedContext(Actions, diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index d6684c39aa734..5c206f4eab90b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -1026,6 +1026,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char: case tok::kw_const: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_enum: case tok::kw_half: @@ -1298,11 +1299,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // 'friend' // 'typedef' // 'constexpr' - // 'concept' case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: - case tok::kw_concept: // storage-class-specifier case tok::kw_register: case tok::kw_static: @@ -1510,6 +1509,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_void: case tok::annot_decltype: @@ -1600,6 +1600,7 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_void: case tok::kw___unknown_anytype: diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 1ed7ef9663589..72d653797c60a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -556,10 +556,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { HandlePragmaUnused(); return false; - case tok::kw_import: - Result = ParseModuleImport(SourceLocation()); - return false; - case tok::kw_export: if (NextToken().isNot(tok::kw_module)) break; @@ -637,6 +633,9 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration +/// +/// [Modules-TS] module-import-declaration +/// Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS) { @@ -753,11 +752,20 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SingleDecl = ParseObjCMethodDefinition(); break; case tok::code_completion: - Actions.CodeCompleteOrdinaryName(getCurScope(), - CurParsedObjCImpl? Sema::PCC_ObjCImplementation - : Sema::PCC_Namespace); + if (CurParsedObjCImpl) { + // Code-complete Objective-C methods even without leading '-'/'+' prefix. + Actions.CodeCompleteObjCMethodDecl(getCurScope(), + /*IsInstanceMethod=*/None, + /*ReturnType=*/nullptr); + } + Actions.CodeCompleteOrdinaryName( + getCurScope(), + CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); cutOffParsing(); return nullptr; + case tok::kw_import: + SingleDecl = ParseModuleImport(SourceLocation()); + break; case tok::kw_export: if (getLangOpts().ModulesTS) { SingleDecl = ParseExportDeclaration(); @@ -1073,8 +1081,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, TemplateInfo.Kind == ParsedTemplateInfo::Template && Actions.canDelayFunctionBody(D)) { MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); - - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); @@ -1104,7 +1113,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && Actions.CurContext->isTranslationUnit()) { - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); @@ -1122,7 +1132,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, } // Enter a scope for the function body. - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. @@ -2045,7 +2056,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { SourceLocation StartLoc = Tok.getLocation(); Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export) - ? Sema::ModuleDeclKind::Module + ? Sema::ModuleDeclKind::Interface : Sema::ModuleDeclKind::Implementation; assert(Tok.is(tok::kw_module) && "not a module declaration"); @@ -2054,7 +2065,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) && Tok.getIdentifierInfo()->isStr("partition")) { // If 'partition' is present, this must be a module interface unit. - if (MDK != Sema::ModuleDeclKind::Module) + if (MDK != Sema::ModuleDeclKind::Interface) Diag(Tok.getLocation(), diag::err_module_implementation_partition) << FixItHint::CreateInsertion(ModuleLoc, "export "); MDK = Sema::ModuleDeclKind::Partition; @@ -2083,7 +2094,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { /// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: /// 'import' module-name attribute-specifier-seq[opt] ';' -Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { +Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import) : Tok.isObjCAtKeyword(tok::objc_import)) && "Improper start to module import"); @@ -2110,7 +2121,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { if (Import.isInvalid()) return nullptr; - return Actions.ConvertDeclToDeclGroup(Import.get()); + return Import.get(); } /// Parse a C++ Modules TS / Objective-C module name (both forms use the same diff --git a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp index 9e307f31be11c..23d1895e31b4c 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp @@ -289,6 +289,11 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID, " body { color:#000000; background-color:#ffffff }\n" " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" " h1 { font-size:14pt }\n" + " .FileName { margin-top: 5px; margin-bottom: 5px; display: inline; }\n" + " .FileNav { margin-left: 5px; margin-right: 5px; display: inline; }\n" + " .FileNav a { text-decoration:none; font-size: larger; }\n" + " .divider { margin-top: 30px; margin-bottom: 30px; height: 15px; }\n" + " .divider { background-color: gray; }\n" " .code { border-collapse:collapse; width:100%; }\n" " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n" " .code { line-height: 1.2em }\n" diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index f83baa790b497..0033edf326ac5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -29,7 +29,7 @@ #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/UninitializedValues.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Basic/SourceLocation.h" @@ -289,14 +289,14 @@ enum ThrowState { static bool isThrowCaught(const CXXThrowExpr *Throw, const CXXCatchStmt *Catch) { + const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); + if (!CaughtType) + return true; const Type *ThrowType = nullptr; if (Throw->getSubExpr()) ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull(); if (!ThrowType) return false; - const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); - if (!CaughtType) - return true; if (ThrowType->isReferenceType()) ThrowType = ThrowType->castAs<ReferenceType>() ->getPointeeType() @@ -361,8 +361,7 @@ static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { SmallVector<CFGBlock *, 16> Stack; Stack.push_back(&BodyCFG->getEntry()); while (!Stack.empty()) { - CFGBlock *CurBlock = Stack.back(); - Stack.pop_back(); + CFGBlock *CurBlock = Stack.pop_back_val(); unsigned ID = CurBlock->getBlockID(); ThrowState CurState = States[ID]; @@ -426,7 +425,7 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (FPT->isNothrow(FD->getASTContext())) + if (FPT->isNothrow(FD->getASTContext()) || FD->hasAttr<NoThrowAttr>()) return true; return false; } @@ -1276,7 +1275,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP, tok::r_square, tok::r_square }; - bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z; + bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17; StringRef MacroName; if (PreferClangAttr) @@ -1292,16 +1291,15 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP, static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction) { - // Only perform this analysis when using C++11. There is no good workflow - // for this warning when not using C++11. There is no good way to silence - // the warning (no attribute is available) unless we are using C++11's support - // for generalized attributes. Once could use pragmas to silence the warning, - // but as a general solution that is gross and not in the spirit of this - // warning. + // Only perform this analysis when using [[]] attributes. There is no good + // workflow for this warning when not using C++11. There is no good way to + // silence the warning (no attribute is available) unless we are using + // [[]] attributes. One could use pragmas to silence the warning, but as a + // general solution that is gross and not in the spirit of this warning. // - // NOTE: This an intermediate solution. There are on-going discussions on + // NOTE: This an intermediate solution. There are on-going discussions on // how to properly support this warning outside of C++11 with an annotation. - if (!AC.getASTContext().getLangOpts().CPlusPlus11) + if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes) return; FallthroughMapper FM(S); @@ -2082,10 +2080,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // time. DiagnosticsEngine &Diags = S.getDiagnostics(); - // Do not do any analysis for declarations in system headers if we are - // going to just ignore them. - if (Diags.getSuppressSystemWarnings() && - S.SourceMgr.isInSystemHeader(D->getLocation())) + // Do not do any analysis if we are going to just ignore them. + if (Diags.getIgnoreAllWarnings() || + (Diags.getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation()))) return; // For code in dependent contexts, we'll do this at instantiation time. diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp index 724db456785fb..14d334746f1fd 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp @@ -114,7 +114,8 @@ static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName, // Normalize the attribute name, __foo__ becomes foo. This is only allowable // for GNU attributes. bool IsGNU = SyntaxUsed == AttributeList::AS_GNU || - (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu"); + ((SyntaxUsed == AttributeList::AS_CXX11 || + SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu"); if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") && AttrName.endswith("__")) AttrName = AttrName.slice(2, AttrName.size() - 2); @@ -135,7 +136,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, // Ensure that in the case of C++11 attributes, we look for '::foo' if it is // unscoped. - if (ScopeName || SyntaxUsed == AS_CXX11) + if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x) FullName += "::"; FullName += AttrName; diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index f5b0104462f78..542b65327b7d2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -613,24 +613,20 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { /// /// If the name needs to be constructed as a string, that string will be /// saved into Saved and the returned StringRef will refer to it. -static StringRef getOrderedName(const CodeCompletionResult &R, - std::string &Saved) { - switch (R.Kind) { - case CodeCompletionResult::RK_Keyword: - return R.Keyword; - - case CodeCompletionResult::RK_Pattern: - return R.Pattern->getTypedText(); - - case CodeCompletionResult::RK_Macro: - return R.Macro->getName(); - - case CodeCompletionResult::RK_Declaration: +StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const { + switch (Kind) { + case RK_Keyword: + return Keyword; + case RK_Pattern: + return Pattern->getTypedText(); + case RK_Macro: + return Macro->getName(); + case RK_Declaration: // Handle declarations below. break; } - DeclarationName Name = R.Declaration->getDeclName(); + DeclarationName Name = Declaration->getDeclName(); // If the name is a simple identifier (by far the common case), or a // zero-argument selector, just return a reference to that identifier. @@ -648,8 +644,8 @@ static StringRef getOrderedName(const CodeCompletionResult &R, bool clang::operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y) { std::string XSaved, YSaved; - StringRef XStr = getOrderedName(X, XSaved); - StringRef YStr = getOrderedName(Y, YSaved); + StringRef XStr = X.getOrderedName(XSaved); + StringRef YStr = Y.getOrderedName(YSaved); int cmp = XStr.compare_lower(YStr); if (cmp) return cmp < 0; diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index e4e84fcec954b..6fe2dcc9895fb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -336,6 +336,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_decimal32: case TST_decimal64: case TST_double: + case TST_Float16: case TST_float128: case TST_enum: case TST_error: @@ -505,6 +506,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_float16: return "_Float16"; case DeclSpec::TST_float128: return "__float128"; case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool"; case DeclSpec::TST_decimal32: return "_Decimal32"; @@ -967,18 +969,6 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, return false; } -bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - if (Concept_specified) { - DiagID = diag::ext_duplicate_declspec; - PrevSpec = "concept"; - return true; - } - Concept_specified = true; - ConceptLoc = Loc; - return false; -} - void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Sign = getTypeSpecSign(); writtenBS.Width = getTypeSpecWidth(); diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp index b7e343c647183..77ace0cfa579f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -19,8 +19,6 @@ using namespace clang; ///\brief Constructs a new multiplexing external sema source and appends the /// given element to it. /// -///\param[in] source - An ExternalSemaSource. -/// MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1, ExternalSemaSource &s2){ Sources.push_back(&s1); diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index a18f71422fde6..4e57e5ef81c6f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -70,6 +70,49 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); } +namespace clang { +namespace sema { + +class SemaPPCallbacks : public PPCallbacks { + Sema *S = nullptr; + llvm::SmallVector<SourceLocation, 8> IncludeStack; + +public: + void set(Sema &S) { this->S = &S; } + + void reset() { S = nullptr; } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override { + if (!S) + return; + switch (Reason) { + case EnterFile: { + SourceManager &SM = S->getSourceManager(); + SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc)); + if (IncludeLoc.isValid()) { + IncludeStack.push_back(IncludeLoc); + S->DiagnoseNonDefaultPragmaPack( + Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc); + } + break; + } + case ExitFile: + if (!IncludeStack.empty()) + S->DiagnoseNonDefaultPragmaPack( + Sema::PragmaPackDiagnoseKind::ChangedStateAtExit, + IncludeStack.pop_back_val()); + break; + default: + break; + } + } +}; + +} // end namespace sema +} // end namespace clang + Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : ExternalSource(nullptr), isMultiplexExternalSource(false), @@ -122,6 +165,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Initilization of data sharing attributes stack for OpenMP InitDataSharingAttributesStack(); + + std::unique_ptr<sema::SemaPPCallbacks> Callbacks = + llvm::make_unique<sema::SemaPPCallbacks>(); + SemaPPCallbackHandler = Callbacks.get(); + PP.addPPCallbacks(std::move(Callbacks)); + SemaPPCallbackHandler->set(*this); } void Sema::addImplicitTypedef(StringRef Name, QualType T) { @@ -306,6 +355,10 @@ Sema::~Sema() { // Destroys data sharing attributes stack for OpenMP DestroyDataSharingAttributesStack(); + // Detach from the PP callback handler which outlives Sema since it's owned + // by the preprocessor. + SemaPPCallbackHandler->reset(); + assert(DelayedTypos.empty() && "Uncorrected typos!"); } @@ -383,14 +436,26 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, } void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { - if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) - return; - if (E->getType()->isNullPtrType()) + if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant, + E->getLocStart())) return; // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) return; + if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) + return; + if (E->IgnoreParenImpCasts()->getType()->isNullPtrType()) + return; + + // If it is a macro from system header, and if the macro name is not "NULL", + // do not warn. + SourceLocation MaybeMacroLoc = E->getLocStart(); + if (Diags.getSuppressSystemWarnings() && + SourceMgr.isInSystemMacro(MaybeMacroLoc) && + !findMacroSpelling(MaybeMacroLoc, "NULL")) + return; + Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant) << FixItHint::CreateReplacement(E->getSourceRange(), "nullptr"); } @@ -464,7 +529,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean; case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean; } - return CK_Invalid; + llvm_unreachable("unknown scalar type kind"); } /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. @@ -529,6 +594,23 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } +static bool isFunctionOrVarDeclExternC(NamedDecl *ND) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isExternC(); + return cast<VarDecl>(ND)->isExternC(); +} + +/// Determine whether ND is an external-linkage function or variable whose +/// type has no linkage. +bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) { + // Note: it's not quite enough to check whether VD has UniqueExternalLinkage, + // because we also want to catch the case where its type has VisibleNoLinkage, + // which does not affect the linkage of VD. + return getLangOpts().CPlusPlus && VD->hasExternalFormalLinkage() && + !isExternalFormalLinkage(VD->getType()->getLinkage()) && + !isFunctionOrVarDeclExternC(VD); +} + /// Obtains a sorted list of functions and variables that are undefined but /// ODR-used. void Sema::getUndefinedButUsed( @@ -545,17 +627,27 @@ void Sema::getUndefinedButUsed( if (isa<CXXDeductionGuideDecl>(ND)) continue; + if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { + // An exported function will always be emitted when defined, so even if + // the function is inline, it doesn't have to be emitted in this TU. An + // imported function implies that it has been exported somewhere else. + continue; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; if (FD->isExternallyVisible() && + !isExternalWithNoLinkageType(FD) && !FD->getMostRecentDecl()->isInlined()) continue; } else { auto *VD = cast<VarDecl>(ND); if (VD->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline()) + if (VD->isExternallyVisible() && + !isExternalWithNoLinkageType(VD) && + !VD->getMostRecentDecl()->isInline()) continue; } @@ -573,33 +665,43 @@ static void checkUndefinedButUsed(Sema &S) { S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; - for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator - I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { - NamedDecl *ND = I->first; + for (auto Undef : Undefined) { + ValueDecl *VD = cast<ValueDecl>(Undef.first); + SourceLocation UseLoc = Undef.second; - if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { - // An exported function will always be emitted when defined, so even if - // the function is inline, it doesn't have to be emitted in this TU. An - // imported function implies that it has been exported somewhere else. - continue; - } - - if (!ND->isExternallyVisible()) { - S.Diag(ND->getLocation(), diag::warn_undefined_internal) - << isa<VarDecl>(ND) << ND; - } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { + if (S.isExternalWithNoLinkageType(VD)) { + // C++ [basic.link]p8: + // A type without linkage shall not be used as the type of a variable + // or function with external linkage unless + // -- the entity has C language linkage + // -- the entity is not odr-used or is defined in the same TU + // + // As an extension, accept this in cases where the type is externally + // visible, since the function or variable actually can be defined in + // another translation unit in that case. + S.Diag(VD->getLocation(), isExternallyVisible(VD->getType()->getLinkage()) + ? diag::ext_undefined_internal_type + : diag::err_undefined_internal_type) + << isa<VarDecl>(VD) << VD; + } else if (!VD->isExternallyVisible()) { + // FIXME: We can promote this to an error. The function or variable can't + // be defined anywhere else, so the program must necessarily violate the + // one definition rule. + S.Diag(VD->getLocation(), diag::warn_undefined_internal) + << isa<VarDecl>(VD) << VD; + } else if (auto *FD = dyn_cast<FunctionDecl>(VD)) { (void)FD; assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); // FIXME: This is ill-formed; we should reject. - S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; + S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD; } else { - assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() && + assert(cast<VarDecl>(VD)->getMostRecentDecl()->isInline() && "used var requires definition but isn't inline or internal?"); - S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND; + S.Diag(VD->getLocation(), diag::err_undefined_inline_var) << VD; } - if (I->second.isValid()) - S.Diag(I->second, diag::note_used_here); + if (UseLoc.isValid()) + S.Diag(UseLoc, diag::note_used_here); } S.UndefinedButUsed.clear(); @@ -635,7 +737,8 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, E = RD->decls_end(); I != E && Complete; ++I) { if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) - Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M)); + Complete = M->isDefined() || M->isDefaulted() || + (M->isPure() && !isa<CXXDestructorDecl>(M)); else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) // If the template function is marked as late template parsed at this // point, it has not been instantiated and therefore we have not @@ -713,10 +816,24 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() { /// declarations. void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().ModulesTS) { + SourceLocation StartOfTU = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + // We start in the global module; all those declarations are implicitly // module-private (though they do not have module linkage). - Context.getTranslationUnitDecl()->setModuleOwnershipKind( - Decl::ModuleOwnershipKind::ModulePrivate); + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU); + assert(GlobalModule && "module creation should not fail"); + + // Enter the scope of the global module. + ModuleScopes.push_back({}); + ModuleScopes.back().Module = GlobalModule; + VisibleModules.setVisible(GlobalModule, StartOfTU); + + // All declarations created from now on are owned by the global module. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + TU->setLocalOwningModule(GlobalModule); } } @@ -769,6 +886,7 @@ void Sema::ActOnEndOfTranslationUnit() { CheckDelayedMemberExceptionSpecs(); } + DiagnoseUnterminatedPragmaPack(); DiagnoseUnterminatedPragmaAttribute(); // All delayed member exception specs should be checked or we end up accepting @@ -825,6 +943,17 @@ void Sema::ActOnEndOfTranslationUnit() { } if (TUKind == TU_Module) { + // If we are building a module interface unit, we need to have seen the + // module declaration by now. + if (getLangOpts().getCompilingModule() == + LangOptions::CMK_ModuleInterface && + ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) { + // FIXME: Make a better guess as to where to put the module declaration. + Diag(getSourceManager().getLocForStartOfFile( + getSourceManager().getMainFileID()), + diag::err_module_declaration_missing); + } + // If we are building a module, resolve all of the exported declarations // now. if (Module *CurrentModule = PP.getCurrentModule()) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 8c13ead644574..4ba2a317e1f97 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -61,6 +61,17 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context, Alignment * 8)); } + if (PackIncludeStack.empty()) + return; + // The #pragma pack affected a record in an included file, so Clang should + // warn when that pragma was written in a file that included the included + // file. + for (auto &PackedInclude : llvm::reverse(PackIncludeStack)) { + if (PackedInclude.CurrentPragmaLocation != PackStack.CurrentPragmaLocation) + break; + if (PackedInclude.HasNonDefaultValue) + PackedInclude.ShouldWarnOnInclude = true; + } } void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { @@ -202,6 +213,61 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal); } +void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind, + SourceLocation IncludeLoc) { + if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) { + SourceLocation PrevLocation = PackStack.CurrentPragmaLocation; + // Warn about non-default alignment at #includes (without redundant + // warnings for the same directive in nested includes). + // The warning is delayed until the end of the file to avoid warnings + // for files that don't have any records that are affected by the modified + // alignment. + bool HasNonDefaultValue = + PackStack.hasValue() && + (PackIncludeStack.empty() || + PackIncludeStack.back().CurrentPragmaLocation != PrevLocation); + PackIncludeStack.push_back( + {PackStack.CurrentValue, + PackStack.hasValue() ? PrevLocation : SourceLocation(), + HasNonDefaultValue, /*ShouldWarnOnInclude*/ false}); + return; + } + + assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind"); + PackIncludeState PrevPackState = PackIncludeStack.pop_back_val(); + if (PrevPackState.ShouldWarnOnInclude) { + // Emit the delayed non-default alignment at #include warning. + Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include); + Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here); + } + // Warn about modified alignment after #includes. + if (PrevPackState.CurrentValue != PackStack.CurrentValue) { + Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include); + Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here); + } +} + +void Sema::DiagnoseUnterminatedPragmaPack() { + if (PackStack.Stack.empty()) + return; + bool IsInnermost = true; + for (const auto &StackSlot : llvm::reverse(PackStack.Stack)) { + Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof); + // The user might have already reset the alignment, so suggest replacing + // the reset with a pop. + if (IsInnermost && PackStack.CurrentValue == PackStack.DefaultValue) { + DiagnosticBuilder DB = Diag(PackStack.CurrentPragmaLocation, + diag::note_pragma_pack_pop_instead_reset); + SourceLocation FixItLoc = Lexer::findLocationAfterToken( + PackStack.CurrentPragmaLocation, tok::l_paren, SourceMgr, LangOpts, + /*SkipTrailing=*/false); + if (FixItLoc.isValid()) + DB << FixItHint::CreateInsertion(FixItLoc, "pop"); + } + IsInnermost = false; + } +} + void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) { MSStructPragmaOn = (Kind == PMSST_ON); } @@ -249,7 +315,8 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, return; } if (Action & PSK_Push) - Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation)); + Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation, + PragmaLocation); else if (Action & PSK_Pop) { if (!StackSlotLabel.empty()) { // If we've got a label, try to find it and jump there. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index d603101c3fd9c..ad6348685b64e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp @@ -2458,24 +2458,17 @@ void CastOperation::CheckCStyleCast() { // GCC's cast to union extension. if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) { RecordDecl *RD = DestRecordTy->getDecl(); - RecordDecl::field_iterator Field, FieldEnd; - for (Field = RD->field_begin(), FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) && - !Field->isUnnamedBitfield()) { - Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) - << SrcExpr.get()->getSourceRange(); - break; - } - } - if (Field == FieldEnd) { + if (CastExpr::getTargetFieldForToUnionCast(RD, SrcType)) { + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) + << SrcExpr.get()->getSourceRange(); + Kind = CK_ToUnion; + return; + } else { Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type) << SrcType << SrcExpr.get()->getSourceRange(); SrcExpr = ExprError(); return; } - Kind = CK_ToUnion; - return; } // OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index b2223b7550614..94070bb9c9aa1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -1,4 +1,4 @@ -//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// +//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,34 +12,88 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/AttrIterator.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" +#include "clang/AST/NSAPI.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" #include "clang/Analysis/Analyses/FormatString.h" +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/SyncScope.h" #include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TypeTraits.h" #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/Locale.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <functional> +#include <limits> +#include <string> +#include <tuple> +#include <utility> using namespace clang; using namespace sema; @@ -98,6 +152,28 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { return false; } +static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { + // We need at least one argument. + if (TheCall->getNumArgs() < 1) { + S.Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return true; + } + + // All arguments should be wide string literals. + for (Expr *Arg : TheCall->arguments()) { + auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts()); + if (!Literal || !Literal->isWide()) { + S.Diag(Arg->getLocStart(), diag::err_msvc_annotation_wide_str) + << Arg->getSourceRange(); + return true; + } + } + + return false; +} + /// Check that the argument to __builtin_addressof is a glvalue, and set the /// result type to the corresponding pointer type. static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { @@ -299,6 +375,41 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { return IllegalParams; } +static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { + if (!S.getOpenCLOptions().isEnabled("cl_khr_subgroups")) { + S.Diag(Call->getLocStart(), diag::err_opencl_requires_extension) + << 1 << Call->getDirectCallee() << "cl_khr_subgroups"; + return true; + } + return false; +} + +static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { + if (checkArgCount(S, TheCall, 2)) + return true; + + if (checkOpenCLSubgroupExt(S, TheCall)) + return true; + + // First argument is an ndrange_t type. + Expr *NDRangeArg = TheCall->getArg(0); + if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") { + S.Diag(NDRangeArg->getLocStart(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; + return true; + } + + Expr *BlockArg = TheCall->getArg(1); + if (!isBlockPointer(BlockArg)) { + S.Diag(BlockArg->getLocStart(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + return checkOpenCLBlockArgs(S, BlockArg); +} + /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. @@ -580,7 +691,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // OpenCL v2.0 s6.13.16.2 - The built-in read/write // functions have two forms. switch (Call->getNumArgs()) { - case 2: { + case 2: if (checkOpenCLPipeArg(S, Call)) return true; // The call with 2 arguments should be @@ -588,7 +699,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // Check packet type T. if (checkOpenCLPipePacketType(S, Call, 1)) return true; - } break; + break; case 4: { if (checkOpenCLPipeArg(S, Call)) @@ -647,6 +758,11 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { return true; } + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + Call->setType(S.Context.OCLReserveIDTy); + return false; } @@ -690,6 +806,7 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { return false; } + // \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. // \brief Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. @@ -721,8 +838,11 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, case Builtin::BIto_local: Qual.setAddressSpace(LangAS::opencl_local); break; + case Builtin::BIto_private: + Qual.setAddressSpace(LangAS::opencl_private); + break; default: - Qual.removeAddressSpace(); + llvm_unreachable("Invalid builtin function"); } Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( RT.getUnqualifiedType(), Qual))); @@ -770,7 +890,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: - if (SemaBuiltinVAStartARM(TheCall)) + if (SemaBuiltinVAStartARMMicrosoft(TheCall)) return ExprError(); break; default: @@ -839,7 +959,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (checkArgCount(*this, TheCall, 1)) return true; break; - case Builtin::BI__builtin_classify_type: if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); @@ -959,6 +1078,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI##ID: \ return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.def" + case Builtin::BI__annotation: + if (SemaBuiltinMSVCAnnotation(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_annotation: if (SemaBuiltinAnnotation(*this, TheCall)) return ExprError(); @@ -1048,22 +1171,26 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + break; case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: - if (SemaBuiltinReserveRWPipe(*this, TheCall)) + if (checkOpenCLSubgroupExt(*this, TheCall) || + SemaBuiltinReserveRWPipe(*this, TheCall)) return ExprError(); - // Since return type of reserve_read/write_pipe built-in function is - // reserve_id_t, which is not defined in the builtin def file , we used int - // as return type and need to override the return type of these functions. - TheCall->setType(Context.OCLReserveIDTy); break; case Builtin::BIcommit_read_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIwork_group_commit_write_pipe: + if (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: - if (SemaBuiltinCommitRWPipe(*this, TheCall)) + if (checkOpenCLSubgroupExt(*this, TheCall) || + SemaBuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: @@ -1088,11 +1215,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; + break; + case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: + case Builtin::BIget_kernel_sub_group_count_for_ndrange: + if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_os_log_format: case Builtin::BI__builtin_os_log_format_buffer_size: - if (SemaBuiltinOSLogFormat(TheCall)) { + if (SemaBuiltinOSLogFormat(TheCall)) return ExprError(); - } break; } @@ -1422,21 +1554,26 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { // For intrinsics which take an immediate value as part of the instruction, // range check them here. - unsigned i = 0, l = 0, u = 0; + // FIXME: VFP Intrinsics should error if VFP not present. switch (BuiltinID) { default: return false; - case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break; - case ARM::BI__builtin_arm_usat: i = 1; u = 31; break; + case ARM::BI__builtin_arm_ssat: + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 32); + case ARM::BI__builtin_arm_usat: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + case ARM::BI__builtin_arm_ssat16: + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + case ARM::BI__builtin_arm_usat16: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); case ARM::BI__builtin_arm_vcvtr_f: - case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break; + case ARM::BI__builtin_arm_vcvtr_d: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: case ARM::BI__builtin_arm_isb: - case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break; + case ARM::BI__builtin_arm_dbg: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15); } - - // FIXME: VFP Intrinsics should error if VFP not present. - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, @@ -1790,6 +1927,26 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { return false; } +/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *). +/// This checks that the target supports __builtin_cpu_is and +/// that the string argument is constant and valid. +static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) { + Expr *Arg = TheCall->getArg(0); + + // Check if the argument is a string literal. + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) + return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the contents of the string. + StringRef Feature = + cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); + if (!S.Context.getTargetInfo().validateCpuIs(Feature)) + return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_is) + << Arg->getSourceRange(); + return false; +} + // Check if the rounding mode is legal. bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { // Indicates if this instruction has rounding control or just SAE. @@ -2103,6 +2260,9 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); + if (BuiltinID == X86::BI__builtin_cpu_is) + return SemaBuiltinCpuIs(*this, TheCall); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -2209,7 +2369,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { i = 1; l = -128; u = 255; break; case X86::BI__builtin_ia32_vcvtps2ph: + case X86::BI__builtin_ia32_vcvtps2ph_mask: case X86::BI__builtin_ia32_vcvtps2ph256: + case X86::BI__builtin_ia32_vcvtps2ph256_mask: + case X86::BI__builtin_ia32_vcvtps2ph512_mask: case X86::BI__builtin_ia32_rndscaleps_128_mask: case X86::BI__builtin_ia32_rndscalepd_128_mask: case X86::BI__builtin_ia32_rndscaleps_256_mask: @@ -2402,6 +2565,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { } return false; } + /// \brief Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void @@ -2595,7 +2759,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // Type safety checking. if (FDecl) { for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) - CheckArgumentWithTypeTag(I, Args.data()); + CheckArgumentWithTypeTag(I, Args, Loc); } } @@ -2734,15 +2898,18 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering; switch (Op) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: llvm_unreachable("There is no ordering argument for an init"); case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: return OrderingCABI != llvm::AtomicOrderingCABI::release && OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: return OrderingCABI != llvm::AtomicOrderingCABI::consume && @@ -2759,27 +2926,39 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); - // All these operations take one of the following forms: + // All the non-OpenCL operations take one of the following forms. + // The OpenCL operations take the __c11 forms with one extra argument for + // synchronization scope. enum { // C __c11_atomic_init(A *, C) Init, + // C __c11_atomic_load(A *, int) Load, + // void __atomic_load(A *, CP, int) LoadCopy, + // void __atomic_store(A *, CP, int) Copy, + // C __c11_atomic_add(A *, M, int) Arithmetic, + // C __atomic_exchange_n(A *, CP, int) Xchg, + // void __atomic_exchange(A *, C *, CP, int) GNUXchg, + // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int) C11CmpXchg, + // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) GNUCmpXchg } Form = Init; + + const unsigned NumForm = GNUCmpXchg + 1; const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: @@ -2789,12 +2968,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // M is C if C is an integer, and ptrdiff_t if C is a pointer, and // the int parameters are for orderings. + static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm + && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm, + "need to update code for modified forms"); static_assert(AtomicExpr::AO__c11_atomic_init == 0 && AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load, "need to update code for modified C11 atomics"); - bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init && - Op <= AtomicExpr::AO__c11_atomic_fetch_xor; + bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init && + Op <= AtomicExpr::AO__opencl_atomic_fetch_max; + bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init && + Op <= AtomicExpr::AO__c11_atomic_fetch_xor) || + IsOpenCL; bool IsN = Op == AtomicExpr::AO__atomic_load_n || Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || @@ -2803,10 +2988,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, switch (Op) { case AtomicExpr::AO__c11_atomic_init: + case AtomicExpr::AO__opencl_atomic_init: Form = Init; break; case AtomicExpr::AO__c11_atomic_load: + case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__atomic_load_n: Form = Load; break; @@ -2816,6 +3003,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; @@ -2823,6 +3011,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: @@ -2832,6 +3024,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__opencl_atomic_fetch_and: + case AtomicExpr::AO__opencl_atomic_fetch_or: + case AtomicExpr::AO__opencl_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_xor: @@ -2844,6 +3039,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: Form = Xchg; break; @@ -2854,6 +3050,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: Form = C11CmpXchg; break; @@ -2863,16 +3061,19 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; } + unsigned AdjustedNumArgs = NumArgs[Form]; + if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) + ++AdjustedNumArgs; // Check we have the right number of arguments. - if (TheCall->getNumArgs() < NumArgs[Form]) { + if (TheCall->getNumArgs() < AdjustedNumArgs) { Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << NumArgs[Form] << TheCall->getNumArgs() + << 0 << AdjustedNumArgs << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); - } else if (TheCall->getNumArgs() > NumArgs[Form]) { - Diag(TheCall->getArg(NumArgs[Form])->getLocStart(), + } else if (TheCall->getNumArgs() > AdjustedNumArgs) { + Diag(TheCall->getArg(AdjustedNumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 << NumArgs[Form] << TheCall->getNumArgs() + << 0 << AdjustedNumArgs << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } @@ -2900,9 +3101,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (AtomTy.isConstQualified()) { + if (AtomTy.isConstQualified() || + AtomTy.getAddressSpace() == LangAS::opencl_constant) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic) - << Ptr->getType() << Ptr->getSourceRange(); + << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() + << Ptr->getSourceRange(); return ExprError(); } ValType = AtomTy->getAs<AtomicType>()->getValueType(); @@ -2971,7 +3174,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || + Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; @@ -2985,7 +3189,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. - for (unsigned i = 1; i != NumArgs[Form]; ++i) { + for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { @@ -3006,7 +3210,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // Treat this argument as _Nonnull as we want to show a warning if // NULL is passed into it. CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); - unsigned AS = 0; + LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = ValArg->getType()->getAs<PointerType>()) { @@ -3027,7 +3231,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; } } else { - // The order(s) are always converted to int. + // The order(s) and scope are always converted to int. Ty = Context.IntTy; } @@ -3088,15 +3292,30 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, << SubExprs[1]->getSourceRange(); } + if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { + auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1); + llvm::APSInt Result(32); + if (Scope->isIntegerConstantExpr(Result, Context) && + !ScopeModel->isValid(Result.getZExtValue())) { + Diag(Scope->getLocStart(), diag::err_atomic_op_has_invalid_synch_scope) + << Scope->getSourceRange(); + } + SubExprs.push_back(Scope); + } + AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), SubExprs, ResultType, Op, TheCall->getRParenLoc()); if ((Op == AtomicExpr::AO__c11_atomic_load || - (Op == AtomicExpr::AO__c11_atomic_store)) && + Op == AtomicExpr::AO__c11_atomic_store || + Op == AtomicExpr::AO__opencl_atomic_load || + Op == AtomicExpr::AO__opencl_atomic_store ) && Context.AtomicUsesUnsupportedLibcall(AE)) - Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) << - ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1); + Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) + << ((Op == AtomicExpr::AO__c11_atomic_load || + Op == AtomicExpr::AO__opencl_atomic_load) + ? 0 : 1); return AE; } @@ -3631,7 +3850,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { bool IsWindows = TT.isOSWindows(); bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; if (IsX64 || IsAArch64) { - clang::CallingConv CC = CC_C; + CallingConv CC = CC_C; if (const FunctionDecl *FD = S.getCurFunctionDecl()) CC = FD->getType()->getAs<FunctionType>()->getCallConv(); if (IsMSVAStart) { @@ -3778,7 +3997,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { +bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); @@ -3797,23 +4016,33 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { if (checkVAStartIsInVariadicFunction(*this, Func)) return true; - const struct { - unsigned ArgNo; - QualType Type; - } ArgumentTypes[] = { - { 1, Context.getPointerType(Context.CharTy.withConst()) }, - { 2, Context.getSizeType() }, - }; + // __va_start on Windows does not validate the parameter qualifiers - for (const auto &AT : ArgumentTypes) { - const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens(); - if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType()) - continue; - Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible) - << Arg->getType() << AT.Type << 1 /* different class */ - << 0 /* qualifier difference */ << 3 /* parameter mismatch */ - << AT.ArgNo + 1 << Arg->getType() << AT.Type; - } + const Expr *Arg1 = Call->getArg(1)->IgnoreParens(); + const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr(); + + const Expr *Arg2 = Call->getArg(2)->IgnoreParens(); + const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr(); + + const QualType &ConstCharPtrTy = + Context.getPointerType(Context.CharTy.withConst()); + if (!Arg1Ty->isPointerType() || + Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy) + Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg1->getType() << ConstCharPtrTy + << 1 /* different class */ + << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << Arg1->getType() << ConstCharPtrTy; + + const QualType SizeTy = Context.getSizeType(); + if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy) + Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg2->getType() << SizeTy + << 1 /* different class */ + << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 3 << Arg2->getType() << SizeTy; return false; } @@ -4143,9 +4372,9 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { << (unsigned)Context.getCharWidth() << Arg->getSourceRange(); - if (Result > INT32_MAX) + if (Result > std::numeric_limits<int32_t>::max()) return Diag(TheCall->getLocStart(), diag::err_alignment_too_big) - << INT32_MAX + << std::numeric_limits<int32_t>::max() << Arg->getSourceRange(); } @@ -4410,7 +4639,6 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, if (!ValidString) return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) << Arg->getSourceRange(); - } else if (IsAArch64Builtin && Fields.size() == 1) { // If the register name is one of those that appear in the condition below // and the special register builtin being used is one of the write builtins, @@ -4464,13 +4692,15 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { } namespace { + class UncoveredArgHandler { enum { Unknown = -1, AllCovered = -2 }; - signed FirstUncoveredArg; + + signed FirstUncoveredArg = Unknown; SmallVector<const Expr *, 4> DiagnosticExprs; public: - UncoveredArgHandler() : FirstUncoveredArg(Unknown) { } + UncoveredArgHandler() = default; bool hasUncoveredArg() const { return (FirstUncoveredArg >= 0); @@ -4514,7 +4744,8 @@ enum StringLiteralCheckType { SLCT_UncheckedLiteral, SLCT_CheckedLiteral }; -} // end anonymous namespace + +} // namespace static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, BinaryOperatorKind BinOpKind, @@ -4547,7 +4778,8 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, // We add an offset to a pointer here so we should support an offset as big as // possible. if (Ov) { - assert(BitWidth <= UINT_MAX / 2 && "index (intermediate) result too big"); + assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 && + "index (intermediate) result too big"); Offset = Offset.sext(2 * BitWidth); sumOffsets(Offset, Addend, BinOpKind, AddendIsRight); return; @@ -4557,6 +4789,7 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, } namespace { + // This is a wrapper class around StringLiteral to support offsetted string // literals as format strings. It takes the offset into account when returning // the string and its length or the source locations to display notes correctly. @@ -4575,6 +4808,7 @@ class FormatStringLiteral { unsigned getByteLength() const { return FExpr->getByteLength() - getCharByteWidth() * Offset; } + unsigned getLength() const { return FExpr->getLength() - Offset; } unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); } @@ -4600,9 +4834,11 @@ class FormatStringLiteral { SourceLocation getLocStart() const LLVM_READONLY { return FExpr->getLocStart().getLocWithOffset(Offset); } + SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } }; -} // end anonymous namespace + +} // namespace static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, @@ -4689,10 +4925,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return (CheckLeft && Left < Right) ? Left : Right; } - case Stmt::ImplicitCastExprClass: { + case Stmt::ImplicitCastExprClass: E = cast<ImplicitCastExpr>(E)->getSubExpr(); goto tryAgain; - } case Stmt::OpaqueValueExprClass: if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { @@ -4881,7 +5116,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, case Stmt::UnaryOperatorClass: { const UnaryOperator *UnaOp = cast<UnaryOperator>(E); auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr()); - if (UnaOp->getOpcode() == clang::UO_AddrOf && ASE) { + if (UnaOp->getOpcode() == UO_AddrOf && ASE) { llvm::APSInt IndexResult; if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) { sumOffsets(Offset, IndexResult, BO_Add, /*RHS is int*/ true); @@ -5014,6 +5249,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, } namespace { + class CheckFormatHandler : public analyze_format_string::FormatStringHandler { protected: Sema &S; @@ -5027,8 +5263,8 @@ protected: ArrayRef<const Expr *> Args; unsigned FormatIdx; llvm::SmallBitVector CoveredArgs; - bool usesPositionalArgs; - bool atFirstArg; + bool usesPositionalArgs = false; + bool atFirstArg = true; bool inFunctionCall; Sema::VariadicCallType CallType; llvm::SmallBitVector &CheckedVarArgs; @@ -5046,7 +5282,6 @@ public: : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), - usesPositionalArgs(false), atFirstArg(true), inFunctionCall(inFunctionCall), CallType(callType), CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); @@ -5116,7 +5351,8 @@ protected: bool IsStringLocation, Range StringRange, ArrayRef<FixItHint> Fixit = None); }; -} // end anonymous namespace + +} // namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); @@ -5470,6 +5706,7 @@ void CheckFormatHandler::EmitFormatDiagnostic( //===--- CHECK: Printf format string checking ------------------------------===// namespace { + class CheckPrintfHandler : public CheckFormatHandler { public: CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, @@ -5534,7 +5771,8 @@ public: const char *conversionPosition) override; }; -} // end anonymous namespace + +} // namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -5652,10 +5890,6 @@ void CheckPrintfHandler::HandleIgnoredFlag( getSpecifierRange(ignoredFlag.getPosition(), 1))); } -// void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, -// bool IsStringLocation, Range StringRange, -// ArrayRef<FixItHint> Fixit = None); - void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) { // Warn about an empty flag. @@ -5722,7 +5956,8 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { /// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't /// allow the call, or if it would be ambiguous). bool Sema::hasCStrMethod(const Expr *E) { - typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet; + using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; + MethodSet Results = CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType()); for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); @@ -5737,7 +5972,7 @@ bool Sema::hasCStrMethod(const Expr *E) { // Returns true when a c_str() conversion method is found. bool CheckPrintfHandler::checkForCStrMembers( const analyze_printf::ArgType &AT, const Expr *E) { - typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet; + using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; MethodSet Results = CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType()); @@ -5765,7 +6000,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier const char *startSpecifier, unsigned specifierLen) { using namespace analyze_format_string; - using namespace analyze_printf; + using namespace analyze_printf; + const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); if (FS.consumesDataArgument()) { @@ -6009,9 +6245,9 @@ shouldNotPrintDirectly(const ASTContext &Context, while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { StringRef Name = UserTy->getDecl()->getName(); QualType CastTy = llvm::StringSwitch<QualType>(Name) - .Case("CFIndex", Context.LongTy) - .Case("NSInteger", Context.LongTy) - .Case("NSUInteger", Context.UnsignedLongTy) + .Case("CFIndex", Context.getNSIntegerType()) + .Case("NSInteger", Context.getNSIntegerType()) + .Case("NSUInteger", Context.getNSUIntegerType()) .Case("SInt32", Context.IntTy) .Case("UInt32", Context.UnsignedIntTy) .Default(QualType()); @@ -6063,6 +6299,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const Expr *E) { using namespace analyze_format_string; using namespace analyze_printf; + // Now type check the data expression that matches the // format specifier. const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext()); @@ -6200,7 +6437,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << ")"; SmallVector<FixItHint,4> Hints; - if (!AT.matchesType(S.Context, IntendedTy)) + if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { @@ -6315,6 +6552,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, //===--- CHECK: Scanf format string checking ------------------------------===// namespace { + class CheckScanfHandler : public CheckFormatHandler { public: CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, @@ -6341,7 +6579,8 @@ public: void HandleIncompleteScanList(const char *start, const char *end) override; }; -} // end anonymous namespace + +} // namespace void CheckScanfHandler::HandleIncompleteScanList(const char *start, const char *end) { @@ -6354,7 +6593,6 @@ bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - const analyze_scanf::ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -7041,8 +7279,8 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, if (!Size) return false; - // if E is binop and op is >, <, >=, <=, ==, &&, ||: - if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp()) + // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||: + if (!Size->isComparisonOp() && !Size->isLogicalOp()) return false; SourceRange SizeRange = Size->getSourceRange(); @@ -7096,7 +7334,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, static const Expr *getSizeOfExprArg(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) + if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); return nullptr; @@ -7106,7 +7344,7 @@ static const Expr *getSizeOfExprArg(const Expr *E) { static QualType getSizeOfArgType(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == clang::UETT_SizeOf) + if (SizeOf->getKind() == UETT_SizeOf) return SizeOf->getTypeOfArgument(); return QualType(); @@ -7294,7 +7532,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { Ex = Ex->IgnoreParenCasts(); - for (;;) { + while (true) { const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); if (!BO || !BO->isAdditiveOp()) break; @@ -7512,7 +7750,6 @@ static const Expr *EvalAddr(const Expr *E, static void CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { - const Expr *stackE = nullptr; SmallVector<const DeclRefExpr *, 8> refVars; @@ -7997,8 +8234,7 @@ struct IntRange { bool NonNegative; IntRange(unsigned Width, bool NonNegative) - : Width(Width), NonNegative(NonNegative) - {} + : Width(Width), NonNegative(NonNegative) {} /// Returns the range of the bool type. static IntRange forBoolType() { @@ -8022,11 +8258,19 @@ struct IntRange { if (const AtomicType *AT = dyn_cast<AtomicType>(T)) T = AT->getValueType().getTypePtr(); - // For enum types, use the known bit width of the enumerators. - if (const EnumType *ET = dyn_cast<EnumType>(T)) { + if (!C.getLangOpts().CPlusPlus) { + // For enum types in C code, use the underlying datatype. + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr(); + } else if (const EnumType *ET = dyn_cast<EnumType>(T)) { + // For enum types in C++, use the known bit width of the enumerators. EnumDecl *Enum = ET->getDecl(); - if (!Enum->isCompleteDefinition()) - return IntRange(C.getIntWidth(QualType(T, 0)), false); + // In C++11, enums can have a fixed underlying type. Use this type to + // compute the range. + if (Enum->isFixed()) { + return IntRange(C.getIntWidth(QualType(T, 0)), + !ET->isSignedIntegerOrEnumerationType()); + } unsigned NumPositive = Enum->getNumPositiveBits(); unsigned NumNegative = Enum->getNumNegativeBits(); @@ -8080,7 +8324,10 @@ struct IntRange { } }; -IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { +} // namespace + +static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, + unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) return IntRange(value.getMinSignedBits(), false); @@ -8092,8 +8339,8 @@ IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { return IntRange(value.getActiveBits(), true); } -IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, - unsigned MaxWidth) { +static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { if (result.isInt()) return GetValueRange(C, result.getInt(), MaxWidth); @@ -8121,7 +8368,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } -QualType GetExprType(const Expr *E) { +static QualType GetExprType(const Expr *E) { QualType Ty = E->getType(); if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>()) Ty = AtomicRHS->getValueType(); @@ -8132,7 +8379,7 @@ QualType GetExprType(const Expr *E) { /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated -IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { +static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { E = E->IgnoreParens(); // Try a full evaluation first. @@ -8186,6 +8433,8 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { if (const auto *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { + case BO_Cmp: + llvm_unreachable("builtin <=> should have class type"); // Boolean-valued operations are single-bit and positive. case BO_LAnd: @@ -8350,16 +8599,16 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { return IntRange::forValueOfType(C, GetExprType(E)); } -IntRange GetExprRange(ASTContext &C, const Expr *E) { +static IntRange GetExprRange(ASTContext &C, const Expr *E) { return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. -bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +static bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { llvm::APFloat truncated = value; bool ignored; @@ -8374,9 +8623,9 @@ bool IsSameFloatAfterCast(const llvm::APFloat &value, /// target semantics. /// /// The value might be a vector of floats (or a complex number). -bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +static bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { if (value.isFloat()) return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); @@ -8392,249 +8641,234 @@ bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); -bool IsZero(Sema &S, Expr *E) { +static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) if (isa<EnumConstantDecl>(DR->getDecl())) - return false; + return true; // Suppress cases where the '0' value is expanded from a macro. if (E->getLocStart().isMacroID()) - return false; + return true; - llvm::APSInt Value; - return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; + return false; } -bool HasEnumType(Expr *E) { - // Strip off implicit integral promotions. - while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { - if (ICE->getCastKind() != CK_IntegralCast && - ICE->getCastKind() != CK_NoOp) - break; - E = ICE->getSubExpr(); - } - - return E->getType()->isEnumeralType(); +static bool isKnownToHaveUnsignedValue(Expr *E) { + return E->getType()->isIntegerType() && + (!E->getType()->isSignedIntegerType() || + !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType()); } -void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { - // Disable warning in template instantiations. - if (S.inTemplateInstantiation()) - return; +namespace { +/// The promoted range of values of a type. In general this has the +/// following structure: +/// +/// |-----------| . . . |-----------| +/// ^ ^ ^ ^ +/// Min HoleMin HoleMax Max +/// +/// ... where there is only a hole if a signed type is promoted to unsigned +/// (in which case Min and Max are the smallest and largest representable +/// values). +struct PromotedRange { + // Min, or HoleMax if there is a hole. + llvm::APSInt PromotedMin; + // Max, or HoleMin if there is a hole. + llvm::APSInt PromotedMax; - BinaryOperatorKind op = E->getOpcode(); - if (E->isValueDependent()) - return; + PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) { + if (R.Width == 0) + PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned); + else if (R.Width >= BitWidth && !Unsigned) { + // Promotion made the type *narrower*. This happens when promoting + // a < 32-bit unsigned / <= 32-bit signed bit-field to 'signed int'. + // Treat all values of 'signed int' as being in range for now. + PromotedMin = llvm::APSInt::getMinValue(BitWidth, Unsigned); + PromotedMax = llvm::APSInt::getMaxValue(BitWidth, Unsigned); + } else { + PromotedMin = llvm::APSInt::getMinValue(R.Width, R.NonNegative) + .extOrTrunc(BitWidth); + PromotedMin.setIsUnsigned(Unsigned); - if (op == BO_LT && IsZero(S, E->getRHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << "< 0" << "false" << HasEnumType(E->getLHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_GE && IsZero(S, E->getRHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << ">= 0" << "true" << HasEnumType(E->getLHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_GT && IsZero(S, E->getLHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 >" << "false" << HasEnumType(E->getRHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_LE && IsZero(S, E->getLHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 <=" << "true" << HasEnumType(E->getRHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + PromotedMax = llvm::APSInt::getMaxValue(R.Width, R.NonNegative) + .extOrTrunc(BitWidth); + PromotedMax.setIsUnsigned(Unsigned); + } } -} - -void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, - Expr *Other, const llvm::APSInt &Value, - bool RhsConstant) { - // Disable warning in template instantiations. - if (S.inTemplateInstantiation()) - return; - // TODO: Investigate using GetExprRange() to get tighter bounds - // on the bit ranges. - QualType OtherT = Other->getType(); - if (const auto *AT = OtherT->getAs<AtomicType>()) - OtherT = AT->getValueType(); - IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); - unsigned OtherWidth = OtherRange.Width; + // Determine whether this range is contiguous (has no hole). + bool isContiguous() const { return PromotedMin <= PromotedMax; } - bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue(); + // Where a constant value is within the range. + enum ComparisonResult { + LT = 0x1, + LE = 0x2, + GT = 0x4, + GE = 0x8, + EQ = 0x10, + NE = 0x20, + InRangeFlag = 0x40, - // 0 values are handled later by CheckTrivialUnsignedComparison(). - if ((Value == 0) && (!OtherIsBooleanType)) - return; + Less = LE | LT | NE, + Min = LE | InRangeFlag, + InRange = InRangeFlag, + Max = GE | InRangeFlag, + Greater = GE | GT | NE, - BinaryOperatorKind op = E->getOpcode(); - bool IsTrue = true; + OnlyValue = LE | GE | EQ | InRangeFlag, + InHole = NE + }; - // Used for diagnostic printout. - enum { - LiteralConstant = 0, - CXXBoolLiteralTrue, - CXXBoolLiteralFalse - } LiteralOrBoolConstant = LiteralConstant; + ComparisonResult compare(const llvm::APSInt &Value) const { + assert(Value.getBitWidth() == PromotedMin.getBitWidth() && + Value.isUnsigned() == PromotedMin.isUnsigned()); + if (!isContiguous()) { + assert(Value.isUnsigned() && "discontiguous range for signed compare"); + if (Value.isMinValue()) return Min; + if (Value.isMaxValue()) return Max; + if (Value >= PromotedMin) return InRange; + if (Value <= PromotedMax) return InRange; + return InHole; + } - if (!OtherIsBooleanType) { - QualType ConstantT = Constant->getType(); - QualType CommonT = E->getLHS()->getType(); + switch (llvm::APSInt::compareValues(Value, PromotedMin)) { + case -1: return Less; + case 0: return PromotedMin == PromotedMax ? OnlyValue : Min; + case 1: + switch (llvm::APSInt::compareValues(Value, PromotedMax)) { + case -1: return InRange; + case 0: return Max; + case 1: return Greater; + } + } - if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) - return; - assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) && - "comparison with non-integer type"); + llvm_unreachable("impossible compare result"); + } - bool ConstantSigned = ConstantT->isSignedIntegerType(); - bool CommonSigned = CommonT->isSignedIntegerType(); + static llvm::Optional<StringRef> + constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) { + if (Op == BO_Cmp) { + ComparisonResult LTFlag = LT, GTFlag = GT; + if (ConstantOnRHS) std::swap(LTFlag, GTFlag); - bool EqualityOnly = false; + if (R & EQ) return StringRef("'std::strong_ordering::equal'"); + if (R & LTFlag) return StringRef("'std::strong_ordering::less'"); + if (R & GTFlag) return StringRef("'std::strong_ordering::greater'"); + return llvm::None; + } - if (CommonSigned) { - // The common type is signed, therefore no signed to unsigned conversion. - if (!OtherRange.NonNegative) { - // Check that the constant is representable in type OtherT. - if (ConstantSigned) { - if (OtherWidth >= Value.getMinSignedBits()) - return; - } else { // !ConstantSigned - if (OtherWidth >= Value.getActiveBits() + 1) - return; - } - } else { // !OtherSigned - // Check that the constant is representable in type OtherT. - // Negative values are out of range. - if (ConstantSigned) { - if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits()) - return; - } else { // !ConstantSigned - if (OtherWidth >= Value.getActiveBits()) - return; - } - } - } else { // !CommonSigned - if (OtherRange.NonNegative) { - if (OtherWidth >= Value.getActiveBits()) - return; - } else { // OtherSigned - assert(!ConstantSigned && - "Two signed types converted to unsigned types."); - // Check to see if the constant is representable in OtherT. - if (OtherWidth > Value.getActiveBits()) - return; - // Check to see if the constant is equivalent to a negative value - // cast to CommonT. - if (S.Context.getIntWidth(ConstantT) == - S.Context.getIntWidth(CommonT) && - Value.isNegative() && Value.getMinSignedBits() <= OtherWidth) - return; - // The constant value rests between values that OtherT can represent - // after conversion. Relational comparison still works, but equality - // comparisons will be tautological. - EqualityOnly = true; + ComparisonResult TrueFlag, FalseFlag; + if (Op == BO_EQ) { + TrueFlag = EQ; + FalseFlag = NE; + } else if (Op == BO_NE) { + TrueFlag = NE; + FalseFlag = EQ; + } else { + if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) { + TrueFlag = LT; + FalseFlag = GE; + } else { + TrueFlag = GT; + FalseFlag = LE; } + if (Op == BO_GE || Op == BO_LE) + std::swap(TrueFlag, FalseFlag); } + if (R & TrueFlag) + return StringRef("true"); + if (R & FalseFlag) + return StringRef("false"); + return llvm::None; + } +}; +} - bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); +static bool HasEnumType(Expr *E) { + // Strip off implicit integral promotions. + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() != CK_IntegralCast && + ICE->getCastKind() != CK_NoOp) + break; + E = ICE->getSubExpr(); + } - if (op == BO_EQ || op == BO_NE) { - IsTrue = op == BO_NE; - } else if (EqualityOnly) { - return; - } else if (RhsConstant) { - if (op == BO_GT || op == BO_GE) - IsTrue = !PositiveConstant; - else // op == BO_LT || op == BO_LE - IsTrue = PositiveConstant; - } else { - if (op == BO_LT || op == BO_LE) - IsTrue = !PositiveConstant; - else // op == BO_GT || op == BO_GE - IsTrue = PositiveConstant; - } - } else { - // Other isKnownToHaveBooleanValue - enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn }; - enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal }; - enum ConstantSide { Lhs, Rhs, SizeOfConstSides }; + return E->getType()->isEnumeralType(); +} - static const struct LinkedConditions { - CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal]; +static int classifyConstantValue(Expr *Constant) { + // The values of this enumeration are used in the diagnostics + // diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare. + enum ConstantValueKind { + Miscellaneous = 0, + LiteralTrue, + LiteralFalse + }; + if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant)) + return BL->getValue() ? ConstantValueKind::LiteralTrue + : ConstantValueKind::LiteralFalse; + return ConstantValueKind::Miscellaneous; +} - } TruthTable = { - // Constant on LHS. | Constant on RHS. | - // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One| - { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } }, - { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } }, - { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } }, - { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } }, - { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } }, - { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } } - }; +static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, + Expr *Constant, Expr *Other, + const llvm::APSInt &Value, + bool RhsConstant) { + if (S.inTemplateInstantiation()) + return false; - bool ConstantIsBoolLiteral = isa<CXXBoolLiteralExpr>(Constant); + Expr *OriginalOther = Other; - enum ConstantValue ConstVal = Zero; - if (Value.isUnsigned() || Value.isNonNegative()) { - if (Value == 0) { - LiteralOrBoolConstant = - ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant; - ConstVal = Zero; - } else if (Value == 1) { - LiteralOrBoolConstant = - ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant; - ConstVal = One; - } else { - LiteralOrBoolConstant = LiteralConstant; - ConstVal = GT_One; - } - } else { - ConstVal = LT_Zero; - } + Constant = Constant->IgnoreParenImpCasts(); + Other = Other->IgnoreParenImpCasts(); - CompareBoolWithConstantResult CmpRes; + // Suppress warnings on tautological comparisons between values of the same + // enumeration type. There are only two ways we could warn on this: + // - If the constant is outside the range of representable values of + // the enumeration. In such a case, we should warn about the cast + // to enumeration type, not about the comparison. + // - If the constant is the maximum / minimum in-range value. For an + // enumeratin type, such comparisons can be meaningful and useful. + if (Constant->getType()->isEnumeralType() && + S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType())) + return false; - switch (op) { - case BO_LT: - CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal]; - break; - case BO_GT: - CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal]; - break; - case BO_LE: - CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal]; - break; - case BO_GE: - CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal]; - break; - case BO_EQ: - CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal]; - break; - case BO_NE: - CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal]; - break; - default: - CmpRes = Unkwn; - break; - } + // TODO: Investigate using GetExprRange() to get tighter bounds + // on the bit ranges. + QualType OtherT = Other->getType(); + if (const auto *AT = OtherT->getAs<AtomicType>()) + OtherT = AT->getValueType(); + IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); - if (CmpRes == AFals) { - IsTrue = false; - } else if (CmpRes == ATrue) { - IsTrue = true; - } else { - return; - } - } + // Whether we're treating Other as being a bool because of the form of + // expression despite it having another type (typically 'int' in C). + bool OtherIsBooleanDespiteType = + !OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue(); + if (OtherIsBooleanDespiteType) + OtherRange = IntRange::forBoolType(); + + // Determine the promoted range of the other type and see if a comparison of + // the constant against that range is tautological. + PromotedRange OtherPromotedRange(OtherRange, Value.getBitWidth(), + Value.isUnsigned()); + auto Cmp = OtherPromotedRange.compare(Value); + auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant); + if (!Result) + return false; + + // Suppress the diagnostic for an in-range comparison if the constant comes + // from a macro or enumerator. We don't want to diagnose + // + // some_long_value <= INT_MAX + // + // when sizeof(int) == sizeof(long). + bool InRange = Cmp & PromotedRange::InRangeFlag; + if (InRange && IsEnumConstOrFromMacro(S, Constant)) + return false; // If this is a comparison to an enum constant, include that // constant in the diagnostic. @@ -8642,6 +8876,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant)) ED = dyn_cast<EnumConstantDecl>(DR->getDecl()); + // Should be enough for uint128 (39 decimal digits) SmallString<64> PrettySourceValue; llvm::raw_svector_ostream OS(PrettySourceValue); if (ED) @@ -8649,17 +8884,35 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, else OS << Value; - S.DiagRuntimeBehavior( - E->getOperatorLoc(), E, - S.PDiag(diag::warn_out_of_range_compare) - << OS.str() << LiteralOrBoolConstant - << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); + // FIXME: We use a somewhat different formatting for the in-range cases and + // cases involving boolean values for historical reasons. We should pick a + // consistent way of presenting these diagnostics. + if (!InRange || Other->isKnownToHaveBooleanValue()) { + S.DiagRuntimeBehavior( + E->getOperatorLoc(), E, + S.PDiag(!InRange ? diag::warn_out_of_range_compare + : diag::warn_tautological_bool_compare) + << OS.str() << classifyConstantValue(Constant) + << OtherT << OtherIsBooleanDespiteType << *Result + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); + } else { + unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) + ? (HasEnumType(OriginalOther) + ? diag::warn_unsigned_enum_always_true_comparison + : diag::warn_unsigned_always_true_comparison) + : diag::warn_tautological_constant_compare; + + S.Diag(E->getOperatorLoc(), Diag) + << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); + } + + return true; } /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. -void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { +static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } @@ -8667,7 +8920,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings -void AnalyzeComparison(Sema &S, BinaryOperator *E) { +static void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -8680,39 +8933,45 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { if (E->isValueDependent()) return AnalyzeImpConvsInComparison(S, E); - Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); - Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); - - bool IsComparisonConstant = false; - - // Check whether an integer constant comparison results in a value - // of 'true' or 'false'. + Expr *LHS = E->getLHS(); + Expr *RHS = E->getRHS(); + if (T->isIntegralType(S.Context)) { llvm::APSInt RHSValue; - bool IsRHSIntegralLiteral = - RHS->isIntegerConstantExpr(RHSValue, S.Context); llvm::APSInt LHSValue; - bool IsLHSIntegralLiteral = - LHS->isIntegerConstantExpr(LHSValue, S.Context); - if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral) - DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true); - else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral) - DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false); - else - IsComparisonConstant = - (IsRHSIntegralLiteral && IsLHSIntegralLiteral); - } else if (!T->hasUnsignedIntegerRepresentation()) - IsComparisonConstant = E->isIntegerConstantExpr(S.Context); - - // We don't do anything special if this isn't an unsigned integral - // comparison: we're only interested in integral comparisons, and - // signed comparisons only happen in cases we don't care to warn about. - // - // We also don't care about value-dependent expressions or expressions - // whose result is a constant. - if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant) + + bool IsRHSIntegralLiteral = RHS->isIntegerConstantExpr(RHSValue, S.Context); + bool IsLHSIntegralLiteral = LHS->isIntegerConstantExpr(LHSValue, S.Context); + + // We don't care about expressions whose result is a constant. + if (IsRHSIntegralLiteral && IsLHSIntegralLiteral) + return AnalyzeImpConvsInComparison(S, E); + + // We only care about expressions where just one side is literal + if (IsRHSIntegralLiteral ^ IsLHSIntegralLiteral) { + // Is the constant on the RHS or LHS? + const bool RhsConstant = IsRHSIntegralLiteral; + Expr *Const = RhsConstant ? RHS : LHS; + Expr *Other = RhsConstant ? LHS : RHS; + const llvm::APSInt &Value = RhsConstant ? RHSValue : LHSValue; + + // Check whether an integer constant comparison results in a value + // of 'true' or 'false'. + if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant)) + return AnalyzeImpConvsInComparison(S, E); + } + } + + if (!T->hasUnsignedIntegerRepresentation()) { + // We don't do anything special if this isn't an unsigned integral + // comparison: we're only interested in integral comparisons, and + // signed comparisons only happen in cases we don't care to warn about. return AnalyzeImpConvsInComparison(S, E); - + } + + LHS = LHS->IgnoreParenImpCasts(); + RHS = RHS->IgnoreParenImpCasts(); + // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; @@ -8725,7 +8984,6 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { signedOperand = RHS; unsignedOperand = LHS; } else { - CheckTrivialUnsignedComparison(S, E); return AnalyzeImpConvsInComparison(S, E); } @@ -8737,11 +8995,9 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); - // If the signed range is non-negative, -Wsign-compare won't fire, - // but we should still check for comparisons which are always true - // or false. + // If the signed range is non-negative, -Wsign-compare won't fire. if (signedRange.NonNegative) - return CheckTrivialUnsignedComparison(S, E); + return; // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, @@ -8768,8 +9024,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { /// Analyzes an attempt to assign the given value to a bitfield. /// /// Returns true if there was something fishy about the attempt. -bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, - SourceLocation InitLoc) { +static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, + SourceLocation InitLoc) { assert(Bitfield->isBitField()); if (Bitfield->isInvalidDecl()) return false; @@ -8899,7 +9155,7 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, /// Analyze the given simple or compound assignment for warning-worthy /// operations. -void AnalyzeAssignment(Sema &S, BinaryOperator *E) { +static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // Just recurse on the LHS. AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); @@ -8918,9 +9174,9 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, + SourceLocation CContext, unsigned diag, + bool pruneControlFlow = false) { if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) @@ -8933,16 +9189,16 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, - unsigned diag, bool pruneControlFlow = false) { +static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, + SourceLocation CContext, + unsigned diag, bool pruneControlFlow = false) { DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } /// Diagnose an implicit cast from a floating point value to an integer value. -void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, - - SourceLocation CContext) { +static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, + SourceLocation CContext) { const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); const bool PruneWarnings = S.inTemplateInstantiation(); @@ -9032,7 +9288,8 @@ void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, } } -std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { +static std::string PrettyPrintInRange(const llvm::APSInt &Value, + IntRange Range) { if (!Range.Width) return "0"; llvm::APSInt ValueInRange = Value; @@ -9041,7 +9298,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } -bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { +static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { if (!isa<ImplicitCastExpr>(Ex)) return false; @@ -9060,8 +9317,8 @@ bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { FloatCandidateBT && (FloatCandidateBT->isFloatingPoint())); } -void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, - SourceLocation CC) { +static void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, + SourceLocation CC) { unsigned NumArgs = TheCall->getNumArgs(); for (unsigned i = 0; i < NumArgs; ++i) { Expr *CurrA = TheCall->getArg(i); @@ -9081,7 +9338,8 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, } } -void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { +static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, E->getExprLoc())) return; @@ -9125,20 +9383,24 @@ void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { return; S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) - << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC) + << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC) << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T, Loc)); } -void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral); -void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral); +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); + +static void +checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); /// Check a single element within a collection literal against the /// target element type. -void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, - Expr *Element, unsigned ElementKind) { +static void checkObjCCollectionLiteralElement(Sema &S, + QualType TargetElementType, + Expr *Element, + unsigned ElementKind) { // Skip a bitcast to 'id' or qualified 'id'. if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { if (ICE->getCastKind() == CK_BitCast && @@ -9167,8 +9429,8 @@ void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, /// Check an Objective-C array literal being converted to the given /// target type. -void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral) { +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { if (!S.NSArrayDecl) return; @@ -9195,8 +9457,9 @@ void checkObjCArrayLiteral(Sema &S, QualType TargetType, /// Check an Objective-C dictionary literal being converted to the given /// target type. -void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral) { +static void +checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { if (!S.NSDictionaryDecl) return; @@ -9224,8 +9487,8 @@ void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, // Helper function to filter out cases for constant width constant conversion. // Don't warn on char array initialization or for non-decimal values. -bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC) { +static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { // If initializing from a constant, and the constant starts with '0', // then it is a binary, octal, or hexadecimal. Allow these constants // to fill all the bits, even if there is a sign change. @@ -9248,8 +9511,9 @@ bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, return true; } -void CheckImplicitConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC, bool *ICContext = nullptr) { +static void +CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, + bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -9316,10 +9580,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip complex types. if (isa<ComplexType>(Source)) { if (!isa<ComplexType>(Target)) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType()) return; - return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar); + return DiagnoseImpCast(S, E, T, CC, + S.getLangOpts().CPlusPlus + ? diag::err_impcast_complex_scalar + : diag::warn_impcast_complex_scalar); } Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); @@ -9514,11 +9781,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } -void CheckConditionalOperator(Sema &S, ConditionalOperator *E, - SourceLocation CC, QualType T); +static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, + SourceLocation CC, QualType T); -void CheckConditionalOperand(Sema &S, Expr *E, QualType T, - SourceLocation CC, bool &ICContext) { +static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, + SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); if (isa<ConditionalOperator>(E)) @@ -9529,8 +9796,8 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T, return CheckImplicitConversion(S, E, T, CC, &ICContext); } -void CheckConditionalOperator(Sema &S, ConditionalOperator *E, - SourceLocation CC, QualType T) { +static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, + SourceLocation CC, QualType T) { AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); bool Suspicious = false; @@ -9559,7 +9826,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. -void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { +static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); @@ -9568,7 +9835,8 @@ void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. -void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { +static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, + SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); @@ -9661,8 +9929,6 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } -} // end anonymous namespace - /// Diagnose integer type and any valid implicit convertion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, @@ -9968,10 +10234,11 @@ void Sema::CheckForIntOverflow (Expr *E) { } namespace { + /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { - typedef EvaluatedExprVisitor<SequenceChecker> Base; + using Base = EvaluatedExprVisitor<SequenceChecker>; /// \brief A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we @@ -9990,11 +10257,14 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// \brief A region within an expression which may be sequenced with respect /// to some other region. class Seq { - explicit Seq(unsigned N) : Index(N) {} - unsigned Index; friend class SequenceTree; + + unsigned Index = 0; + + explicit Seq(unsigned N) : Index(N) {} + public: - Seq() : Index(0) {} + Seq() = default; }; SequenceTree() { Values.push_back(Value(0)); } @@ -10038,16 +10308,18 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; /// An object for which we can track unsequenced uses. - typedef NamedDecl *Object; + using Object = NamedDecl *; /// Different flavors of object usage which we track. We only track the /// least-sequenced usage of each kind. enum UsageKind { /// A read of an object. Multiple unsequenced reads are OK. UK_Use, + /// A modification of an object which is sequenced before the value /// computation of the expression, such as ++n in C++. UK_ModAsValue, + /// A modification of an object which is not sequenced before the value /// computation of the expression, such as n++. UK_ModAsSideEffect, @@ -10056,29 +10328,37 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; struct Usage { - Usage() : Use(nullptr), Seq() {} - Expr *Use; + Expr *Use = nullptr; SequenceTree::Seq Seq; + + Usage() = default; }; struct UsageInfo { - UsageInfo() : Diagnosed(false) {} Usage Uses[UK_Count]; + /// Have we issued a diagnostic for this variable already? - bool Diagnosed; + bool Diagnosed = false; + + UsageInfo() = default; }; - typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap; + using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; Sema &SemaRef; + /// Sequenced regions within the expression. SequenceTree Tree; + /// Declaration modifications and references which we have seen. UsageInfoMap UsageMap; + /// The region we are currently within. SequenceTree::Seq Region; + /// Filled in with declarations which were modified as a side-effect /// (that is, post-increment operations). - SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect; + SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr; + /// Expressions to check later. We defer checking these to reduce /// stack usage. SmallVectorImpl<Expr *> &WorkList; @@ -10093,6 +10373,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) { Self.ModAsSideEffect = &ModAsSideEffect; } + ~SequencedSubexpression() { for (auto &M : llvm::reverse(ModAsSideEffect)) { UsageInfo &U = Self.UsageMap[M.first]; @@ -10105,7 +10386,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SequenceChecker &Self; SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect; - SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect; + SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect; }; /// RAII object wrapping the visitation of a subexpression which we might @@ -10115,9 +10396,10 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { class EvaluationTracker { public: EvaluationTracker(SequenceChecker &Self) - : Self(Self), Prev(Self.EvalTracker), EvalOK(true) { + : Self(Self), Prev(Self.EvalTracker) { Self.EvalTracker = this; } + ~EvaluationTracker() { Self.EvalTracker = Prev; if (Prev) @@ -10134,8 +10416,8 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { private: SequenceChecker &Self; EvaluationTracker *Prev; - bool EvalOK; - } *EvalTracker; + bool EvalOK = true; + } *EvalTracker = nullptr; /// \brief Find the object which is produced by the specified expression, /// if any. @@ -10169,6 +10451,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { U.Seq = Region; } } + /// \brief Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { @@ -10196,6 +10479,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { // Uses conflict with other modifications. checkUsage(O, U, Use, UK_ModAsValue, false); } + void notePostUse(Object O, Expr *Use) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, false); @@ -10208,6 +10492,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { checkUsage(O, U, Mod, UK_ModAsValue, true); checkUsage(O, U, Mod, UK_Use, false); } + void notePostMod(Object O, Expr *Use, UsageKind UK) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, true); @@ -10216,8 +10501,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { public: SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList) - : Base(S.Context), SemaRef(S), Region(Tree.root()), - ModAsSideEffect(nullptr), WorkList(WorkList), EvalTracker(nullptr) { + : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) { Visit(E); } @@ -10451,7 +10735,8 @@ public: Tree.merge(Elts[I]); } }; -} // end anonymous namespace + +} // namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector<Expr *, 8> WorkList; @@ -10868,19 +11153,22 @@ void Sema::CheckArrayAccess(const Expr *expr) { //===--- CHECK: Objective-C retain cycles ----------------------------------// namespace { - struct RetainCycleOwner { - RetainCycleOwner() : Variable(nullptr), Indirect(false) {} - VarDecl *Variable; - SourceRange Range; - SourceLocation Loc; - bool Indirect; - void setLocsFrom(Expr *e) { - Loc = e->getExprLoc(); - Range = e->getSourceRange(); - } - }; -} // end anonymous namespace +struct RetainCycleOwner { + VarDecl *Variable = nullptr; + SourceRange Range; + SourceLocation Loc; + bool Indirect = false; + + RetainCycleOwner() = default; + + void setLocsFrom(Expr *e) { + Loc = e->getExprLoc(); + Range = e->getSourceRange(); + } +}; + +} // namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. @@ -10977,15 +11265,16 @@ static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) { } namespace { + struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> { - FindCaptureVisitor(ASTContext &Context, VarDecl *variable) - : EvaluatedExprVisitor<FindCaptureVisitor>(Context), - Context(Context), Variable(variable), Capturer(nullptr), - VarWillBeReased(false) {} ASTContext &Context; VarDecl *Variable; - Expr *Capturer; - bool VarWillBeReased; + Expr *Capturer = nullptr; + bool VarWillBeReased = false; + + FindCaptureVisitor(ASTContext &Context, VarDecl *variable) + : EvaluatedExprVisitor<FindCaptureVisitor>(Context), + Context(Context), Variable(variable) {} void VisitDeclRefExpr(DeclRefExpr *ref) { if (ref->getDecl() == Variable && !Capturer) @@ -11010,6 +11299,7 @@ namespace { if (OVE->getSourceExpr()) Visit(OVE->getSourceExpr()); } + void VisitBinaryOperator(BinaryOperator *BinOp) { if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign) return; @@ -11026,7 +11316,8 @@ namespace { } } }; -} // end anonymous namespace + +} // namespace /// Check whether the given argument is a block which captures a /// variable. @@ -11283,9 +11574,15 @@ void Sema::checkRetainCycles(ObjCMessageExpr *msg) { } // Check whether the receiver is captured by any of the arguments. - for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) - if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) + const ObjCMethodDecl *MD = msg->getMethodDecl(); + for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) { + if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) { + // noescape blocks should not be retained by the method. + if (MD && MD->parameters()[i]->hasAttr<NoEscapeAttr>()) + continue; return diagnoseRetainCycle(*this, capturer, owner); + } + } } /// Check a property assign to see if it's likely to cause a retain cycle. @@ -11433,16 +11730,14 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, //===--- CHECK: Empty statement body (-Wempty-body) ---------------------===// -namespace { -bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, - SourceLocation StmtLoc, - const NullStmt *Body) { +static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, + SourceLocation StmtLoc, + const NullStmt *Body) { // Do not warn if the body is a macro that expands to nothing, e.g: // // #define CALL(x) // if (condition) // CALL(0); - // if (Body->hasLeadingEmptyMacro()) return false; @@ -11465,7 +11760,6 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, return true; } -} // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, @@ -11577,9 +11871,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, return; // Check for a call to std::move - const FunctionDecl *FD = CE->getDirectCallee(); - if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || - !FD->getIdentifier()->isStr("move")) + if (!CE->isCallToStdMove()) return; // Get argument from std::move @@ -11647,12 +11939,10 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, //===--- Layout compatibility ----------------------------------------------// -namespace { - -bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); +static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); /// \brief Check if two enumeration types are layout-compatible. -bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { +static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same // underlying type. @@ -11661,7 +11951,8 @@ bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { } /// \brief Check if two fields are layout-compatible. -bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { +static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, + FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) return false; @@ -11682,9 +11973,8 @@ bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { /// \brief Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) -bool isLayoutCompatibleStruct(ASTContext &C, - RecordDecl *RD1, - RecordDecl *RD2) { +static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { // If both records are C++ classes, check that base classes match. if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) { // If one of records is a CXXRecordDecl we are in C++ mode, @@ -11727,9 +12017,8 @@ bool isLayoutCompatibleStruct(ASTContext &C, /// \brief Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) -bool isLayoutCompatibleUnion(ASTContext &C, - RecordDecl *RD1, - RecordDecl *RD2) { +static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields; for (auto *Field2 : RD2->fields()) UnmatchedFields.insert(Field2); @@ -11754,7 +12043,8 @@ bool isLayoutCompatibleUnion(ASTContext &C, return UnmatchedFields.empty(); } -bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { +static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { if (RD1->isUnion() != RD2->isUnion()) return false; @@ -11765,7 +12055,7 @@ bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { } /// \brief Check if two types are layout-compatible in C++11 sense. -bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { +static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; @@ -11799,11 +12089,9 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { return false; } -} // end anonymous namespace //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// -namespace { /// \brief Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. @@ -11811,8 +12099,8 @@ namespace { /// \param VD Declaration of an identifier that appears in a type tag. /// /// \param MagicValue Type tag magic value. -bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, - const ValueDecl **VD, uint64_t *MagicValue) { +static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, + const ValueDecl **VD, uint64_t *MagicValue) { while(true) { if (!TypeExpr) return false; @@ -11887,7 +12175,7 @@ bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, /// \param TypeInfo Information about the corresponding C type. /// /// \returns true if the corresponding C type was found. -bool GetMatchingCType( +static bool GetMatchingCType( const IdentifierInfo *ArgumentKind, const Expr *TypeExpr, const ASTContext &Ctx, const llvm::DenseMap<Sema::TypeTagMagicValue, @@ -11930,7 +12218,6 @@ bool GetMatchingCType( TypeInfo = I->second; return true; } -} // end anonymous namespace void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, @@ -11945,8 +12232,7 @@ void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, TypeTagData(Type, LayoutCompatible, MustBeNull); } -namespace { -bool IsSameCharType(QualType T1, QualType T2) { +static bool IsSameCharType(QualType T1, QualType T2) { const BuiltinType *BT1 = T1->getAs<BuiltinType>(); if (!BT1) return false; @@ -11963,13 +12249,20 @@ bool IsSameCharType(QualType T1, QualType T2) { (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); } -} // end anonymous namespace void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, - const Expr * const *ExprArgs) { + const ArrayRef<const Expr *> ExprArgs, + SourceLocation CallSiteLoc) { const IdentifierInfo *ArgumentKind = Attr->getArgumentKind(); bool IsPointerAttr = Attr->getIsPointer(); + // Retrieve the argument representing the 'type_tag'. + if (Attr->getTypeTagIdx() >= ExprArgs.size()) { + // Add 1 to display the user's specified value. + Diag(CallSiteLoc, diag::err_tag_index_out_of_range) + << 0 << Attr->getTypeTagIdx() + 1; + return; + } const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; bool FoundWrongKind; TypeTagData TypeInfo; @@ -11983,6 +12276,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, return; } + // Retrieve the argument representing the 'arg_idx'. + if (Attr->getArgumentIdx() >= ExprArgs.size()) { + // Add 1 to display the user's specified value. + Diag(CallSiteLoc, diag::err_tag_index_out_of_range) + << 1 << Attr->getArgumentIdx() + 1; + return; + } const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). @@ -12074,8 +12374,9 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { MisalignedMember(Op)); if (MA != MisalignedMembers.end() && (T->isIntegerType() || - (T->isPointerType() && - Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) + (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || + Context.getTypeAlignInChars( + T->getPointeeType()) <= MA->Alignment)))) MisalignedMembers.erase(MA); } } @@ -12192,8 +12493,8 @@ void Sema::RefersToMemberWithReducedAlignment( void Sema::CheckAddressOfPackedMember(Expr *rhs) { using namespace std::placeholders; + RefersToMemberWithReducedAlignment( rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, _2, _3, _4)); } - diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index 4de7d422072da..834e149d1af4c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -10,10 +10,11 @@ // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/QualTypeNames.h" #include "clang/Basic/CharInfo.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" @@ -23,6 +24,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -46,7 +48,7 @@ namespace { /// the result set (when it returns true) and which declarations should be /// filtered out (returns false). typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const; - + typedef CodeCompletionResult Result; private: @@ -741,8 +743,18 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) { } const DeclContext *DC = ND->getDeclContext()->getRedeclContext(); - if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) + if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) { + // Explicit destructor calls are very rare. + if (isa<CXXDestructorDecl>(ND)) + return CCP_Unlikely; + // Explicit operator and conversion function calls are also very rare. + auto DeclNameKind = ND->getDeclName().getNameKind(); + if (DeclNameKind == DeclarationName::CXXOperatorName || + DeclNameKind == DeclarationName::CXXLiteralOperatorName || + DeclNameKind == DeclarationName::CXXConversionFunctionName) + return CCP_Unlikely; return CCP_MemberDeclaration; + } // Content-based decisions. if (isa<EnumConstantDecl>(ND)) @@ -1070,9 +1082,16 @@ bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { /// ordinary name lookup but is not a type name. bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { ND = cast<NamedDecl>(ND->getUnderlyingDecl()); - if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) + if (isa<TypeDecl>(ND)) return false; - + // Objective-C interfaces names are not filtered by this method because they + // can be used in a class property expression. We can still filter out + // @class declarations though. + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) { + if (!ID->getDefinition()) + return false; + } + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; @@ -1484,6 +1503,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, Policy.AnonymousTagLocations = false; Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; + Policy.SuppressScope = true; return Policy; } @@ -1647,21 +1667,23 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); + bool IsNotInheritanceScope = + !(S->getFlags() & Scope::ClassInheritanceScope); // public: Builder.AddTypedTextChunk("public"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // protected: Builder.AddTypedTextChunk("protected"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // private: Builder.AddTypedTextChunk("private"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); } @@ -2126,9 +2148,10 @@ static void AddResultTypeChunk(ASTContext &Context, T = Method->getSendResultType(BaseType); else T = Method->getReturnType(); - } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) { T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); - else if (isa<UnresolvedUsingValueDecl>(ND)) { + T = clang::TypeName::getFullyQualifiedType(T, Context); + } else if (isa<UnresolvedUsingValueDecl>(ND)) { /* Do nothing: ignore unresolved using declarations*/ } else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { if (!BaseType.isNull()) @@ -3355,12 +3378,9 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, return; PrintingPolicy Policy = getCompletionPrintingPolicy(S); - for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), - MEnd = Method->end_overridden_methods(); - M != MEnd; ++M) { + for (const CXXMethodDecl *Overridden : Method->overridden_methods()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - const CXXMethodDecl *Overridden = *M; if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) continue; @@ -4282,13 +4302,17 @@ static void mergeCandidatesWithResults(Sema &SemaRef, std::stable_sort( CandidateSet.begin(), CandidateSet.end(), [&](const OverloadCandidate &X, const OverloadCandidate &Y) { - return isBetterOverloadCandidate(SemaRef, X, Y, Loc); + return isBetterOverloadCandidate(SemaRef, X, Y, Loc, + CandidateSet.getKind()); }); // Add the remaining viable overload candidates as code-completion results. - for (auto &Candidate : CandidateSet) + for (auto &Candidate : CandidateSet) { + if (Candidate.Function && Candidate.Function->isDeleted()) + continue; if (Candidate.Viable) Results.push_back(ResultCandidate(Candidate.Function)); + } } } @@ -4379,9 +4403,11 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) { ArgExprs.append(Args.begin(), Args.end()); UnresolvedSet<8> Decls; Decls.append(UME->decls_begin(), UME->decls_end()); + const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase(); AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs, /*SuppressUsedConversions=*/false, - /*PartialOverloading=*/true); + /*PartialOverloading=*/true, + FirstArgumentIsBase); } else { FunctionDecl *FD = nullptr; if (auto MCE = dyn_cast<MemberExpr>(NakedFn)) @@ -4574,9 +4600,19 @@ void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) { void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { - if (!SS.getScopeRep() || !CodeCompleter) + if (SS.isEmpty() || !CodeCompleter) return; + // We want to keep the scope specifier even if it's invalid (e.g. the scope + // "a::b::" is not corresponding to any context/namespace in the AST), since + // it can be useful for global code completion which have information about + // contexts/symbols that are not in the AST. + if (SS.isInvalid()) { + CodeCompletionContext CC(CodeCompletionContext::CCC_Name); + CC.setCXXScopeSpecifier(SS); + HandleCodeCompleteResults(this, CodeCompleter, CC, nullptr, 0); + return; + } // Always pretend to enter a context to ensure that a dependent type // resolves to a dependent record. DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); @@ -4592,7 +4628,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Name); Results.EnterNewScope(); - + // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. NestedNameSpecifier *NNS = SS.getScopeRep(); @@ -4606,16 +4642,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // qualified-id completions. if (!EnteringContext) MaybeAddOverrideCalls(*this, Ctx, Results); - Results.ExitScope(); - - CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, - /*IncludeGlobalScope=*/true, - /*IncludeDependentBases=*/true); + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - Results.getCompletionContext(), - Results.data(),Results.size()); + if (CodeCompleter->includeNamespaceLevelDecls() || + (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, + /*IncludeGlobalScope=*/true, + /*IncludeDependentBases=*/true); + } + + auto CC = Results.getCompletionContext(); + CC.setCXXScopeSpecifier(SS); + + HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(), + Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { @@ -6630,7 +6671,7 @@ typedef llvm::DenseMap< /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, - bool WantInstanceMethods, + Optional<bool> WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { @@ -6701,7 +6742,7 @@ static void FindImplementableMethods(ASTContext &Context, // we want the methods from this container to override any methods // we've previously seen with the same selector. for (auto *M : Container->methods()) { - if (M->isInstanceMethod() == WantInstanceMethods) { + if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) { if (!ReturnType.isNull() && !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType())) continue; @@ -7373,8 +7414,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } } -void Sema::CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, +void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. @@ -7429,7 +7469,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ObjCMethodDecl *Method = M->second.getPointer(); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + + // Add the '-'/'+' prefix if it wasn't provided yet. + if (!IsInstanceMethod) { + Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + } + // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) { @@ -7531,11 +7577,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, if (IFace) for (auto *Cat : IFace->visible_categories()) Containers.push_back(Cat); - - for (unsigned I = 0, N = Containers.size(); I != N; ++I) - for (auto *P : Containers[I]->instance_properties()) - AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context, - KnownSelectors, Results); + + if (IsInstanceMethod) { + for (unsigned I = 0, N = Containers.size(); I != N; ++I) + for (auto *P : Containers[I]->instance_properties()) + AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context, + KnownSelectors, Results); + } } Results.ExitScope(); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp index dc7d8e4e9cec3..e6b640f878c2b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp @@ -363,6 +363,32 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr); } +// See if return type is coroutine-handle and if so, invoke builtin coro-resume +// on its address. This is to enable experimental support for coroutine-handle +// returning await_suspend that results in a guranteed tail call to the target +// coroutine. +static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, + SourceLocation Loc) { + if (RetType->isReferenceType()) + return nullptr; + Type const *T = RetType.getTypePtr(); + if (!T->isClassType() && !T->isStructureType()) + return nullptr; + + // FIXME: Add convertability check to coroutine_handle<>. Possibly via + // EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment + // a private function in SemaExprCXX.cpp + + ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None); + if (AddressExpr.isInvalid()) + return nullptr; + + Expr *JustAddress = AddressExpr.get(); + // FIXME: Check that the type of AddressExpr is void* + return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, + JustAddress); +} + /// Build calls to await_ready, await_suspend, and await_resume for a co_await /// expression. static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, @@ -412,16 +438,21 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, // - await-suspend is the expression e.await_suspend(h), which shall be // a prvalue of type void or bool. QualType RetType = AwaitSuspend->getCallReturnType(S.Context); - // non-class prvalues always have cv-unqualified types - QualType AdjRetType = RetType.getUnqualifiedType(); - if (RetType->isReferenceType() || - (AdjRetType != S.Context.BoolTy && AdjRetType != S.Context.VoidTy)) { - S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), - diag::err_await_suspend_invalid_return_type) - << RetType; - S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) - << AwaitSuspend->getDirectCallee(); - Calls.IsInvalid = true; + + // Experimental support for coroutine_handle returning await_suspend. + if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc)) + Calls.Results[ACT::ACT_Suspend] = TailCallSuspend; + else { + // non-class prvalues always have cv-unqualified types + if (RetType->isReferenceType() || + (!RetType->isBooleanType() && !RetType->isVoidType())) { + S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(), + diag::err_await_suspend_invalid_return_type) + << RetType; + S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) + << AwaitSuspend->getDirectCallee(); + Calls.IsInvalid = true; + } } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index 59c10128f9087..ec5ca69735683 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -132,6 +132,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw__Float16: case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: @@ -280,7 +281,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, IdentifierInfo **CorrectedII) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && - getLangOpts().CPlusPlus1z && !IsCtorOrDtorName && + getLangOpts().CPlusPlus17 && !IsCtorOrDtorName && !isClassName && !HasTrailingDot; // Determine where we will perform name lookup. @@ -1447,6 +1448,46 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, F.done(); } +/// We've determined that \p New is a redeclaration of \p Old. Check that they +/// have compatible owning modules. +bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { + // FIXME: The Modules TS is not clear about how friend declarations are + // to be treated. It's not meaningful to have different owning modules for + // linkage in redeclarations of the same entity, so for now allow the + // redeclaration and change the owning modules to match. + if (New->getFriendObjectKind() && + Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) { + New->setLocalOwningModule(Old->getOwningModule()); + makeMergedDefinitionVisible(New); + return false; + } + + Module *NewM = New->getOwningModule(); + Module *OldM = Old->getOwningModule(); + if (NewM == OldM) + return false; + + // FIXME: Check proclaimed-ownership-declarations here too. + bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit; + bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit; + if (NewIsModuleInterface || OldIsModuleInterface) { + // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]: + // if a declaration of D [...] appears in the purview of a module, all + // other such declarations shall appear in the purview of the same module + Diag(New->getLocation(), diag::err_mismatched_owning_module) + << New + << NewIsModuleInterface + << (NewIsModuleInterface ? NewM->getFullModuleName() : "") + << OldIsModuleInterface + << (OldIsModuleInterface ? OldM->getFullModuleName() : ""); + Diag(Old->getLocation(), diag::note_previous_declaration); + New->setInvalidDecl(); + return true; + } + + return false; +} + static bool isUsingDecl(NamedDecl *D) { return isa<UsingShadowDecl>(D) || isa<UnresolvedUsingTypenameDecl>(D) || @@ -1682,7 +1723,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { dyn_cast<CXXConstructExpr>(Init); if (Construct && !Construct->isElidable()) { CXXConstructorDecl *CD = Construct->getConstructor(); - if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>()) + if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>() && + (VD->getInit()->isValueDependent() || !VD->evaluateValue())) return false; } } @@ -2623,6 +2665,16 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, } } + // This redeclaration adds a section attribute. + if (New->hasAttr<SectionAttr>() && !Old->hasAttr<SectionAttr>()) { + if (auto *VD = dyn_cast<VarDecl>(New)) { + if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) { + Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration); + Diag(Old->getLocation(), diag::note_previous_declaration); + } + } + } + if (!Old->hasAttrs()) return; @@ -2951,6 +3003,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, New->dropAttr<InternalLinkageAttr>(); } + if (CheckRedeclarationModuleOwnership(New, Old)) + return true; + if (!getLangOpts().CPlusPlus) { bool OldOvl = Old->hasAttr<OverloadableAttr>(); if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) { @@ -3526,8 +3581,6 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne && oi != oe; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, *this); - - CheckObjCMethodOverride(newMethod, oldMethod); } static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { @@ -3820,6 +3873,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + if (CheckRedeclarationModuleOwnership(New, Old)) + return; + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -3843,7 +3899,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } } - // If this redeclaration makes the function inline, we may need to add it to + // If this redeclaration makes the variable inline, we may need to add it to // UndefinedButUsed. if (!Old->isInline() && New->isInline() && Old->isUsed(false) && !Old->getDefinition() && !New->isThisDeclarationADefinition()) @@ -4143,7 +4199,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (DS.isConstexprSpecified()) { // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations @@ -4157,14 +4213,6 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, return TagD; } - if (DS.isConceptSpecified()) { - // C++ Concepts TS [dcl.spec.concept]p1: A concept definition refers to - // either a function concept and its definition or a variable concept and - // its initializer. - Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind); - return TagD; - } - DiagnoseFunctionSpecifiers(DS); if (DS.isFriendSpecified()) { @@ -4371,7 +4419,7 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, SourceLocation NameLoc, bool IsUnion) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); if (!SemaRef.LookupName(R, S)) return false; // Pick a representative declaration. @@ -5305,19 +5353,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); - if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo)) - // If this is a typedef, we'll end up spewing multiple diagnostics. - // Just return early; it's safer. If this is a function, let the - // "constructor cannot have a return type" diagnostic handle it. - if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - return nullptr; - if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); // See if this is a redefinition of a variable in the same scope. if (!D.getCXXScopeSpec().isSet()) { @@ -5343,8 +5384,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) CreateBuiltins = true; - if (IsLinkageLookup) + if (IsLinkageLookup) { Previous.clear(LookupRedeclarationWithLinkage); + Previous.setRedeclarationKind(ForExternalRedeclaration); + } LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" @@ -5390,12 +5433,17 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, Previous.clear(); } + if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo)) + // Forget that the previous declaration is the injected-class-name. + Previous.clear(); + // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the - // tag type. Note that this does does not apply if we're declaring a - // typedef (C++ [dcl.typedef]p4). + // tag type. Note that this applies to functions, function templates, and + // variables, but not to typedefs (C++ [dcl.typedef]p4) or variable templates. if (Previous.isSingleTagDecl() && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + (TemplateParamLists.size() == 0 || R->isFunctionType())) Previous.clear(); // Check that there are no default arguments other than in the parameters @@ -5403,23 +5451,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (getLangOpts().CPlusPlus) CheckExtraCXXDefaultArguments(D); - if (D.getDeclSpec().isConceptSpecified()) { - // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be - // applied only to the definition of a function template or variable - // template, declared in namespace scope - if (!TemplateParamLists.size()) { - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag:: err_concept_wrong_decl_kind); - return nullptr; - } - - if (!DC->getRedeclContext()->isFileContext()) { - Diag(D.getIdentifierLoc(), - diag::err_concept_decls_may_only_appear_in_namespace_scope); - return nullptr; - } - } - NamedDecl *New; bool AddToScope = true; @@ -5634,13 +5665,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; - if (D.getDeclSpec().isConceptSpecified()) - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag::err_concept_wrong_decl_kind); if (D.getName().Kind != UnqualifiedId::IK_Identifier) { if (D.getName().Kind == UnqualifiedId::IK_DeductionGuideName) @@ -5919,7 +5947,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, bool IsSpecialization, bool IsDefinition) { - if (OldDecl->isInvalidDecl()) + if (OldDecl->isInvalidDecl() || NewDecl->isInvalidDecl()) return; bool IsTemplate = false; @@ -6025,13 +6053,30 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NewDecl->dropAttr<DLLImportAttr>(); } } else if (IsInline && OldImportAttr && !IsMicrosoft) { - // In MinGW, seeing a function declared inline drops the dllimport attribute. + // In MinGW, seeing a function declared inline drops the dllimport + // attribute. OldDecl->dropAttr<DLLImportAttr>(); NewDecl->dropAttr<DLLImportAttr>(); S.Diag(NewDecl->getLocation(), diag::warn_dllimport_dropped_from_inline_function) << NewDecl << OldImportAttr; } + + // A specialization of a class template member function is processed here + // since it's a redeclaration. If the parent class is dllexport, the + // specialization inherits that attribute. This doesn't happen automatically + // since the parent class isn't instantiated until later. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDecl)) { + if (MD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization && + !NewImportAttr && !NewExportAttr) { + if (const DLLExportAttr *ParentExportAttr = + MD->getParent()->getAttr<DLLExportAttr>()) { + DLLExportAttr *NewAttr = ParentExportAttr->clone(S.Context); + NewAttr->setInherited(true); + NewDecl->addAttr(NewAttr); + } + } + } } /// Given that we are within the definition of the given function, @@ -6253,7 +6298,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( // The event type cannot be used with the __local, __constant and __global // address space qualifiers. if (R->isEventT()) { - if (R.getAddressSpace()) { + if (R.getAddressSpace() != LangAS::opencl_private) { Diag(D.getLocStart(), diag::err_event_t_addr_space_qual); D.setInvalidType(); } @@ -6289,7 +6334,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( // Suppress the warning in system macros, it's used in macros in some // popular C system headers, such as in glibc's htonl() macro. Diag(D.getDeclSpec().getStorageClassSpecLoc(), - getLangOpts().CPlusPlus1z ? diag::ext_register_storage_class + getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class : diag::warn_deprecated_register) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } @@ -6477,49 +6522,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( // C++1z [dcl.spec.constexpr]p1: // A static data member declared with the constexpr specifier is // implicitly an inline variable. - if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus1z) + if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17) NewVD->setImplicitlyInline(); } - - if (D.getDeclSpec().isConceptSpecified()) { - if (VarTemplateDecl *VTD = NewVD->getDescribedVarTemplate()) - VTD->setConcept(); - - // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not - // be declared with the thread_local, inline, friend, or constexpr - // specifiers, [...] - if (D.getDeclSpec().getThreadStorageClassSpec() == TSCS_thread_local) { - Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), - diag::err_concept_decl_invalid_specifiers) - << 0 << 0; - NewVD->setInvalidDecl(true); - } - - if (D.getDeclSpec().isConstexprSpecified()) { - Diag(D.getDeclSpec().getConstexprSpecLoc(), - diag::err_concept_decl_invalid_specifiers) - << 0 << 3; - NewVD->setInvalidDecl(true); - } - - // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be - // applied only to the definition of a function template or variable - // template, declared in namespace scope. - if (IsVariableTemplateSpecialization) { - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag::err_concept_specified_specialization) - << (IsPartialSpecialization ? 2 : 1); - } - - // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the - // following restrictions: - // - The declared type shall have the type bool. - if (!Context.hasSameType(NewVD->getType(), Context.BoolTy) && - !NewVD->isInvalidDecl()) { - Diag(D.getIdentifierLoc(), diag::err_variable_concept_bool_decl); - NewVD->setInvalidDecl(true); - } - } } if (D.getDeclSpec().isInlineSpecified()) { @@ -6533,7 +6538,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } else { Diag(D.getDeclSpec().getInlineSpecLoc(), - getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_inline_variable + getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_inline_variable : diag::ext_inline_variable); NewVD->setInlineSpecified(); } @@ -6770,25 +6775,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (!IsVariableTemplateSpecialization) D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); - // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...] - // an explicit specialization (14.8.3) or a partial specialization of a - // concept definition. - if (IsVariableTemplateSpecialization && - !D.getDeclSpec().isConceptSpecified() && !Previous.empty() && - Previous.isSingleResult()) { - NamedDecl *PreviousDecl = Previous.getFoundDecl(); - if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(PreviousDecl)) { - if (VarTmpl->isConcept()) { - Diag(NewVD->getLocation(), diag::err_concept_specialized) - << 1 /*variable*/ - << (IsPartialSpecialization ? 2 /*partially specialized*/ - : 1 /*explicitly specialized*/); - Diag(VarTmpl->getLocation(), diag::note_previous_declaration); - NewVD->setInvalidDecl(); - } - } - } - if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() @@ -7087,7 +7073,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { return; LookupResult R(*this, D->getDeclName(), D->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); LookupName(R, S); if (NamedDecl *ShadowedDecl = getShadowedDeclaration(D, R)) CheckShadow(D, ShadowedDecl, R); @@ -7260,8 +7246,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. // ISO/IEC TR 18037 S5.1.2 - if (!getLangOpts().OpenCL - && NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { + if (!getLangOpts().OpenCL && NewVD->hasLocalStorage() && + T.getAddressSpace() != LangAS::Default) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 0; NewVD->setInvalidDecl(); return; @@ -7356,7 +7342,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } } - } else if (T.getAddressSpace() != LangAS::Default) { + } else if (T.getAddressSpace() != LangAS::opencl_private) { // Do not allow other address spaces on automatic variable. Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1; NewVD->setInvalidDecl(); @@ -7531,16 +7517,14 @@ enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, OverrideErrorKind OEK = OEK_All) { S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) { + for (const CXXMethodDecl *O : MD->overridden_methods()) { // This check (& the OEK parameter) could be replaced by a predicate, but // without lambdas that would be overkill. This is still nicer than writing // out the diag loop 3 times. if ((OEK == OEK_All) || - (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || - (OEK == OEK_Deleted && (*I)->isDeleted())) - S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + (OEK == OEK_NonDeleted && !O->isDeleted()) || + (OEK == OEK_Deleted && O->isDeleted())) + S.Diag(O->getLocation(), diag::note_overridden_virtual_function); } } @@ -7663,7 +7647,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration( LookupResult Prev(SemaRef, Name, NewFD->getLocation(), IsLocalFriend ? Sema::LookupLocalFriendName : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); NewFD->setInvalidDecl(); if (IsLocalFriend) @@ -7991,7 +7975,8 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PointeeType->isPointerType()) return PtrPtrKernelParam; if (PointeeType.getAddressSpace() == LangAS::opencl_generic || - PointeeType.getAddressSpace() == 0) + PointeeType.getAddressSpace() == LangAS::opencl_private || + PointeeType.getAddressSpace() == LangAS::Default) return InvalidAddrSpacePtrKernelParam; return PtrKernelParam; } @@ -8241,7 +8226,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); - bool isConcept = D.getDeclSpec().isConceptSpecified(); isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 @@ -8453,89 +8437,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor); } - if (isConcept) { - // This is a function concept. - if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate()) - FTD->setConcept(); - - // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be - // applied only to the definition of a function template [...] - if (!D.isFunctionDefinition()) { - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag::err_function_concept_not_defined); - NewFD->setInvalidDecl(); - } - - // C++ Concepts TS [dcl.spec.concept]p1: [...] A function concept shall - // have no exception-specification and is treated as if it were specified - // with noexcept(true) (15.4). [...] - if (const FunctionProtoType *FPT = R->getAs<FunctionProtoType>()) { - if (FPT->hasExceptionSpec()) { - SourceRange Range; - if (D.isFunctionDeclarator()) - Range = D.getFunctionTypeInfo().getExceptionSpecRange(); - Diag(NewFD->getLocation(), diag::err_function_concept_exception_spec) - << FixItHint::CreateRemoval(Range); - NewFD->setInvalidDecl(); - } else { - Context.adjustExceptionSpec(NewFD, EST_BasicNoexcept); - } - - // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the - // following restrictions: - // - The declared return type shall have the type bool. - if (!Context.hasSameType(FPT->getReturnType(), Context.BoolTy)) { - Diag(D.getIdentifierLoc(), diag::err_function_concept_bool_ret); - NewFD->setInvalidDecl(); - } - - // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the - // following restrictions: - // - The declaration's parameter list shall be equivalent to an empty - // parameter list. - if (FPT->getNumParams() > 0 || FPT->isVariadic()) - Diag(NewFD->getLocation(), diag::err_function_concept_with_params); - } - - // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is - // implicity defined to be a constexpr declaration (implicitly inline) - NewFD->setImplicitlyInline(); - - // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not - // be declared with the thread_local, inline, friend, or constexpr - // specifiers, [...] - if (isInline) { - Diag(D.getDeclSpec().getInlineSpecLoc(), - diag::err_concept_decl_invalid_specifiers) - << 1 << 1; - NewFD->setInvalidDecl(true); - } - - if (isFriend) { - Diag(D.getDeclSpec().getFriendSpecLoc(), - diag::err_concept_decl_invalid_specifiers) - << 1 << 2; - NewFD->setInvalidDecl(true); - } - - if (isConstexpr) { - Diag(D.getDeclSpec().getConstexprSpecLoc(), - diag::err_concept_decl_invalid_specifiers) - << 1 << 3; - NewFD->setInvalidDecl(true); - } - - // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be - // applied only to the definition of a function template or variable - // template, declared in namespace scope. - if (isFunctionTemplateSpecialization) { - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag::err_concept_specified_specialization) << 1; - NewFD->setInvalidDecl(true); - return NewFD; - } - } - // If __module_private__ was specified, mark the function accordingly. if (D.getDeclSpec().isModulePrivateSpecified()) { if (isFunctionTemplateSpecialization) { @@ -8760,10 +8661,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return // type declaration will generate a compilation error. - unsigned AddressSpace = NewFD->getReturnType().getAddressSpace(); - if (AddressSpace == LangAS::opencl_local || - AddressSpace == LangAS::opencl_global || - AddressSpace == LangAS::opencl_constant) { + LangAS AddressSpace = NewFD->getReturnType().getAddressSpace(); + if (AddressSpace != LangAS::Default) { Diag(NewFD->getLocation(), diag::err_opencl_return_value_with_address_space); NewFD->setInvalidDecl(); @@ -8890,10 +8789,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::ext_function_specialization_in_class : diag::err_function_specialization_in_class) << NewFD->getDeclName(); - } else if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs - : nullptr), - Previous)) + } else if (!NewFD->isInvalidDecl() && + CheckFunctionTemplateSpecialization( + NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), + Previous)) NewFD->setInvalidDecl(); // C++ [dcl.stc]p1: @@ -9529,7 +9428,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // return type. (Exception specifications on the function itself are OK in // most cases, and exception specifications are not permitted in most other // contexts where they could make it into a mangling.) - if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) { + if (!getLangOpts().CPlusPlus17 && !NewFD->getPrimaryTemplate()) { auto HasNoexcept = [&](QualType T) -> bool { // Strip off declarator chunks that could be between us and a function // type. We don't need to look far, exception specifications are very @@ -9552,7 +9451,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, AnyNoexcept |= HasNoexcept(T); if (AnyNoexcept) Diag(NewFD->getLocation(), - diag::warn_cxx1z_compat_exception_spec_in_signature) + diag::warn_cxx17_compat_exception_spec_in_signature) << NewFD; } @@ -9601,6 +9500,13 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType* FT = T->castAs<FunctionType>(); + // Set default calling convention for main() + if (FT->getCallConv() != CC_C) { + FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC_C)); + FD->setType(QualType(FT, 0)); + T = Context.getCanonicalType(FD->getType()); + } + if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) { // In C with GNU extensions we allow main() to have non-integer return // type, but we should warn about the extension, and we disable the @@ -10000,14 +9906,9 @@ namespace { void VisitCallExpr(CallExpr *E) { // Treat std::move as a use. - if (E->getNumArgs() == 1) { - if (FunctionDecl *FD = E->getDirectCallee()) { - if (FD->isInStdNamespace() && FD->getIdentifier() && - FD->getIdentifier()->isStr("move")) { - HandleValue(E->getArg(0)); - return; - } - } + if (E->isCallToStdMove()) { + HandleValue(E->getArg(0)); + return; } Inherited::VisitCallExpr(E); @@ -10737,7 +10638,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { if (Var->isStaticDataMember()) { // C++1z removes the relevant rule; the in-class declaration is always // a definition there. - if (!getLangOpts().CPlusPlus1z) { + if (!getLangOpts().CPlusPlus17) { Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) << Var->getDeclName(); @@ -10751,17 +10652,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { } } - // C++ Concepts TS [dcl.spec.concept]p1: [...] A variable template - // definition having the concept specifier is called a variable concept. A - // concept definition refers to [...] a variable concept and its initializer. - if (VarTemplateDecl *VTD = Var->getDescribedVarTemplate()) { - if (VTD->isConcept()) { - Diag(Var->getLocation(), diag::err_var_concept_not_initialized); - Var->setInvalidDecl(); - return; - } - } - // OpenCL v1.1 s6.5.3: variables declared in the constant address space must // be initialized. if (!Var->isInvalidDecl() && @@ -11651,6 +11541,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { StorageClass SC = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { SC = SC_Register; + // In C++11, the 'register' storage class specifier is deprecated. + // In C++17, it is not allowed, but we tolerate it as an extension. + if (getLangOpts().CPlusPlus11) { + Diag(DS.getStorageClassSpecLoc(), + getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class + : diag::warn_deprecated_register) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + } } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { SC = SC_Auto; @@ -11665,12 +11563,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { << DeclSpec::getSpecifierName(TSCS); if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (DS.isConstexprSpecified()) Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; - if (DS.isConceptSpecified()) - Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind); DiagnoseFunctionSpecifiers(DS); @@ -11704,7 +11600,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check for redeclaration of parameters, e.g. int foo(int x, int x); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); @@ -11873,13 +11769,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. - if (T.getAddressSpace() != 0) { - // OpenCL allows function arguments declared to be an array of a type - // to be qualified with an address space. - if (!(getLangOpts().OpenCL && T->isArrayType())) { - Diag(NameLoc, diag::err_arg_with_address_space); - New->setInvalidDecl(); - } + if (T.getAddressSpace() != LangAS::Default && + // OpenCL allows function arguments declared to be an array of a type + // to be qualified with an address space. + !(getLangOpts().OpenCL && + (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) { + Diag(NameLoc, diag::err_arg_with_address_space); + New->setInvalidDecl(); } return New; @@ -12346,18 +12242,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } } - // The only way to be included in UndefinedButUsed is if there is an - // ODR use before the definition. Avoid the expensive map lookup if this - // is the first declaration. - if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) { - if (!FD->isExternallyVisible()) - UndefinedButUsed.erase(FD); - else if (FD->isInlined() && - !LangOpts.GNUInline && - (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>())) - UndefinedButUsed.erase(FD); - } - // If the function implicitly returns zero (like 'main') or is naked, // don't complain about missing return statements. if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>()) @@ -12621,28 +12505,50 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { + Scope *BlockScope = S; + while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent()) + BlockScope = BlockScope->getParent(); + // Before we produce a declaration for an implicitly defined // function, see whether there was a locally-scoped declaration of // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. - if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) { - Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev; - Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); - return ExternCPrev; + NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II); + if (ExternCPrev) { + // We still need to inject the function into the enclosing block scope so + // that later (non-call) uses can see it. + PushOnScopeChains(ExternCPrev, BlockScope, /*AddToContext*/false); + + // C89 footnote 38: + // If in fact it is not defined as having type "function returning int", + // the behavior is undefined. + if (!isa<FunctionDecl>(ExternCPrev) || + !Context.typesAreCompatible( + cast<FunctionDecl>(ExternCPrev)->getType(), + Context.getFunctionNoProtoType(Context.IntTy))) { + Diag(Loc, diag::ext_use_out_of_scope_declaration) + << ExternCPrev << !getLangOpts().C99; + Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); + return ExternCPrev; + } } // Extension in C99. Legal in C90, but warn about it. + // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported. unsigned diag_id; if (II.getName().startswith("__builtin_")) diag_id = diag::warn_builtin_unknown; - // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported. - else if (getLangOpts().OpenCL) - diag_id = diag::err_opencl_implicit_function_decl; - else if (getLangOpts().C99) + else if (getLangOpts().C99 || getLangOpts().OpenCL) diag_id = diag::ext_implicit_function_decl; else diag_id = diag::warn_implicit_function_decl; - Diag(Loc, diag_id) << &II; + Diag(Loc, diag_id) << &II << getLangOpts().OpenCL; + + // If we found a prior declaration of this function, don't bother building + // another one. We've already pushed that one into scope, so there's nothing + // more to do. + if (ExternCPrev) + return ExternCPrev; // Because typo correction is expensive, only do it if the implicit // function declaration is going to be treated as an error. @@ -12694,16 +12600,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, SourceLocation()); D.SetIdentifier(&II, Loc); - // Insert this function into translation-unit scope. - - DeclContext *PrevDC = CurContext; - CurContext = Context.getTranslationUnitDecl(); - - FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D)); + // Insert this function into the enclosing block scope. + FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(BlockScope, D)); FD->setImplicit(); - CurContext = PrevDC; - AddKnownFunctionAttributes(FD); return FD; @@ -12752,15 +12652,33 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->getLocation())); } - // Mark const if we don't care about errno and that is the only - // thing preventing the function from being const. This allows - // IRgen to use LLVM intrinsics for such functions. - if (!getLangOpts().MathErrno && - Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { - if (!FD->hasAttr<ConstAttr>()) + // Mark const if we don't care about errno and that is the only thing + // preventing the function from being const. This allows IRgen to use LLVM + // intrinsics for such functions. + if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() && + Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) + FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); + + // We make "fma" on GNU or Windows const because we know it does not set + // errno in those environments even though it could set errno based on the + // C standard. + const llvm::Triple &Trip = Context.getTargetInfo().getTriple(); + if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) && + !FD->hasAttr<ConstAttr>()) { + switch (BuiltinID) { + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BIfma: + case Builtin::BIfmaf: + case Builtin::BIfmal: FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); + break; + default: + break; + } } - + if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->hasAttr<ReturnsTwiceAttr>()) FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, @@ -13260,7 +13178,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isStdBadAlloc = false; bool isStdAlignValT = false; - RedeclarationKind Redecl = ForRedeclaration; + RedeclarationKind Redecl = forRedeclarationInCurContext(); if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; @@ -13538,10 +13456,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // type declared by an elaborated-type-specifier. In C that is not correct // and we should instead merge compatible types found by lookup. if (getLangOpts().CPlusPlus) { - Previous.setRedeclarationKind(ForRedeclaration); + Previous.setRedeclarationKind(forRedeclarationInCurContext()); LookupQualifiedName(Previous, SearchDC); } else { - Previous.setRedeclarationKind(ForRedeclaration); + Previous.setRedeclarationKind(forRedeclarationInCurContext()); LookupName(Previous, S); } } @@ -13941,6 +13859,13 @@ CreateNewDecl: Invalid = true; } + if (!Invalid && getLangOpts().CPlusPlus && TUK == TUK_Definition && + DC->getDeclKind() == Decl::Enum) { + Diag(New->getLocation(), diag::err_type_defined_in_enum) + << Context.getTagDeclType(New); + Invalid = true; + } + // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { @@ -14032,6 +13957,9 @@ CreateNewDecl: if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); + if (PrevDecl) + CheckRedeclarationModuleOwnership(New, PrevDecl); + if (TUK == TUK_Definition) New->startDefinition(); @@ -14358,7 +14286,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, } // TR 18037 does not allow fields to be declared with address spaces. - if (T.getQualifiers().hasAddressSpace()) { + if (T.getQualifiers().hasAddressSpace() || + T->isDependentAddressSpaceType() || + T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) { Diag(Loc, diag::err_field_with_address_space); D.setInvalidType(); } @@ -14375,7 +14305,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) @@ -14383,7 +14313,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; - LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupResult Previous(*this, II, Loc, LookupMemberName, + ForVisibleRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: @@ -14771,7 +14702,7 @@ Decl *Sema::ActOnIvar(Scope *S, if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, - ForRedeclaration); + ForVisibleRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; @@ -14913,6 +14844,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // possibly recursively, a member that is such a structure) // shall not be a member of a structure or an element of an // array. + bool IsLastField = (i + 1 == Fields.end()); if (FDTy->isFunctionType()) { // Field declared as a function. Diag(FD->getLocation(), diag::err_field_declared_as_function) @@ -14920,60 +14852,70 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && Record && - ((i + 1 == Fields.end() && !Record->isUnion()) || - ((getLangOpts().MicrosoftExt || - getLangOpts().CPlusPlus) && - (i + 1 == Fields.end() || Record->isUnion())))) { - // Flexible array member. - // Microsoft and g++ is more permissive regarding flexible array. - // It will accept flexible array in union and also - // as the sole element of a struct/class. - unsigned DiagID = 0; - if (Record->isUnion()) - DiagID = getLangOpts().MicrosoftExt - ? diag::ext_flexible_array_union_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_union_gnu - : diag::err_flexible_array_union; - else if (NumNamedMembers < 1) - DiagID = getLangOpts().MicrosoftExt - ? diag::ext_flexible_array_empty_aggregate_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_empty_aggregate_gnu - : diag::err_flexible_array_empty_aggregate; + } else if (FDTy->isIncompleteArrayType() && + (Record || isa<ObjCContainerDecl>(EnclosingDecl))) { + if (Record) { + // Flexible array member. + // Microsoft and g++ is more permissive regarding flexible array. + // It will accept flexible array in union and also + // as the sole element of a struct/class. + unsigned DiagID = 0; + if (!Record->isUnion() && !IsLastField) { + Diag(FD->getLocation(), diag::err_flexible_array_not_at_end) + << FD->getDeclName() << FD->getType() << Record->getTagKind(); + Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } else if (Record->isUnion()) + DiagID = getLangOpts().MicrosoftExt + ? diag::ext_flexible_array_union_ms + : getLangOpts().CPlusPlus + ? diag::ext_flexible_array_union_gnu + : diag::err_flexible_array_union; + else if (NumNamedMembers < 1) + DiagID = getLangOpts().MicrosoftExt + ? diag::ext_flexible_array_empty_aggregate_ms + : getLangOpts().CPlusPlus + ? diag::ext_flexible_array_empty_aggregate_gnu + : diag::err_flexible_array_empty_aggregate; - if (DiagID) - Diag(FD->getLocation(), DiagID) << FD->getDeclName() - << Record->getTagKind(); - // While the layout of types that contain virtual bases is not specified - // by the C++ standard, both the Itanium and Microsoft C++ ABIs place - // virtual bases after the derived members. This would make a flexible - // array member declared at the end of an object not adjacent to the end - // of the type. - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) - if (RD->getNumVBases() != 0) - Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) + if (DiagID) + Diag(FD->getLocation(), DiagID) << FD->getDeclName() + << Record->getTagKind(); + // While the layout of types that contain virtual bases is not specified + // by the C++ standard, both the Itanium and Microsoft C++ ABIs place + // virtual bases after the derived members. This would make a flexible + // array member declared at the end of an object not adjacent to the end + // of the type. + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) + if (RD->getNumVBases() != 0) + Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) + << FD->getDeclName() << Record->getTagKind(); + if (!getLangOpts().C99) + Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) << FD->getDeclName() << Record->getTagKind(); - if (!getLangOpts().C99) - Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) - << FD->getDeclName() << Record->getTagKind(); - // If the element type has a non-trivial destructor, we would not - // implicitly destroy the elements, so disallow it for now. - // - // FIXME: GCC allows this. We should probably either implicitly delete - // the destructor of the containing class, or just allow this. - QualType BaseElem = Context.getBaseElementType(FD->getType()); - if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { - Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) - << FD->getDeclName() << FD->getType(); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; + // If the element type has a non-trivial destructor, we would not + // implicitly destroy the elements, so disallow it for now. + // + // FIXME: GCC allows this. We should probably either implicitly delete + // the destructor of the containing class, or just allow this. + QualType BaseElem = Context.getBaseElementType(FD->getType()); + if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { + Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) + << FD->getDeclName() << FD->getType(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. + Record->setHasFlexibleArrayMember(true); + } else { + // In ObjCContainerDecl ivars with incomplete array type are accepted, + // unless they are followed by another ivar. That check is done + // elsewhere, after synthesized ivars are known. } - // Okay, we have a legal flexible array member at the end of the struct. - Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { @@ -14990,7 +14932,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. - if (i + 1 != Fields.end()) + if (!IsLastField) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { @@ -15137,8 +15079,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) { auto *Dtor = CXXRecord->getDestructor(); if (Dtor && Dtor->isImplicit() && - ShouldDeleteSpecialMember(Dtor, CXXDestructor)) + ShouldDeleteSpecialMember(Dtor, CXXDestructor)) { + CXXRecord->setImplicitDestructorIsDeleted(); SetDeclDeleted(Dtor, CXXRecord->getLocation()); + } } if (Record->hasAttrs()) { @@ -15271,7 +15215,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, QualType T) { - assert(T->isIntegralType(Context) && "Integral type required!"); + assert((T->isIntegralType(Context) || T->isEnumeralType()) && + "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) { @@ -15287,7 +15232,8 @@ static bool isRepresentableIntegerValue(ASTContext &Context, static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { // FIXME: Int128/UInt128 support, which also needs to be introduced into // enum checking below. - assert(T->isIntegralType(Context) && "Integral type required!"); + assert((T->isIntegralType(Context) || + T->isEnumeralType()) && "Integral type required!"); const unsigned NumTypes = 4; QualType SignedIntegralTypes[NumTypes] = { Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy @@ -15326,7 +15272,6 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { - SourceLocation ExpLoc; if (getLangOpts().CPlusPlus11 && Enum->isFixed() && !getLangOpts().MSVCCompat) { // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the @@ -15491,7 +15436,7 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, // determine if we should merge the definition with an existing one and // skip the body. NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl); if (!PrevECD) return SkipBodyInfo(); @@ -15522,7 +15467,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // Verify that there isn't already something declared with this name in this // scope. NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -15549,8 +15494,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // enum constant will 'hide' the tag. assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) && "Received TagDecl when not in C++!"); - if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) && - shouldLinkPossiblyHiddenDecl(PrevDecl, New)) { + if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) { if (isa<EnumConstantDecl>(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else @@ -16043,7 +15987,7 @@ static void checkModuleImportContext(Sema &S, Module *M, DC = LSD->getParent(); } - while (isa<LinkageSpecDecl>(DC)) + while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC)) DC = DC->getParent(); if (!isa<TranslationUnitDecl>(DC)) { @@ -16064,6 +16008,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path) { + assert(getLangOpts().ModulesTS && + "should only have module decl in modules TS"); + // A module implementation unit requires that we are not compiling a module // of any kind. A module interface unit requires that we are not compiling a // module map. @@ -16080,6 +16027,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, // implementation unit. That indicates the 'export' is missing. Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) << FixItHint::CreateInsertion(ModuleLoc, "export "); + MDK = ModuleDeclKind::Interface; break; case LangOptions::CMK_ModuleMap: @@ -16087,9 +16035,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, return nullptr; } + assert(ModuleScopes.size() == 1 && "expected to be at global module scope"); + // FIXME: Most of this work should be done by the preprocessor rather than // here, in order to support macro import. + // Only one module-declaration is permitted per source file. + if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) { + Diag(ModuleLoc, diag::err_module_redeclaration); + Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), + diag::note_prev_module_declaration); + return nullptr; + } + // Flatten the dots in a module name. Unlike Clang's hierarchical module map // modules, the dots here are just another character that can appear in a // module name. @@ -16100,8 +16058,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, ModuleName += Piece.first->getName(); } - // FIXME: If we've already seen a module-declaration, report an error. - // If a module name was explicitly specified on the command line, it must be // correct. if (!getLangOpts().CurrentModule.empty() && @@ -16117,9 +16073,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, Module *Mod; switch (MDK) { - case ModuleDeclKind::Module: { - // FIXME: Check we're not in a submodule. - + case ModuleDeclKind::Interface: { // We can't have parsed or imported a definition of this module or parsed a // module map defining it already. if (auto *M = Map.findModule(ModuleName)) { @@ -16129,11 +16083,13 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, else if (const auto *FE = M->getASTFile()) Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) << FE->getName(); - return nullptr; + Mod = M; + break; } // Create a Module for the module that we're defining. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, + ModuleScopes.front().Module); assert(Mod && "module creation should not fail"); break; } @@ -16147,21 +16103,26 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, PP.getIdentifierInfo(ModuleName), Path[0].second); Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); - if (!Mod) - return nullptr; + if (!Mod) { + Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; + // Create an empty module interface unit for error recovery. + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, + ModuleScopes.front().Module); + } break; } - // Enter the semantic scope of the module. - ModuleScopes.push_back({}); + // Switch from the global module to the named module. ModuleScopes.back().Module = Mod; - ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation; VisibleModules.setVisible(Mod, ModuleLoc); // From now on, we have an owning module for all declarations we see. // However, those declarations are module-private unless explicitly // exported. - Context.getTranslationUnitDecl()->setLocalOwningModule(Mod); + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + TU->setLocalOwningModule(Mod); // FIXME: Create a ModuleDecl. return nullptr; @@ -16204,12 +16165,17 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, IdentifierLocs.push_back(Path[I].second); } - TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); - ImportDecl *Import = ImportDecl::Create(Context, TU, StartLoc, + ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc, Mod, IdentifierLocs); if (!ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, Import); - TU->addDecl(Import); + CurContext->addDecl(Import); + + // Re-export the module if needed. + if (Import->isExported() && + !ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) + getCurrentModule()->Exports.emplace_back(Mod, false); + return Import; } @@ -16339,8 +16305,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // C++ Modules TS draft: // An export-declaration shall appear in the purview of a module other than // the global module. - if (ModuleScopes.empty() || !ModuleScopes.back().Module || - ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) + if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface) Diag(ExportLoc, diag::err_export_not_in_module_interface); // An export-declaration [...] shall not contain more than one diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 2a310bf41c703..676d00357c960 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -540,14 +540,13 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { // a DeclRefExpr is found, its type should be checked to determine whether it // is a capability or not. - if (const auto *E = dyn_cast<DeclRefExpr>(Ex)) - return typeHasCapability(S, E->getType()); - else if (const auto *E = dyn_cast<CastExpr>(Ex)) + if (const auto *E = dyn_cast<CastExpr>(Ex)) return isCapabilityExpr(S, E->getSubExpr()); else if (const auto *E = dyn_cast<ParenExpr>(Ex)) return isCapabilityExpr(S, E->getSubExpr()); else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) { - if (E->getOpcode() == UO_LNot) + if (E->getOpcode() == UO_LNot || E->getOpcode() == UO_AddrOf || + E->getOpcode() == UO_Deref) return isCapabilityExpr(S, E->getSubExpr()); return false; } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) { @@ -557,7 +556,7 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { return false; } - return false; + return typeHasCapability(S, Ex->getType()); } /// \brief Checks that all attribute arguments, starting from Sidx, resolve to @@ -1304,14 +1303,28 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { - // Report warning about changed offset in the newer compiler versions. - if (!FD->getType()->isDependentType() && - !FD->getType()->isIncompleteType() && FD->isBitField() && - S.Context.getTypeAlign(FD->getType()) <= 8) - S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + bool BitfieldByteAligned = (!FD->getType()->isDependentType() && + !FD->getType()->isIncompleteType() && + FD->isBitField() && + S.Context.getTypeAlign(FD->getType()) <= 8); + + if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { + if (BitfieldByteAligned) + // The PS4 target needs to maintain ABI backwards compatibility. + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) + << Attr.getName() << FD->getType(); + else + FD->addAttr(::new (S.Context) PackedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + } else { + // Report warning about changed offset in the newer compiler versions. + if (BitfieldByteAligned) + S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + + FD->addAttr(::new (S.Context) PackedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + } - FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -1517,6 +1530,22 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (D->isInvalidDecl()) + return; + + // noescape only applies to pointer types. + QualType T = cast<ParmVarDecl>(D)->getType(); + if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) + << Attr.getName() << Attr.getRange() << 0; + return; + } + + D->addAttr(::new (S.Context) NoEscapeAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleAssumeAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Expr *E = Attr.getArgAsExpr(0), @@ -1939,20 +1968,20 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { +static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(attr)) + if (S.CheckNoReturnAttr(Attrs)) return; if (!isa<ObjCMethodDecl>(D)) { - S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedFunctionOrMethod; + S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attrs.getName() << ExpectedFunctionOrMethod; return; } D->addAttr(::new (S.Context) NoReturnAttr( - attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); + Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, @@ -1964,9 +1993,9 @@ static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } -bool Sema::CheckNoReturnAttr(const AttributeList &attr) { - if (!checkAttributeNumArgs(*this, attr, 0)) { - attr.setInvalid(); +bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { + if (!checkAttributeNumArgs(*this, Attrs, 0)) { + Attrs.setInvalid(); return true; } @@ -2122,10 +2151,10 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName(); + bool IsCXX17Attr = Attr.isCXX11Attribute() && !Attr.getScopeName(); - if (IsCXX1zAttr && isa<VarDecl>(D)) { - // The C++1z spelling of this attribute cannot be applied to a static data + if (IsCXX17Attr && isa<VarDecl>(D)) { + // The C++17 spelling of this attribute cannot be applied to a static data // member per [dcl.attr.unused]p2. if (cast<VarDecl>(D)->isStaticDataMember()) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -2134,10 +2163,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } - // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr) - S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) + S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); D->addAttr(::new (S.Context) UnusedAttr( Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -2831,11 +2860,11 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) return; } - // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() && + if (!S.getLangOpts().CPlusPlus17 && Attr.isCXX11Attribute() && !Attr.getScopeName()) - S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context, @@ -2993,22 +3022,43 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(NewAttr); } -// Check for things we'd like to warn about, no errors or validation for now. -// TODO: Validation should use a backend target library that specifies -// the allowable subtarget features and cpus. We could use something like a -// TargetCodeGenInfo hook here to do validation. -void Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { +// Check for things we'd like to warn about. Multiversioning issues are +// handled later in the process, once we know how many exist. +bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { + enum FirstParam { Unsupported, Duplicate }; + enum SecondParam { None, Architecture }; for (auto Str : {"tune=", "fpmath="}) if (AttrStr.find(Str) != StringRef::npos) - Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Str; + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str; + + TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); + + if (!ParsedAttrs.Architecture.empty() && + !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << Architecture << ParsedAttrs.Architecture; + + if (ParsedAttrs.DuplicateArchitecture) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Duplicate << None << "arch="; + + for (const auto &Feature : ParsedAttrs.Features) { + auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. + if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature; + } + + return true; } static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) || + !S.checkTargetAttr(LiteralLoc, Str)) return; - S.checkTargetAttr(LiteralLoc, Str); unsigned Index = Attr.getAttributeSpellingListIndex(); TargetAttr *NewAttr = ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index); @@ -3016,12 +3066,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - VarDecl *VD = cast<VarDecl>(D); - if (!VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - Expr *E = Attr.getArgAsExpr(0); SourceLocation Loc = E->getExprLoc(); FunctionDecl *FD = nullptr; @@ -3064,7 +3108,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { // We're currently more strict than GCC about what function types we accept. // If this ever proves to be a problem it should be easy to fix. - QualType Ty = S.Context.getPointerType(VD->getType()); + QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), ParamTy, Ty) != Sema::Compatible) { @@ -4252,24 +4296,24 @@ static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); } -bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, +bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, const FunctionDecl *FD) { - if (attr.isInvalid()) + if (Attrs.isInvalid()) return true; - if (attr.hasProcessingCache()) { - CC = (CallingConv) attr.getProcessingCache(); + if (Attrs.hasProcessingCache()) { + CC = (CallingConv) Attrs.getProcessingCache(); return false; } - unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0; - if (!checkAttributeNumArgs(*this, attr, ReqArgs)) { - attr.setInvalid(); + unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0; + if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) { + Attrs.setInvalid(); return true; } // TODO: diagnose uses of these conventions on the wrong target. - switch (attr.getKind()) { + switch (Attrs.getKind()) { case AttributeList::AT_CDecl: CC = CC_C; break; case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; @@ -4288,8 +4332,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, break; case AttributeList::AT_Pcs: { StringRef StrRef; - if (!checkStringLiteralArgumentAttr(attr, 0, StrRef)) { - attr.setInvalid(); + if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) { + Attrs.setInvalid(); return true; } if (StrRef == "aapcs") { @@ -4300,8 +4344,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, break; } - attr.setInvalid(); - Diag(attr.getLoc(), diag::err_invalid_pcs); + Attrs.setInvalid(); + Diag(Attrs.getLoc(), diag::err_invalid_pcs); return true; } case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; @@ -4314,7 +4358,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); if (A != TargetInfo::CCCR_OK) { if (A == TargetInfo::CCCR_Warning) - Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName(); + Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs.getName(); // This convention is not valid for the target. Use the default function or // method calling convention. @@ -4326,7 +4370,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod); } - attr.setProcessingCache((unsigned) CC); + Attrs.setProcessingCache((unsigned) CC); return false; } @@ -4334,7 +4378,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, static bool isValidSwiftContextType(QualType type) { if (!type->hasPointerRepresentation()) return type->isDependentType(); - return type->getPointeeType().getAddressSpace() == 0; + return type->getPointeeType().getAddressSpace() == LangAS::Default; } /// Pointers and references in the default address space. @@ -4346,7 +4390,7 @@ static bool isValidSwiftIndirectResultType(QualType type) { } else { return type->isDependentType(); } - return type.getAddressSpace() == 0; + return type.getAddressSpace() == LangAS::Default; } /// Pointers and references to pointers in the default address space. @@ -4363,10 +4407,10 @@ static bool isValidSwiftErrorResultType(QualType type) { return isValidSwiftContextType(type); } -static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr, - ParameterABI abi) { - S.AddParameterABIAttr(attr.getRange(), D, abi, - attr.getAttributeSpellingListIndex()); +static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs, + ParameterABI Abi) { + S.AddParameterABIAttr(Attrs.getRange(), D, Abi, + Attrs.getAttributeSpellingListIndex()); } void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, @@ -4807,11 +4851,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, } static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, - const AttributeList &attr) { + const AttributeList &Attrs) { const int EP_ObjCMethod = 1; const int EP_ObjCProperty = 2; - SourceLocation loc = attr.getLoc(); + SourceLocation loc = Attrs.getLoc(); QualType resultType; if (isa<ObjCMethodDecl>(D)) resultType = cast<ObjCMethodDecl>(D)->getReturnType(); @@ -4822,7 +4866,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, (!resultType->isPointerType() || resultType->isObjCRetainableType())) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) << SourceRange(loc) - << attr.getName() + << Attrs.getName() << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty) << /*non-retainable pointer*/ 2; @@ -4831,29 +4875,29 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr( - attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); + Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, - const AttributeList &attr) { + const AttributeList &Attrs) { ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); DeclContext *DC = method->getDeclContext(); if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << attr.getName() << 0; + << Attrs.getName() << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } if (method->getMethodFamily() == OMF_dealloc) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << attr.getName() << 1; + << Attrs.getName() << 1; return; } method->addAttr(::new (S.Context) - ObjCRequiresSuperAttr(attr.getRange(), S.Context, - attr.getAttributeSpellingListIndex())); + ObjCRequiresSuperAttr(Attrs.getRange(), S.Context, + Attrs.getAttributeSpellingListIndex())); } static void handleCFAuditedTransferAttr(Sema &S, Decl *D, @@ -5665,8 +5709,12 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleAssertCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { + SmallVector<Expr*, 1> Args; + if (!checkLockFunAttrCommon(S, D, Attr, Args)) + return; + D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, - Attr.getArgAsExpr(0), + Args.data(), Args.size(), Attr.getAttributeSpellingListIndex())); } @@ -5965,6 +6013,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoMicroMips: handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr); break; + case AttributeList::AT_MipsLongCall: + handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>( + S, D, Attr); + break; + case AttributeList::AT_MipsShortCall: + handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>( + S, D, Attr); + break; case AttributeList::AT_AMDGPUFlatWorkGroupSize: handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr); break; @@ -6120,6 +6176,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReturnsNonNull: handleReturnsNonNullAttr(S, D, Attr); break; + case AttributeList::AT_NoEscape: + handleNoEscapeAttr(S, D, Attr); + break; case AttributeList::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, Attr); break; @@ -7003,6 +7062,49 @@ static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { return dyn_cast<NamedDecl>(OrigCtx); } +namespace { + +struct AttributeInsertion { + StringRef Prefix; + SourceLocation Loc; + StringRef Suffix; + + static AttributeInsertion createInsertionAfter(const NamedDecl *D) { + return {" ", D->getLocEnd(), ""}; + } + static AttributeInsertion createInsertionAfter(SourceLocation Loc) { + return {" ", Loc, ""}; + } + static AttributeInsertion createInsertionBefore(const NamedDecl *D) { + return {"", D->getLocStart(), "\n"}; + } +}; + +} // end anonymous namespace + +/// Returns a source location in which it's appropriate to insert a new +/// attribute for the given declaration \D. +static Optional<AttributeInsertion> +createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, + const LangOptions &LangOpts) { + if (isa<ObjCPropertyDecl>(D)) + return AttributeInsertion::createInsertionAfter(D); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->hasBody()) + return None; + return AttributeInsertion::createInsertionAfter(D); + } + if (const auto *TD = dyn_cast<TagDecl>(D)) { + SourceLocation Loc = + Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); + if (Loc.isInvalid()) + return None; + // Insert after the 'struct'/whatever keyword. + return AttributeInsertion::createInsertionAfter(Loc); + } + return AttributeInsertion::createInsertionBefore(D); +} + /// Actually emit an availability diagnostic for a reference to an unavailable /// decl. /// @@ -7038,7 +7140,83 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + // The declaration can have multiple availability attributes, we are looking + // at one of them. + const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); + if (A && A->isInherited()) { + for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; + Redecl = Redecl->getPreviousDecl()) { + const AvailabilityAttr *AForRedecl = + getAttrForPlatform(S.Context, Redecl); + if (AForRedecl && !AForRedecl->isInherited()) { + // If D is a declaration with inherited attributes, the note should + // point to the declaration with actual attributes. + NoteLocation = Redecl->getLocation(); + break; + } + } + } + switch (K) { + case AR_NotYetIntroduced: { + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + const AvailabilityAttr *AA = + getAttrForPlatform(S.getASTContext(), OffendingDecl); + VersionTuple Introduced = AA->getIntroduced(); + + bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( + S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), + Introduced); + unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + S.Diag(Loc, Warning) + << OffendingDecl + << AvailabilityAttr::getPrettyPlatformName( + S.getASTContext().getTargetInfo().getPlatformName()) + << Introduced.getAsString(); + + S.Diag(OffendingDecl->getLocation(), diag::note_availability_specified_here) + << OffendingDecl << /* partial */ 3; + + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { + if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (TD->getDeclName().isEmpty()) { + S.Diag(TD->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Anonymous*/ 1 << TD->getKindName(); + return; + } + auto FixitNoteDiag = + S.Diag(Enclosing->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Named*/ 0 << Enclosing; + // Don't offer a fixit for declarations with availability attributes. + if (Enclosing->hasAttr<AvailabilityAttr>()) + return; + if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) + return; + Optional<AttributeInsertion> Insertion = createAttributeInsertion( + Enclosing, S.getSourceManager(), S.getLangOpts()); + if (!Insertion) + return; + std::string PlatformName = + AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()) + .lower(); + std::string Introduced = + OffendingDecl->getVersionIntroduced().getAsString(); + FixitNoteDiag << FixItHint::CreateInsertion( + Insertion->Loc, + (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + + "(" + Introduced + "))" + Insertion->Suffix) + .str()); + } + return; + } case AR_Deprecated: diag = !ObjCPropertyAccess ? diag::warn_deprecated : diag::warn_property_method_deprecated; @@ -7046,8 +7224,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>()) - NoteLocation = attr->getLocation(); + if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>()) + NoteLocation = Attr->getLocation(); break; case AR_Unavailable: @@ -7058,8 +7236,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) { - if (attr->isImplicit() && attr->getImplicitReason()) { + if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) { + if (Attr->isImplicit() && Attr->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { @@ -7069,7 +7247,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag = diag::err_unavailable_in_arc; }; - switch (attr->getImplicitReason()) { + switch (Attr->getImplicitReason()) { case UnavailableAttr::IR_None: break; case UnavailableAttr::IR_ARCForbiddenType: @@ -7103,28 +7281,6 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } break; - case AR_NotYetIntroduced: { - // We would like to emit the diagnostic even if -Wunguarded-availability is - // not specified for deployment targets >= to iOS 11 or equivalent or - // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or - // later. - const AvailabilityAttr *AA = - getAttrForPlatform(S.getASTContext(), OffendingDecl); - VersionTuple Introduced = AA->getIntroduced(); - bool NewWarning = shouldDiagnoseAvailabilityByDefault( - S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), - Introduced); - diag = NewWarning ? diag::warn_partial_availability_new - : diag::warn_partial_availability; - diag_message = NewWarning ? diag::warn_partial_message_new - : diag::warn_partial_message; - diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new - : diag::warn_partial_fwdclass_message; - property_note_select = /* partial */ 2; - available_here_select_kind = /* partial */ 3; - break; - } - case AR_Available: llvm_unreachable("Warning for availability of available declaration?"); } @@ -7132,10 +7288,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, CharSourceRange UseRange; StringRef Replacement; if (K == AR_Deprecated) { - if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>()) - Replacement = attr->getReplacement(); - if (auto attr = getAttrForPlatform(S.Context, OffendingDecl)) - Replacement = attr->getReplacement(); + if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>()) + Replacement = Attr->getReplacement(); + if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl)) + Replacement = Attr->getReplacement(); if (!Replacement.empty()) UseRange = @@ -7163,38 +7319,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - // The declaration can have multiple availability attributes, we are looking - // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); - if (A && A->isInherited()) { - for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; - Redecl = Redecl->getPreviousDecl()) { - const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, - Redecl); - if (AForRedecl && !AForRedecl->isInherited()) { - // If D is a declaration with inherited attributes, the note should - // point to the declaration with actual attributes. - S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl - << available_here_select_kind; - break; - } - } - } - else - S.Diag(NoteLocation, diag_available_here) - << OffendingDecl << available_here_select_kind; - - if (K == AR_NotYetIntroduced) - if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (auto *TD = dyn_cast<TagDecl>(Enclosing)) - if (TD->getDeclName().isEmpty()) { - S.Diag(TD->getLocation(), diag::note_partial_availability_silence) - << /*Anonymous*/1 << TD->getKindName(); - return; - } - S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence) - << /*Named*/0 << Enclosing; - } + S.Diag(NoteLocation, diag_available_here) + << OffendingDecl << available_here_select_kind; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, @@ -7399,6 +7525,10 @@ public: bool TraverseLambdaExpr(LambdaExpr *E) { return true; } + // for 'case X:' statements, don't bother looking at the 'X'; it can't lead + // to any useful diagnostics. + bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); } + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { if (PRE->isClassReceiver()) DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation()); @@ -7581,8 +7711,7 @@ bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) { // If we're using the '*' case here or if this check is redundant, then we // use the enclosing version to check both branches. if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) - return Base::TraverseStmt(If->getThen()) && - Base::TraverseStmt(If->getElse()); + return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse()); } else { // This isn't an availability checking 'if', we can just continue. return Base::TraverseIfStmt(If); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 48f698cfe71e3..96472a0a70fe7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -143,7 +143,7 @@ namespace { if (Lambda->capture_begin() == Lambda->capture_end()) return false; - return S->Diag(Lambda->getLocStart(), + return S->Diag(Lambda->getLocStart(), diag::err_lambda_capture_default_arg); } } @@ -167,6 +167,9 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, if (ComputedEST == EST_None) return; + if (EST == EST_None && Method->hasAttr<NoThrowAttr>()) + EST = EST_BasicNoexcept; + switch(EST) { // If this function can throw any exceptions, make a note of that. case EST_MSAny: @@ -276,18 +279,18 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); - // We have already instantiated this parameter; provide each of the + // We have already instantiated this parameter; provide each of the // instantiations with the uninstantiated default argument. UnparsedDefaultArgInstantiationsMap::iterator InstPos = UnparsedDefaultArgInstantiations.find(Param); if (InstPos != UnparsedDefaultArgInstantiations.end()) { for (unsigned I = 0, N = InstPos->second.size(); I != N; ++I) InstPos->second[I]->setUninstantiatedDefaultArg(Arg); - + // We're done tracking this parameter's instantiations. UnparsedDefaultArgInstantiations.erase(InstPos); } - + return false; } @@ -524,8 +527,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = false; } } - - // FIXME: If we knew where the '=' was, we could easily provide a fix-it + + // FIXME: If we knew where the '=' was, we could easily provide a fix-it // hint here. Alternatively, we could walk the type-source information // for NewParam to find the last source location in the type... but it // isn't worth the effort right now. This is the kind of test case that @@ -535,7 +538,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // void g(int (*fp)(int) = &f); Diag(NewParam->getLocation(), DiagDefaultParamID) << NewParam->getDefaultArgRange(); - + // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. for (auto Older = PrevForDefaultArgs; @@ -581,9 +584,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // or a definition for one of the following explicit specializations: // - the explicit specialization of a function template; // - the explicit specialization of a member function template; - // - the explicit specialization of a member function of a class + // - the explicit specialization of a member function of a class // template where the class template specialization to which the - // member function specialization belongs is implicitly + // member function specialization belongs is implicitly // instantiated. Diag(NewParam->getLocation(), diag::err_template_spec_default_arg) << (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization) @@ -591,16 +594,16 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, << NewParam->getDefaultArgRange(); } else if (New->getDeclContext()->isDependentContext()) { // C++ [dcl.fct.default]p6 (DR217): - // Default arguments for a member function of a class template shall - // be specified on the initial declaration of the member function + // Default arguments for a member function of a class template shall + // be specified on the initial declaration of the member function // within the class template. // - // Reading the tea leaves a bit in DR217 and its reference to DR205 - // leads me to the conclusion that one cannot add default function - // arguments for an out-of-line definition of a member function of a + // Reading the tea leaves a bit in DR217 and its reference to DR205 + // leads me to the conclusion that one cannot add default function + // arguments for an out-of-line definition of a member function of a // dependent type. int WhichKind = 2; - if (CXXRecordDecl *Record + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(New->getDeclContext())) { if (Record->getDescribedClassTemplate()) WhichKind = 0; @@ -609,8 +612,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, else WhichKind = 2; } - - Diag(NewParam->getLocation(), + + Diag(NewParam->getLocation(), diag::err_param_default_argument_member_template_redecl) << WhichKind << NewParam->getDefaultArgRange(); @@ -689,8 +692,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, assert(D.isDecompositionDeclarator()); const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); - // The syntax only allows a decomposition declarator as a simple-declaration - // or a for-range-declaration, but we parse it in more cases than that. + // The syntax only allows a decomposition declarator as a simple-declaration, + // a for-range-declaration, or a condition in Clang, but we parse it in more + // cases than that. if (!D.mayHaveDecompositionDeclarator()) { Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) << Decomp.getSourceRange(); @@ -705,9 +709,12 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, return nullptr; } - Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z - ? diag::warn_cxx14_compat_decomp_decl - : diag::ext_decomp_decl) + Diag(Decomp.getLSquareLoc(), + !getLangOpts().CPlusPlus17 + ? diag::ext_decomp_decl + : D.getContext() == Declarator::ConditionContext + ? diag::ext_decomp_decl_cond + : diag::warn_cxx14_compat_decomp_decl) << Decomp.getSourceRange(); // The semantic context is always just the current context. @@ -787,7 +794,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // Check for name conflicts. DeclarationNameInfo NameInfo(B.Name, B.NameLoc); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(Previous, S, /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit()); @@ -819,7 +826,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // is unnamed. DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr, Decomp.getLSquareLoc()); - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); // Build the variable that holds the non-decomposed object. bool AddToScope = true; @@ -2151,7 +2159,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, return nullptr; } - if (EllipsisLoc.isValid() && + if (EllipsisLoc.isValid() && !TInfo->getType()->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << TInfo->getTypeLoc().getSourceRange(); @@ -2300,10 +2308,10 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, GetTypeFromParser(basetype, &TInfo); if (EllipsisLoc.isInvalid() && - DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, + DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, UPPC_BaseType)) return true; - + if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, TInfo, EllipsisLoc)) @@ -2387,11 +2395,11 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, // Note this base's direct & indirect bases, if there could be ambiguity. if (Bases.size() > 1) NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); - + if (const RecordType *Record = NewBaseType->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); if (Class->isInterface() && - (!RD->isInterface() || + (!RD->isInterfaceLike() || KnownBase->getAccessSpecifier() != AS_public)) { // The Microsoft extension __interface does not permit bases that // are not themselves public interfaces. @@ -2408,7 +2416,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, // Attach the remaining base class specifiers to the derived class. Class->setBases(Bases.data(), NumGoodBases); - + for (unsigned idx = 0; idx < NumGoodBases; ++idx) { // Check whether this direct base is inaccessible due to ambiguity. QualType BaseType = Bases[idx]->getType(); @@ -2460,7 +2468,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) { CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl(); if (!DerivedRD) return false; - + CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl(); if (!BaseRD) return false; @@ -2474,7 +2482,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) { // to be able to use the inheritance relationship? if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined()) return false; - + return DerivedRD->isDerivedFrom(BaseRD); } @@ -2484,28 +2492,23 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths) { if (!getLangOpts().CPlusPlus) return false; - + CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl(); if (!DerivedRD) return false; - + CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl(); if (!BaseRD) return false; - + if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined()) return false; - + return DerivedRD->isDerivedFrom(BaseRD, Paths); } -void Sema::BuildBasePathArray(const CXXBasePaths &Paths, - CXXCastPath &BasePathArray) { - assert(BasePathArray.empty() && "Base path array must be empty!"); - assert(Paths.isRecordingPaths() && "Must record paths!"); - - const CXXBasePath &Path = Paths.front(); - +static void BuildBasePathArray(const CXXBasePath &Path, + CXXCastPath &BasePathArray) { // We first go backward and check if we have a virtual base. // FIXME: It would be better if CXXBasePath had the base specifier for // the nearest virtual base. @@ -2522,6 +2525,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, BasePathArray.push_back(const_cast<CXXBaseSpecifier*>(Path[I].Base)); } + +void Sema::BuildBasePathArray(const CXXBasePaths &Paths, + CXXCastPath &BasePathArray) { + assert(BasePathArray.empty() && "Base path array must be empty!"); + assert(Paths.isRecordingPaths() && "Must record paths!"); + return ::BuildBasePathArray(Paths.front(), BasePathArray); +} /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -2549,30 +2559,48 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths); - assert(DerivationOkay && - "Can only be used with a derived-to-base conversion"); - (void)DerivationOkay; - - if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { + if (!DerivationOkay) + return true; + + const CXXBasePath *Path = nullptr; + if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) + Path = &Paths.front(); + + // For MSVC compatibility, check if Derived directly inherits from Base. Clang + // warns about this hierarchy under -Winaccessible-base, but MSVC allows the + // user to access such bases. + if (!Path && getLangOpts().MSVCCompat) { + for (const CXXBasePath &PossiblePath : Paths) { + if (PossiblePath.size() == 1) { + Path = &PossiblePath; + if (AmbigiousBaseConvID) + Diag(Loc, diag::ext_ms_ambiguous_direct_base) + << Base << Derived << Range; + break; + } + } + } + + if (Path) { if (!IgnoreAccess) { // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), - InaccessibleBaseID)) { - case AR_inaccessible: - return true; - case AR_accessible: - case AR_dependent: - case AR_delayed: - break; + switch ( + CheckBaseClassAccess(Loc, Base, Derived, *Path, InaccessibleBaseID)) { + case AR_inaccessible: + return true; + case AR_accessible: + case AR_dependent: + case AR_delayed: + break; } } - + // Build a base path if necessary. if (BasePath) - BuildBasePathArray(Paths, *BasePath); + ::BuildBasePathArray(*Path, *BasePath); return false; } - + if (AmbigiousBaseConvID) { // We know that the derived-to-base conversion is ambiguous, and // we're going to produce a diagnostic. Perform the derived-to-base @@ -2637,7 +2665,7 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { PathDisplayStr += " -> " + Element->Base->getType().getAsString(); } } - + return PathDisplayStr; } @@ -2720,8 +2748,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { // If a function is marked with the virt-specifier override and // does not override a member function of a base class, the program is // ill-formed. - bool HasOverriddenMethods = - MD->begin_overridden_methods() != MD->end_overridden_methods(); + bool HasOverriddenMethods = MD->size_overridden_methods() != 0; if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding) << MD->getDeclName(); @@ -2860,6 +2887,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(!DS.isFriendSpecified()); bool isFunc = D.isDeclarationOfFunction(); + AttributeList *MSPropertyAttr = + getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); if (cast<CXXRecordDecl>(CurContext)->isInterface()) { // The Microsoft extension __interface only permits public member functions @@ -2867,8 +2896,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // functions, static methods and data members. unsigned InvalidDecl; bool ShowDeclName = true; - if (!isFunc) - InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1; + if (!isFunc && + (DS.getStorageClassSpec() == DeclSpec::SCS_typedef || MSPropertyAttr)) + InvalidDecl = 0; + else if (!isFunc) + InvalidDecl = 1; else if (AS != AS_public) InvalidDecl = 2; else if (DS.getStorageClassSpec() == DeclSpec::SCS_static) @@ -3016,12 +3048,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); - + SS.clear(); } - AttributeList *MSPropertyAttr = - getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); if (MSPropertyAttr) { Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, InitStyle, AS, MSPropertyAttr); @@ -3390,14 +3420,9 @@ namespace { void VisitCallExpr(CallExpr *E) { // Treat std::move as a use. - if (E->getNumArgs() == 1) { - if (FunctionDecl *FD = E->getDirectCallee()) { - if (FD->isInStdNamespace() && FD->getIdentifier() && - FD->getIdentifier()->isStr("move")) { - HandleValue(E->getArg(0), false /*AddressOf*/); - return; - } - } + if (E->isCallToStdMove()) { + HandleValue(E->getArg(0), /*AddressOf=*/false); + return; } Inherited::VisitCallExpr(E); @@ -3585,7 +3610,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, /// \brief Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. -static bool FindBaseInitializer(Sema &SemaRef, +static bool FindBaseInitializer(Sema &SemaRef, CXXRecordDecl *ClassDecl, QualType BaseType, const CXXBaseSpecifier *&DirectBaseSpec, @@ -3769,7 +3794,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (SS.isSet() && isDependentScopeSpecifier(SS)) { bool NotUnknownSpecialization = false; DeclContext *DC = computeDeclContext(SS, false); - if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC)) + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC)) NotUnknownSpecialization = !Record->hasAnyDependentBases(); if (!NotUnknownSpecialization) { @@ -3813,7 +3838,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) { const CXXBaseSpecifier *DirectBaseSpec; const CXXBaseSpecifier *VirtualBaseSpec; - if (FindBaseInitializer(*this, ClassDecl, + if (FindBaseInitializer(*this, ClassDecl, Context.getTypeDeclType(Type), DirectBaseSpec, VirtualBaseSpec)) { // We have found a direct or virtual base class with a @@ -4038,7 +4063,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, if (CurContext->isDependentContext()) DelegationInit = Init; - return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), + return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.getAs<Expr>(), InitRange.getEnd()); } @@ -4083,12 +4108,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = nullptr; const CXXBaseSpecifier *VirtualBaseSpec = nullptr; - if (!Dependent) { + if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); - FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); // C++ [base.class.init]p2: @@ -4208,7 +4233,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, IsInheritedVirtualBase); ExprResult BaseInit; - + switch (ImplicitInitKind) { case IIK_Inherit: case IIK_Default: { @@ -4225,7 +4250,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); - Expr *CopyCtorArg = + Expr *CopyCtorArg = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), Param, false, Constructor->getLocation(), ParamType, @@ -4234,8 +4259,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg)); // Cast to the base class to avoid ambiguities. - QualType ArgTy = - SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), + QualType ArgTy = + SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), ParamType.getQualifiers()); if (Moving) { @@ -4261,10 +4286,10 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit); if (BaseInit.isInvalid()) return true; - + CXXBaseInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, - SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), + SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), SourceLocation()), BaseSpec->isVirtual(), SourceLocation(), @@ -4298,8 +4323,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, // Suppress copying zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0) return false; - - Expr *MemberExprBase = + + Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), Param, false, Loc, ParamType, VK_LValue, nullptr); @@ -4317,7 +4342,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect) : cast<ValueDecl>(Field), AS_public); MemberLookup.resolveKind(); - ExprResult CtorArg + ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr(MemberExprBase, ParamType, Loc, /*IsArrow=*/false, @@ -4346,7 +4371,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, // Direct-initialize to use the copy constructor. InitializationKind InitKind = InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); - + Expr *CtorArgE = CtorArg.getAs<Expr>(); InitializationSequence InitSeq(SemaRef, Entity, InitKind, CtorArgE); ExprResult MemberInit = @@ -4367,16 +4392,16 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) && "Unhandled implicit init kind!"); - QualType FieldBaseElementType = + QualType FieldBaseElementType = SemaRef.Context.getBaseElementType(Field->getType()); - + if (FieldBaseElementType->isRecordType()) { InitializedEntity InitEntity = Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr, /*Implicit*/ true) : InitializedEntity::InitializeMember(Field, nullptr, /*Implicit*/ true); - InitializationKind InitKind = + InitializationKind InitKind = InitializationKind::CreateDefault(Loc); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); @@ -4386,10 +4411,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; - + if (Indirect) CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, - Indirect, Loc, + Indirect, Loc, Loc, MemberInit.get(), Loc); @@ -4403,9 +4428,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, if (!Field->getParent()->isUnion()) { if (FieldBaseElementType->isReferenceType()) { - SemaRef.Diag(Constructor->getLocation(), + SemaRef.Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() + << (int)Constructor->isImplicit() << SemaRef.Context.getTagDeclType(Constructor->getParent()) << 0 << Field->getDeclName(); SemaRef.Diag(Field->getLocation(), diag::note_declared_at); @@ -4413,27 +4438,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, } if (FieldBaseElementType.isConstQualified()) { - SemaRef.Diag(Constructor->getLocation(), + SemaRef.Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() + << (int)Constructor->isImplicit() << SemaRef.Context.getTagDeclType(Constructor->getParent()) << 1 << Field->getDeclName(); SemaRef.Diag(Field->getLocation(), diag::note_declared_at); return true; } } - + if (FieldBaseElementType.hasNonTrivialObjCLifetime()) { // ARC and Weak: // Default-initialize Objective-C pointers to NULL. CXXMemberInit - = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, - Loc, Loc, - new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()), + = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + Loc, Loc, + new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()), Loc); return false; } - + // Nothing to initialize. CXXMemberInit = nullptr; return false; @@ -4461,13 +4486,13 @@ struct BaseAndFieldInfo { else IIK = IIK_Default; } - + bool isImplicitCopyOrMove() const { switch (IIK) { case IIK_Copy: case IIK_Move: return true; - + case IIK_Default: case IIK_Inherit: return false; @@ -4534,19 +4559,19 @@ struct BaseAndFieldInfo { static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { if (T->isIncompleteArrayType()) return true; - + while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) { if (!ArrayT->getSize()) return true; - + T = ArrayT->getElementType(); } - + return false; } static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, - FieldDecl *Field, + FieldDecl *Field, IndirectFieldDecl *Indirect = nullptr) { if (Field->isInvalidDecl()) return false; @@ -4659,7 +4684,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); if (!ClassDecl) return true; - + bool HadError = false; for (unsigned i = 0; i < Initializers.size(); i++) { @@ -4758,34 +4783,34 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, // initialized. if (F->isUnnamedBitfield()) continue; - + // If we're not generating the implicit copy/move constructor, then we'll // handle anonymous struct/union fields based on their individual // indirect fields. if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove()) continue; - + if (CollectFieldInitializer(*this, Info, F)) HadError = true; continue; } - + // Beyond this point, we only consider default initialization. if (Info.isImplicitCopyOrMove()) continue; - + if (auto *F = dyn_cast<IndirectFieldDecl>(Mem)) { if (F->getType()->isIncompleteArrayType()) { assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } - + // Initialize each field of an anonymous struct individually. if (CollectFieldInitializer(*this, Info, F->getAnonField(), F)) HadError = true; - - continue; + + continue; } } @@ -4827,7 +4852,7 @@ static const void *GetKeyForMember(ASTContext &Context, CXXCtorInitializer *Member) { if (!Member->isAnyMemberInitializer()) return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0)); - + return Member->getAnyMember()->getCanonicalDecl(); } @@ -4838,7 +4863,7 @@ static void DiagnoseBaseOrMemInitializerOrder( return; // Don't check initializers order unless the warning is enabled at the - // location of at least one initializer. + // location of at least one initializer. bool ShouldCheckOrder = false; for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) { CXXCtorInitializer *Init = Inits[InitIndex]; @@ -4850,7 +4875,7 @@ static void DiagnoseBaseOrMemInitializerOrder( } if (!ShouldCheckOrder) return; - + // Build the list of bases and members in the order that they'll // actually be initialized. The explicit initializers should be in // this same order but may be missing things. @@ -4873,10 +4898,10 @@ static void DiagnoseBaseOrMemInitializerOrder( for (auto *Field : ClassDecl->fields()) { if (Field->isUnnamedBitfield()) continue; - + PopulateKeysForFields(Field, IdealInitKeys); } - + unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; @@ -4903,7 +4928,7 @@ static void DiagnoseBaseOrMemInitializerOrder( D << 0 << PrevInit->getAnyMember()->getDeclName(); else D << 1 << PrevInit->getTypeSourceInfo()->getType(); - + if (Init->isAnyMemberInitializer()) D << 0 << Init->getAnyMember()->getDeclName(); else @@ -4971,7 +4996,7 @@ bool CheckRedundantUnionInit(Sema &S, S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer) << 0 << En.second->getSourceRange(); return true; - } + } if (!En.first) { En.first = Child; En.second = Init; @@ -5005,7 +5030,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, Diag(ColonLoc, diag::err_only_constructors_take_base_inits); return; } - + // Mapping for the duplicate initializers check. // For member initializers, this is keyed with a FieldDecl*. // For base initializers, this is keyed with a Type*. @@ -5067,22 +5092,22 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // field/base declaration. That's probably good; that said, the // user might reasonably want to know why the destructor is being // emitted, and we currently don't say. - + // Non-static data members. for (auto *Field : ClassDecl->fields()) { if (Field->isInvalidDecl()) continue; - + // Don't destroy incomplete or zero-length arrays. if (isIncompleteOrZeroLengthArrayType(Context, Field->getType())) continue; QualType FieldType = Context.getBaseElementType(Field->getType()); - + const RecordType* RT = FieldType->getAs<RecordType>(); if (!RT) continue; - + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); if (FieldClassDecl->isInvalidDecl()) continue; @@ -5137,14 +5162,14 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, << Base.getType() << Base.getSourceRange(), Context.getTypeDeclType(ClassDecl)); - + MarkFunctionReferenced(Location, Dtor); DiagnoseUseOfDecl(Dtor, Location); } if (!VisitVirtualBases) return; - + // Virtual bases. for (const auto &VBase : ClassDecl->vbases()) { // Bases are always records in a well-formed non-dependent class. @@ -5241,12 +5266,12 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { // Keep a set of seen pure methods so we won't diagnose the same method // more than once. llvm::SmallPtrSet<const CXXMethodDecl *, 8> SeenPureMethods; - - for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), MEnd = FinalOverriders.end(); - M != MEnd; + M != MEnd; ++M) { - for (OverridingMethods::iterator SO = M->second.begin(), + for (OverridingMethods::iterator SO = M->second.begin(), SOEnd = M->second.end(); SO != SOEnd; ++SO) { // C++ [class.abstract]p4: @@ -5254,7 +5279,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { // pure virtual function for which the final overrider is pure // virtual. - // + // if (SO->second.size() != 1) continue; @@ -5264,8 +5289,8 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { if (!SeenPureMethods.insert(SO->second.front().Method).second) continue; - Diag(SO->second.front().Method->getLocation(), - diag::note_pure_virtual_function) + Diag(SO->second.front().Method->getLocation(), + diag::note_pure_virtual_function) << SO->second.front().Method->getDeclName() << RD->getDeclName(); } } @@ -5745,7 +5770,7 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { !D->defaultedCopyConstructorIsDeleted()) { if (!D->hasTrivialCopyConstructor()) return false; - HasNonDeletedCopyOrMove = true; + HasNonDeletedCopyOrMove = true; } if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() && @@ -5787,7 +5812,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { AbstractUsageInfo Info(*this, Record); CheckAbstractClassUsage(Info, Record); } - + // If this is not an aggregate type and has no user-declared constructor, // complain about any non-static data members of reference or const scalar // type, since they will never get initializers. @@ -5806,7 +5831,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { << Record->getTagKind() << Record; Complained = true; } - + Diag(F->getLocation(), diag::note_refconst_member_not_initialized) << F->getType()->isReferenceType() << F->getDeclName(); @@ -5816,12 +5841,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->getIdentifier()) { // C++ [class.mem]p13: - // If T is the name of a class, then each of the following shall have a + // If T is the name of a class, then each of the following shall have a // name different from T: // - every member of every anonymous union that is a member of class T. // // C++ [class.mem]p14: - // In addition, if class T has a user-declared constructor (12.1), every + // In addition, if class T has a user-declared constructor (12.1), every // non-static data member of class T shall have a name different from T. DeclContext::lookup_result R = Record->lookup(Record->getDeclName()); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; @@ -7398,10 +7423,8 @@ private: const llvm::SmallPtrSetImpl<const CXXMethodDecl *> &Methods) { if (MD->size_overridden_methods() == 0) return Methods.count(MD->getCanonicalDecl()); - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) - if (CheckMostOverridenMethods(*I, Methods)) + for (const CXXMethodDecl *O : MD->overridden_methods()) + if (CheckMostOverridenMethods(O, Methods)) return true; return false; } @@ -7459,10 +7482,9 @@ static void AddMostOverridenMethods(const CXXMethodDecl *MD, llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { if (MD->size_overridden_methods() == 0) Methods.insert(MD->getCanonicalDecl()); - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) - AddMostOverridenMethods(*I, Methods); + else + for (const CXXMethodDecl *O : MD->overridden_methods()) + AddMostOverridenMethods(O, Methods); } /// \brief Check if a method overloads virtual methods in a base class without @@ -7821,11 +7843,11 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, // A constructor shall not be declared with a ref-qualifier. if (FTI.hasRefQualifier()) { Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor) - << FTI.RefQualifierIsLValueRef + << FTI.RefQualifierIsLValueRef << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); D.setInvalidType(); } - + // Rebuild the function type "R" without any type qualifiers (in // case any of the errors above fired) and with "void" as the // return type, since constructors don't have return types. @@ -7864,8 +7886,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); - const char *ConstRef - = Constructor->getParamDecl(0)->getIdentifier() ? "const &" + const char *ConstRef + = Constructor->getParamDecl(0)->getIdentifier() ? "const &" : " const &"; Diag(ParamLoc, diag::err_constructor_byvalue_arg) << FixItHint::CreateInsertion(ParamLoc, ConstRef); @@ -7882,23 +7904,49 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { /// on error. bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) { CXXRecordDecl *RD = Destructor->getParent(); - + if (!Destructor->getOperatorDelete() && Destructor->isVirtual()) { SourceLocation Loc; - + if (!Destructor->isImplicit()) Loc = Destructor->getLocation(); else Loc = RD->getLocation(); - + // If we have a virtual destructor, look up the deallocation function if (FunctionDecl *OperatorDelete = FindDeallocationFunctionForDestructor(Loc, RD)) { + Expr *ThisArg = nullptr; + + // If the notional 'delete this' expression requires a non-trivial + // conversion from 'this' to the type of a destroying operator delete's + // first parameter, perform that conversion now. + if (OperatorDelete->isDestroyingOperatorDelete()) { + QualType ParamType = OperatorDelete->getParamDecl(0)->getType(); + if (!declaresSameEntity(ParamType->getAsCXXRecordDecl(), RD)) { + // C++ [class.dtor]p13: + // ... as if for the expression 'delete this' appearing in a + // non-virtual destructor of the destructor's class. + ContextRAII SwitchContext(*this, Destructor); + ExprResult This = + ActOnCXXThis(OperatorDelete->getParamDecl(0)->getLocation()); + assert(!This.isInvalid() && "couldn't form 'this' expr in dtor?"); + This = PerformImplicitConversion(This.get(), ParamType, AA_Passing); + if (This.isInvalid()) { + // FIXME: Register this as a context note so that it comes out + // in the right order. + Diag(Loc, diag::note_implicit_delete_this_in_destructor_here); + return true; + } + ThisArg = This.get(); + } + } + MarkFunctionReferenced(Loc, OperatorDelete); - Destructor->setOperatorDelete(OperatorDelete); + Destructor->setOperatorDelete(OperatorDelete, ThisArg); } } - + return false; } @@ -7939,7 +7987,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - + SC = SC_None; } if (!D.isInvalidType()) { @@ -7988,7 +8036,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); D.setInvalidType(); } - + // Make sure we don't have any parameters. if (FTIHasNonVoidParameters(FTI)) { Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); @@ -8007,7 +8055,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // Rebuild the function type "R" without any type qualifiers or // parameters (in case any of the errors above fired) and with // "void" as the return type, since destructors don't have return - // types. + // types. if (!D.isInvalidType()) return R; @@ -8236,7 +8284,7 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) return ConversionTemplate; - + return Conversion; } @@ -8294,8 +8342,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, // We leave 'friend' and 'virtual' to be rejected in the normal way. if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() || DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() || - DS.isNoreturnSpecified() || DS.isConstexprSpecified() || - DS.isConceptSpecified()) { + DS.isNoreturnSpecified() || DS.isConstexprSpecified()) { BadSpecifierDiagnoser Diagnoser( *this, D.getIdentifierLoc(), diag::err_deduction_guide_invalid_specifier); @@ -8308,9 +8355,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, Diagnoser.check(DS.getInlineSpecLoc(), "inline"); Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn"); Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr"); - Diagnoser.check(DS.getConceptSpecLoc(), "concept"); DS.ClearConstexprSpec(); - DS.ClearConceptSpec(); Diagnoser.check(DS.getConstSpecLoc(), "const"); Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict"); @@ -8464,7 +8509,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // Since namespace names are unique in their scope, and we don't // look through using directives, just look for any ordinary names // as if by qualified name lookup. - LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration); + LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, + ForExternalRedeclaration); LookupQualifiedName(R, CurContext->getRedeclContext()); NamedDecl *PrevDecl = R.isSingleResult() ? R.getRepresentativeDecl() : nullptr; @@ -8495,7 +8541,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } } else { // Anonymous namespaces. - + // Determine whether the parent already has an anonymous namespace. DeclContext *Parent = CurContext->getRedeclContext(); if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) { @@ -8509,12 +8555,12 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II, &IsInline, PrevNS); } - + NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS); if (IsInvalid) Namespc->setInvalidDecl(); - + ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); AddPragmaAttributes(DeclRegionScope, Namespc); @@ -8526,7 +8572,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, StdNamespace = Namespc; if (AddToKnown) KnownNamespaces[Namespc] = false; - + if (II) { PushOnScopeChains(Namespc, DeclRegionScope); } else { @@ -8627,12 +8673,12 @@ NamespaceDecl *Sema::lookupStdExperimentalNamespace() { return StdExperimentalNamespaceCache; } -/// \brief Retrieve the special "std" namespace, which may require us to +/// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { // The "std" namespace has not yet been defined, so build one implicitly. - StdNamespace = NamespaceDecl::Create(Context, + StdNamespace = NamespaceDecl::Create(Context, Context.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(), SourceLocation(), @@ -8845,7 +8891,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, NestedNameSpecifier *Qualifier = nullptr; if (SS.isSet()) Qualifier = SS.getScopeRep(); - + // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); LookupParsedName(R, S, &SS); @@ -8854,18 +8900,18 @@ Decl *Sema::ActOnUsingDirective(Scope *S, if (R.empty()) { R.clear(); - // Allow "using namespace std;" or "using namespace ::std;" even if + // Allow "using namespace std;" or "using namespace ::std;" even if // "std" hasn't been defined yet, for GCC compatibility. if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) && NamespcName->isStr("std")) { Diag(IdentLoc, diag::ext_using_undefined_std); R.addDecl(getOrCreateStdNamespace()); R.resolveKind(); - } + } // Otherwise, attempt typo correction. else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName); } - + if (!R.empty()) { NamedDecl *Named = R.getRepresentativeDecl(); NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>(); @@ -8946,7 +8992,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_ConversionFunctionId: break; - + case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: // C++11 inheriting constructors. @@ -9089,7 +9135,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // If the target happens to be one of the previous declarations, we // don't have a conflict. - // + // // FIXME: but we might be increasing its access, in which case we // should redeclare it. NamedDecl *NonTag = nullptr, *Tag = nullptr; @@ -9401,7 +9447,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Do the redeclaration lookup in the current scope. LookupResult Previous(*this, UsingName, LookupUsingDeclName, - ForRedeclaration); + ForVisibleRedeclaration); Previous.setHideTags(false); if (S) { LookupName(Previous, S); @@ -9464,7 +9510,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, IdentLoc, NameInfo.getName(), EllipsisLoc); } else { - D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, + D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo, EllipsisLoc); } D->setAccess(AS); @@ -9977,11 +10023,14 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, UPPC_DeclarationType)) { Invalid = true; - TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, TInfo->getTypeLoc().getBeginLoc()); } - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + TemplateParamLists.size() + ? forRedeclarationInCurContext() + : ForVisibleRedeclaration); LookupName(Previous, S); // Warn about shadowing the name of a template parameter. @@ -10084,8 +10133,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewDecl->setInvalidDecl(); - else if (OldDecl) + else if (OldDecl) { NewDecl->setPreviousDecl(OldDecl); + CheckRedeclarationModuleOwnership(NewDecl, OldDecl); + } NewND = NewDecl; } else { @@ -10126,7 +10177,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, // Check if we have a previous declaration with the same name. LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(PrevR, S); // Check we're not shadowing a template parameter. @@ -10140,7 +10191,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, /*AllowInlineNamespace*/false); // Find the previous declaration and check that we can redeclare it. - NamespaceAliasDecl *Prev = nullptr; + NamespaceAliasDecl *Prev = nullptr; if (PrevR.isSingleResult()) { NamedDecl *PrevDecl = PrevR.getRepresentativeDecl(); if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { @@ -10261,7 +10312,7 @@ ComputeDefaultedSpecialMemberExceptionSpec( CXXRecordDecl *ClassDecl = MD->getParent(); // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an + // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc); if (ClassDecl->isInvalidDecl()) @@ -10339,7 +10390,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) { // implicit special members with this name. DeclarationName Name = FD->getDeclName(); LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName, - ForRedeclaration); + ForExternalRedeclaration); for (auto *D : FD->getParent()->lookup(Name)) if (auto *Acceptable = R.getAcceptableDecl(D)) R.addDecl(Acceptable); @@ -11126,7 +11177,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0) // - // that will copy each of the array elements. + // that will copy each of the array elements. QualType SizeType = S.Context.getSizeType(); // Create the iteration variable. @@ -11338,7 +11389,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { - assert((CopyAssignOperator->isDefaulted() && + assert((CopyAssignOperator->isDefaulted() && CopyAssignOperator->isOverloadedOperator() && CopyAssignOperator->getOverloadedOperator() == OO_Equal && !CopyAssignOperator->doesThisDeclarationHaveABody() && @@ -11372,15 +11423,15 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator - // for a non-union class X performs memberwise copy assignment of its - // subobjects. The direct base classes of X are assigned first, in the - // order of their declaration in the base-specifier-list, and then the - // immediate non-static data members of X are assigned, in the order in + // for a non-union class X performs memberwise copy assignment of its + // subobjects. The direct base classes of X are assigned first, in the + // order of their declaration in the base-specifier-list, and then the + // immediate non-static data members of X are assigned, in the order in // which they were declared in the class definition. - + // The statements that form the synthesized function body. SmallVector<Stmt*, 8> Statements; - + // The parameter for the "other" object, which we are copying from. ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); Qualifiers OtherQuals = Other->getType().getQualifiers(); @@ -11390,7 +11441,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, OtherRefType = OtherRef->getPointeeType(); OtherQuals = OtherRefType.getQualifiers(); } - + // Our location for everything implicitly-generated. SourceLocation Loc = CopyAssignOperator->getLocEnd().isValid() ? CopyAssignOperator->getLocEnd() @@ -11401,7 +11452,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Builds the "this" pointer. ThisBuilder This; - + // Assign base classes. bool Invalid = false; for (auto &Base : ClassDecl->bases()) { @@ -11437,11 +11488,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setInvalidDecl(); return; } - + // Success! Record the copy. Statements.push_back(Copy.getAs<Expr>()); } - + // Assign non-static members. for (auto *Field : ClassDecl->fields()) { // FIXME: We should form some kind of AST representation for the implied @@ -11462,28 +11513,28 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Invalid = true; continue; } - + // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Invalid = true; + Invalid = true; continue; } // Suppress assigning zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) continue; - + QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { - assert(ClassDecl->hasFlexibleArrayMember() && + assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } - + // Build references to the field in the object we're copying from and to. CXXScopeSpec SS; // Intentionally empty LookupResult MemberLookup(*this, Field->getDeclName(), Loc, @@ -11504,7 +11555,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setInvalidDecl(); return; } - + // Success! Record the copy. Statements.push_back(Copy.getAs<Stmt>()); } @@ -11512,7 +11563,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, if (!Invalid) { // Add a "return *this;" ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); - + StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; @@ -11700,7 +11751,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class, void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MoveAssignOperator) { - assert((MoveAssignOperator->isDefaulted() && + assert((MoveAssignOperator->isDefaulted() && MoveAssignOperator->isOverloadedOperator() && MoveAssignOperator->getOverloadedOperator() == OO_Equal && !MoveAssignOperator->doesThisDeclarationHaveABody() && @@ -11714,7 +11765,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, MoveAssignOperator->setInvalidDecl(); return; } - + // C++0x [class.copy]p28: // The implicitly-defined or move assignment operator for a non-union class // X performs memberwise move assignment of its subobjects. The direct base @@ -11836,21 +11887,21 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Invalid = true; + Invalid = true; continue; } // Suppress assigning zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) continue; - + QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { - assert(ClassDecl->hasFlexibleArrayMember() && + assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } - + // Build references to the field in the object we're copying from and to. LookupResult MemberLookup(*this, Field->getDeclName(), Loc, LookupMemberName); @@ -12164,26 +12215,26 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { SynthesizedFunctionScope Scope(*this, Conv); - + CXXRecordDecl *Lambda = Conv->getParent(); CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); // If we are defining a specialization of a conversion to function-ptr // cache the deduced template arguments for this specialization // so that we can use them to retrieve the corresponding call-operator - // and static-invoker. + // and static-invoker. const TemplateArgumentList *DeducedTemplateArgs = nullptr; // Retrieve the corresponding call-operator specialization. if (Lambda->isGenericLambda()) { assert(Conv->isFunctionTemplateSpecialization()); - FunctionTemplateDecl *CallOpTemplate = + FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate(); DeducedTemplateArgs = Conv->getTemplateSpecializationArgs(); void *InsertPos = nullptr; FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization( DeducedTemplateArgs->asArray(), InsertPos); - assert(CallOpSpec && + assert(CallOpSpec && "Conversion operator must have a corresponding call operator"); CallOp = cast<CXXMethodDecl>(CallOpSpec); } @@ -12199,15 +12250,15 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker(); // ... and get the corresponding specialization for a generic lambda. if (Lambda->isGenericLambda()) { - assert(DeducedTemplateArgs && + assert(DeducedTemplateArgs && "Must have deduced template arguments from Conversion Operator"); - FunctionTemplateDecl *InvokeTemplate = + FunctionTemplateDecl *InvokeTemplate = Invoker->getDescribedFunctionTemplate(); void *InsertPos = nullptr; FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization( DeducedTemplateArgs->asArray(), InsertPos); - assert(InvokeSpec && + assert(InvokeSpec && "Must have a corresponding static invoker specialization"); Invoker = cast<CXXMethodDecl>(InvokeSpec); } @@ -12222,13 +12273,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( Conv->markUsed(Context); Conv->setReferenced(); - + // Fill in the __invoke function with a dummy implementation. IR generation // will fill in the actual details. Invoker->markUsed(Context); Invoker->setReferenced(); Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); - + if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); L->CompletedImplicitDefinition(Invoker); @@ -12239,16 +12290,16 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( void Sema::DefineImplicitLambdaToBlockPointerConversion( SourceLocation CurrentLocation, - CXXConversionDecl *Conv) + CXXConversionDecl *Conv) { assert(!Conv->getParent()->isGenericLambda()); SynthesizedFunctionScope Scope(*this, Conv); - + // Copy-initialize the lambda object as needed to capture it. Expr *This = ActOnCXXThis(CurrentLocation).get(); Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).get(); - + ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation, Conv->getLocation(), Conv, DerefThis); @@ -12283,29 +12334,29 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); - + // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); } } -/// \brief Determine whether the given list arguments contains exactly one +/// \brief Determine whether the given list arguments contains exactly one /// "real" (non-default) argument. static bool hasOneRealArgument(MultiExprArg Args) { switch (Args.size()) { case 0: return false; - + default: if (!Args[1]->isDefaultArgument()) return false; - + // fall through case 1: return !Args[0]->isDefaultArgument(); } - + return false; } @@ -12362,7 +12413,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) { Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow); if (DiagnoseUseOfDecl(Constructor, ConstructLoc)) - return ExprError(); + return ExprError(); } return BuildCXXConstructExpr( @@ -12439,7 +12490,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { assert(Pattern && "We must have set the Pattern!"); } - if (InstantiateInClassInitializer(Loc, Field, Pattern, + if (!Pattern->hasInClassInitializer() || + InstantiateInClassInitializer(Loc, Field, Pattern, getTemplateInstantiationArgs(Field))) { // Don't diagnose this again. Field->setInvalidDecl(); @@ -12505,7 +12557,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { /// to form a proper call to this constructor. /// /// \returns true if an error occurred, false otherwise. -bool +bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, @@ -12516,7 +12568,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, unsigned NumArgs = ArgsPtr.size(); Expr **Args = ArgsPtr.data(); - const FunctionProtoType *Proto + const FunctionProtoType *Proto = Constructor->getType()->getAs<FunctionProtoType>(); assert(Proto && "Constructor without a prototype?"); unsigned NumParams = Proto->getNumParams(); @@ -12527,7 +12579,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, else ConvertedArgs.reserve(NumArgs); - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; SmallVector<Expr *, 8> AllArgs; bool Invalid = GatherArgumentsForCall(Loc, Constructor, @@ -12548,22 +12600,22 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, } static inline bool -CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, +CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { const DeclContext *DC = FnDecl->getDeclContext()->getRedeclContext(); if (isa<NamespaceDecl>(DC)) { - return SemaRef.Diag(FnDecl->getLocation(), + return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_in_namespace) << FnDecl->getDeclName(); } - - if (isa<TranslationUnitDecl>(DC) && + + if (isa<TranslationUnitDecl>(DC) && FnDecl->getStorageClass() == SC_Static) { return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_static) << FnDecl->getDeclName(); } - + return false; } @@ -12585,21 +12637,21 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, // Check that the result type is what we expect. if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_new_delete_invalid_result_type) + diag::err_operator_new_delete_invalid_result_type) << FnDecl->getDeclName() << ExpectedResultType; - + // A function template must have at least 2 parameters. if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_template_too_few_parameters) << FnDecl->getDeclName(); - + // The function decl must have at least 1 parameter. if (FnDecl->getNumParams() == 0) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_too_few_parameters) << FnDecl->getDeclName(); - + // Check the first parameter type is not dependent. QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); if (FirstParamType->isDependentType()) @@ -12607,11 +12659,11 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, << FnDecl->getDeclName() << ExpectedFirstParamType; // Check that the first parameter type is what we expect. - if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != + if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != ExpectedFirstParamType) return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) << FnDecl->getDeclName() << ExpectedFirstParamType; - + return false; } @@ -12619,18 +12671,18 @@ static bool CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { // C++ [basic.stc.dynamic.allocation]p1: // A program is ill-formed if an allocation function is declared in a - // namespace scope other than global scope or declared static in global + // namespace scope other than global scope or declared static in global // scope. if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) return true; - CanQualType SizeTy = + CanQualType SizeTy = SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType()); // C++ [basic.stc.dynamic.allocation]p1: - // The return type shall be void*. The first parameter shall have type + // The return type shall be void*. The first parameter shall have type // std::size_t. - if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, + if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, SizeTy, diag::err_operator_new_dependent_param_type, diag::err_operator_new_param_type)) @@ -12650,20 +12702,40 @@ static bool CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) { // C++ [basic.stc.dynamic.deallocation]p1: // A program is ill-formed if deallocation functions are declared in a - // namespace scope other than global scope or declared static in global + // namespace scope other than global scope or declared static in global // scope. if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) return true; + auto *MD = dyn_cast<CXXMethodDecl>(FnDecl); + + // C++ P0722: + // Within a class C, the first parameter of a destroying operator delete + // shall be of type C *. The first parameter of any other deallocation + // function shall be of type void *. + CanQualType ExpectedFirstParamType = + MD && MD->isDestroyingOperatorDelete() + ? SemaRef.Context.getCanonicalType(SemaRef.Context.getPointerType( + SemaRef.Context.getRecordType(MD->getParent()))) + : SemaRef.Context.VoidPtrTy; + // C++ [basic.stc.dynamic.deallocation]p2: - // Each deallocation function shall return void and its first parameter - // shall be void*. - if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy, - SemaRef.Context.VoidPtrTy, - diag::err_operator_delete_dependent_param_type, - diag::err_operator_delete_param_type)) + // Each deallocation function shall return void + if (CheckOperatorNewDeleteTypes( + SemaRef, FnDecl, SemaRef.Context.VoidTy, ExpectedFirstParamType, + diag::err_operator_delete_dependent_param_type, + diag::err_operator_delete_param_type)) return true; + // C++ P0722: + // A destroying operator delete shall be a usual deallocation function. + if (MD && !MD->getParent()->isDependentContext() && + MD->isDestroyingOperatorDelete() && !MD->isUsualDeallocationFunction()) { + SemaRef.Diag(MD->getLocation(), + diag::err_destroying_operator_delete_not_usual); + return true; + } + return false; } @@ -12684,7 +12756,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // explicitly stated in 3.7.3. if (Op == OO_Delete || Op == OO_Array_Delete) return CheckOperatorDeleteDeclaration(*this, FnDecl); - + if (Op == OO_New || Op == OO_Array_New) return CheckOperatorNewDeclaration(*this, FnDecl); @@ -13088,7 +13160,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, IdentifierInfo *Name) { bool Invalid = false; QualType ExDeclType = TInfo->getType(); - + // Arrays and functions decay. if (ExDeclType->isArrayType()) ExDeclType = Context.getArrayDecayedType(ExDeclType); @@ -13152,7 +13224,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name, ExDeclType, TInfo, SC_None); ExDecl->setExceptionVariable(true); - + // In ARC, infer 'retaining' for variables of retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(ExDecl)) Invalid = true; @@ -13193,13 +13265,13 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Expr *init = MaybeCreateExprWithCleanups(construct); ExDecl->setInit(init); } - + // And make sure it's destructable. FinalizeVarWithDestructor(ExDecl, recordType); } } } - + if (Invalid) ExDecl->setInvalidDecl(); @@ -13215,7 +13287,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_ExceptionType)) { - TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, D.getIdentifierLoc()); Invalid = true; } @@ -13223,7 +13295,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration)) { + ForVisibleRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration, except for function parameters in // a function-try-block's catch statement. @@ -13300,8 +13372,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, llvm::raw_svector_ostream Msg(MsgBuffer); if (AssertMessage) AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + + Expr *InnerCond = nullptr; + std::string InnerCondDescription; + std::tie(InnerCond, InnerCondDescription) = + findFailedBooleanCondition(Converted.get(), + /*AllowTopLevelCond=*/false); + if (InnerCond) { + Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) + << InnerCondDescription << !AssertMessage + << Msg.str() << InnerCond->getSourceRange(); + } else { + Diag(StaticAssertLoc, diag::err_static_assert_failed) + << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + } Failed = true; } } @@ -13329,10 +13413,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo) { assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); - + QualType T = TSInfo->getType(); SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); - + // C++03 [class.friend]p2: // An elaborated-type-specifier shall be used in a friend declaration // for a class.* @@ -13376,7 +13460,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, << T << TypeRange; } - + // C++11 [class.friend]p3: // A friend declaration that does not declare a function shall have one // of the following forms: @@ -13489,9 +13573,9 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, CurContext->addDecl(Friend); return Friend; } - + assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); - + // Handle the case of a templated-scope friend class. e.g. @@ -13571,7 +13655,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << DS.getSourceRange(); return nullptr; } - + // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 @@ -13591,7 +13675,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, DS.getFriendSpecLoc()); else D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI); - + if (!D) return nullptr; @@ -13660,7 +13744,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, DeclContext *DC; Scope *DCScope = S; LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + ForExternalRedeclaration); // There are five cases here. // - There's no scope specifier and we're in a local class. Only look @@ -13791,15 +13875,15 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_friend_is_member : diag::err_friend_is_member); - + if (D.isFunctionDefinition()) { // C++ [class.friend]p6: - // A function can be defined in a friend declaration of a class if and + // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. SemaDiagnosticBuilder DB = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); - + DB << SS.getScopeRep(); if (DC->isFileContext()) DB << FixItHint::CreateRemoval(SS.getRange()); @@ -13814,13 +13898,13 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, } else { if (D.isFunctionDefinition()) { // C++ [class.friend]p6: - // A function can be defined in a friend declaration of a class if and + // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) << SS.getScopeRep(); } - + DC = CurContext; assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?"); } @@ -13856,7 +13940,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, } // FIXME: This is an egregious hack to cope with cases where the scope stack - // does not contain the declaration context, i.e., in an out-of-line + // does not contain the declaration context, i.e., in an out-of-line // definition of a class. Scope FakeDCScope(S, Scope::DeclScope, Diags); if (!DCScope) { @@ -13974,15 +14058,13 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // non-deleted virtual function. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { bool IssuedDiagnostic = false; - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) { + for (const CXXMethodDecl *O : MD->overridden_methods()) { if (!(*MD->begin_overridden_methods())->isDeleted()) { if (!IssuedDiagnostic) { Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName(); IssuedDiagnostic = true; } - Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + Diag(O->getLocation(), diag::note_overridden_virtual_function); } } // If this function was implicitly deleted because it was defaulted, @@ -14072,8 +14154,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - const FunctionType *NewFT = New->getType()->getAs<FunctionType>(); - const FunctionType *OldFT = Old->getType()->getAs<FunctionType>(); + const auto *NewFT = New->getType()->getAs<FunctionProtoType>(); + const auto *OldFT = Old->getType()->getAs<FunctionProtoType>(); + + if (OldFT->hasExtParameterInfos()) { + for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I) + // A parameter of the overriding method should be annotated with noescape + // if the corresponding parameter of the overridden method is annotated. + if (OldFT->getExtParameterInfo(I).isNoEscape() && + !NewFT->getExtParameterInfo(I).isNoEscape()) { + Diag(New->getParamDecl(I)->getLocation(), + diag::warn_overriding_method_missing_noescape); + Diag(Old->getParamDecl(I)->getLocation(), + diag::note_overridden_marked_noescape); + } + } CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv(); @@ -14231,21 +14326,22 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) { Diag(D->getLocation(), diag::err_illegal_initializer); } -/// \brief Determine whether the given declaration is a static data member. -static bool isStaticDataMember(const Decl *D) { +/// \brief Determine whether the given declaration is a global variable or +/// static data member. +static bool isNonlocalVariable(const Decl *D) { if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D)) - return Var->isStaticDataMember(); + return Var->hasGlobalStorage(); return false; } -/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse -/// an initializer for the out-of-line declaration 'Dcl'. The scope -/// is a fresh scope pushed for just this purpose. +/// Invoked when we are about to parse an initializer for the declaration +/// 'Dcl'. /// /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of -/// class X. +/// class X. If the declaration had a scope specifier, a scope will have +/// been created and passed in for this purpose. Otherwise, S will be null. void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (!D || D->isInvalidDecl()) @@ -14255,28 +14351,27 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // might not be out of line if the specifier names the current namespace: // extern int n; // int ::n = 0; - if (D->isOutOfLine()) + if (S && D->isOutOfLine()) EnterDeclaratorContext(S, D->getDeclContext()); // If we are parsing the initializer for a static data member, push a // new expression evaluation context that is associated with this static // data member. - if (isStaticDataMember(D)) + if (isNonlocalVariable(D)) PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated, D); } -/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an -/// initializer for the out-of-line declaration 'D'. +/// Invoked after we are finished parsing an initializer for the declaration D. void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (!D || D->isInvalidDecl()) return; - if (isStaticDataMember(D)) + if (isNonlocalVariable(D)) PopExpressionEvaluationContext(); - if (D->isOutOfLine()) + if (S && D->isOutOfLine()) ExitDeclaratorContext(S); } @@ -14307,7 +14402,7 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { void Sema::LoadExternalVTableUses() { if (!ExternalSource) return; - + SmallVector<ExternalVTableUse, 4> VTables; ExternalSource->ReadUsedVTables(VTables); SmallVector<VTableUse, 4> NewUses; @@ -14320,11 +14415,11 @@ void Sema::LoadExternalVTableUses() { Pos->second = true; continue; } - + VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired; NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location)); } - + VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end()); } @@ -14531,17 +14626,17 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { FieldDecl *Field = ivars[i]; if (Field->isInvalidDecl()) continue; - + CXXCtorInitializer *Member; InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); - InitializationKind InitKind = + InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); InitializationSequence InitSeq(*this, InitEntity, InitKind, None); ExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, None); MemberInit = MaybeCreateExprWithCleanups(MemberInit); - // Note, MemberInit could actually come back empty if no initialization + // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) if (!MemberInit.get() || MemberInit.isInvalid()) continue; @@ -14552,7 +14647,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { MemberInit.getAs<Expr>(), SourceLocation()); AllToInit.push_back(Member); - + // Be sure that the destructor is accessible and is marked as referenced. if (const RecordType *RecordTy = Context.getBaseElementType(Field->getType()) @@ -14564,9 +14659,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { PDiag(diag::err_access_dtor_ivar) << Context.getBaseElementType(Field->getType())); } - } + } } - ObjCImplementation->setIvarInitializers(Context, + ObjCImplementation->setIvarInitializers(Context, AllToInit.data(), AllToInit.size()); } } @@ -14634,7 +14729,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor, DelegatingCycleHelper(Target, Valid, Invalid, Current, S); } } - + void Sema::CheckDelegatingCtorCycles() { llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; @@ -14655,10 +14750,10 @@ namespace { /// \brief AST visitor that finds references to the 'this' expression. class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> { Sema &S; - + public: explicit FindCXXThisExpr(Sema &S) : S(S) { } - + bool VisitCXXThisExpr(CXXThisExpr *E) { S.Diag(E->getLocation(), diag::err_this_static_member_func) << E->isImplicit(); @@ -14671,22 +14766,22 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); if (!TSInfo) return false; - + TypeLoc TL = TSInfo->getTypeLoc(); FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>(); if (!ProtoTL) return false; - + // C++11 [expr.prim.general]p3: - // [The expression this] shall not appear before the optional - // cv-qualifier-seq and it shall not appear within the declaration of a + // [The expression this] shall not appear before the optional + // cv-qualifier-seq and it shall not appear within the declaration of a // static member function (although its type and value category are defined // within a static member function as they are within a non-static member // function). [ Note: this is because declaration matching does not occur // until the complete declarator is known. - end note ] const FunctionProtoType *Proto = ProtoTL.getTypePtr(); FindCXXThisExpr Finder(*this); - + // If the return type came after the cv-qualifier-seq, check it now. if (Proto->hasTrailingReturn() && !Finder.TraverseTypeLoc(ProtoTL.getReturnLoc())) @@ -14695,7 +14790,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { // Check the exception specification. if (checkThisInStaticMemberFunctionExceptionSpec(Method)) return true; - + return checkThisInStaticMemberFunctionAttributes(Method); } @@ -14703,12 +14798,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); if (!TSInfo) return false; - + TypeLoc TL = TSInfo->getTypeLoc(); FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>(); if (!ProtoTL) return false; - + const FunctionProtoType *Proto = ProtoTL.getTypePtr(); FindCXXThisExpr Finder(*this); @@ -14721,12 +14816,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { case EST_MSAny: case EST_None: break; - + case EST_ComputedNoexcept: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; LLVM_FALLTHROUGH; - + case EST_Dynamic: for (const auto &E : Proto->exceptions()) { if (!Finder.TraverseType(E)) @@ -14775,13 +14870,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { if (Arg && !Finder.TraverseStmt(Arg)) return true; - + for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (!Finder.TraverseStmt(Args[I])) return true; } } - + return false; } @@ -14832,10 +14927,16 @@ void Sema::checkExceptionSpecification( return; } - if (!NoexceptExpr->isValueDependent()) - NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr, - diag::err_noexcept_needs_constant_expression, - /*AllowFold*/ false).get(); + if (!NoexceptExpr->isValueDependent()) { + ExprResult Result = VerifyIntegerConstantExpression( + NoexceptExpr, nullptr, diag::err_noexcept_needs_constant_expression, + /*AllowFold*/ false); + if (Result.isInvalid()) { + ESI.Type = EST_BasicNoexcept; + return; + } + NoexceptExpr = Result.get(); + } ESI.NoexceptExpr = NoexceptExpr; } return; @@ -14874,10 +14975,8 @@ void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, if (Method->isVirtual()) { // Check overrides, which we previously had to delay. - for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(), - OEnd = Method->end_overridden_methods(); - O != OEnd; ++O) - CheckOverridingFunctionExceptionSpec(Method, *O); + for (const CXXMethodDecl *O : Method->overridden_methods()) + CheckOverridingFunctionExceptionSpec(Method, O); } } @@ -14913,7 +15012,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) @@ -14921,7 +15020,8 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; - LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupResult Previous(*this, II, Loc, LookupMemberName, + ForVisibleRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index 967573011d0dc..abbdc9574b8ce 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -157,34 +157,44 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, diag::note_related_result_type_overridden); } if (getLangOpts().ObjCAutoRefCount) { - if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() != - Overridden->hasAttr<NSReturnsRetainedAttr>())) { - Diag(NewMethod->getLocation(), - diag::err_nsreturns_retained_attribute_mismatch) << 1; - Diag(Overridden->getLocation(), diag::note_previous_decl) - << "method"; - } - if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() != - Overridden->hasAttr<NSReturnsNotRetainedAttr>())) { - Diag(NewMethod->getLocation(), - diag::err_nsreturns_retained_attribute_mismatch) << 0; - Diag(Overridden->getLocation(), diag::note_previous_decl) - << "method"; + Diags.setSeverity(diag::warn_nsreturns_retained_attribute_mismatch, + diag::Severity::Error, SourceLocation()); + Diags.setSeverity(diag::warn_nsconsumed_attribute_mismatch, + diag::Severity::Error, SourceLocation()); + } + + if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() != + Overridden->hasAttr<NSReturnsRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::warn_nsreturns_retained_attribute_mismatch) << 1; + Diag(Overridden->getLocation(), diag::note_previous_decl) << "method"; + } + if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() != + Overridden->hasAttr<NSReturnsNotRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::warn_nsreturns_retained_attribute_mismatch) << 0; + Diag(Overridden->getLocation(), diag::note_previous_decl) << "method"; + } + + ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(), + oe = Overridden->param_end(); + for (ObjCMethodDecl::param_iterator ni = NewMethod->param_begin(), + ne = NewMethod->param_end(); + ni != ne && oi != oe; ++ni, ++oi) { + const ParmVarDecl *oldDecl = (*oi); + ParmVarDecl *newDecl = (*ni); + if (newDecl->hasAttr<NSConsumedAttr>() != + oldDecl->hasAttr<NSConsumedAttr>()) { + Diag(newDecl->getLocation(), diag::warn_nsconsumed_attribute_mismatch); + Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter"; } - ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(), - oe = Overridden->param_end(); - for (ObjCMethodDecl::param_iterator - ni = NewMethod->param_begin(), ne = NewMethod->param_end(); - ni != ne && oi != oe; ++ni, ++oi) { - const ParmVarDecl *oldDecl = (*oi); - ParmVarDecl *newDecl = (*ni); - if (newDecl->hasAttr<NSConsumedAttr>() != - oldDecl->hasAttr<NSConsumedAttr>()) { - Diag(newDecl->getLocation(), - diag::err_nsconsumed_attribute_mismatch); - Diag(oldDecl->getLocation(), diag::note_previous_decl) - << "parameter"; - } + + // A parameter of the overriding method should be annotated with noescape + // if the corresponding parameter of the overridden method is annotated. + if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) { + Diag(newDecl->getLocation(), + diag::warn_overriding_method_missing_noescape); + Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape); } } } @@ -933,8 +943,9 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *PrevDecl = + LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, + forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; @@ -1085,16 +1096,18 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, IdentifierInfo *ClassName, SourceLocation ClassLocation) { // Look for previous declaration of alias name - NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *ADecl = + LookupSingleName(TUScope, AliasName, AliasLocation, LookupOrdinaryName, + forRedeclarationInCurContext()); if (ADecl) { Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName; Diag(ADecl->getLocation(), diag::note_previous_declaration); return nullptr; } // Check for class declaration - NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *CDeclU = + LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, + forRedeclarationInCurContext()); if (const TypedefNameDecl *TDecl = dyn_cast_or_null<TypedefNameDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); @@ -1102,7 +1115,8 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { ClassName = IDecl->getIdentifier(); CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, + forRedeclarationInCurContext()); } } } @@ -1164,7 +1178,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc, - ForRedeclaration); + forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = nullptr; if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) { // If we already have a definition, complain. @@ -1720,7 +1734,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, for (const IdentifierLocPair &IdentPair : IdentList) { IdentifierInfo *Ident = IdentPair.first; ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentPair.second, - ForRedeclaration); + forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident, IdentPair.second, AtProtocolLoc, @@ -1911,7 +1925,7 @@ Decl *Sema::ActOnStartClassImplementation( // Check for another declaration kind with the same name. NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -2987,7 +3001,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // Check for another declaration kind with the same name. NamedDecl *PrevDecl = LookupSingleName(TUScope, IdentList[i], IdentLocs[i], - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { // GCC apparently allows the following idiom: // @@ -3707,6 +3721,26 @@ static void DiagnoseWeakIvars(Sema &S, ObjCImplementationDecl *ID) { } } +/// Diagnose attempts to use flexible array member with retainable object type. +static void DiagnoseRetainableFlexibleArrayMember(Sema &S, + ObjCInterfaceDecl *ID) { + if (!S.getLangOpts().ObjCAutoRefCount) + return; + + for (auto ivar = ID->all_declared_ivar_begin(); ivar; + ivar = ivar->getNextIvar()) { + if (ivar->isInvalidDecl()) + continue; + QualType IvarTy = ivar->getType(); + if (IvarTy->isIncompleteArrayType() && + (IvarTy.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) && + IvarTy->isObjCLifetimeType()) { + S.Diag(ivar->getLocation(), diag::err_flexible_array_arc_retainable); + ivar->setInvalidDecl(); + } + } +} + Sema::ObjCContainerKind Sema::getObjCContainerKind() const { switch (CurContext->getDeclKind()) { case Decl::ObjCInterface: @@ -3727,6 +3761,96 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const { } } +static bool IsVariableSizedType(QualType T) { + if (T->isIncompleteArrayType()) + return true; + const auto *RecordTy = T->getAs<RecordType>(); + return (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()); +} + +static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { + ObjCInterfaceDecl *IntfDecl = nullptr; + ObjCInterfaceDecl::ivar_range Ivars = llvm::make_range( + ObjCInterfaceDecl::ivar_iterator(), ObjCInterfaceDecl::ivar_iterator()); + if ((IntfDecl = dyn_cast<ObjCInterfaceDecl>(OCD))) { + Ivars = IntfDecl->ivars(); + } else if (auto *ImplDecl = dyn_cast<ObjCImplementationDecl>(OCD)) { + IntfDecl = ImplDecl->getClassInterface(); + Ivars = ImplDecl->ivars(); + } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(OCD)) { + if (CategoryDecl->IsClassExtension()) { + IntfDecl = CategoryDecl->getClassInterface(); + Ivars = CategoryDecl->ivars(); + } + } + + // Check if variable sized ivar is in interface and visible to subclasses. + if (!isa<ObjCInterfaceDecl>(OCD)) { + for (auto ivar : Ivars) { + if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) { + S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility) + << ivar->getDeclName() << ivar->getType(); + } + } + } + + // Subsequent checks require interface decl. + if (!IntfDecl) + return; + + // Check if variable sized ivar is followed by another ivar. + for (ObjCIvarDecl *ivar = IntfDecl->all_declared_ivar_begin(); ivar; + ivar = ivar->getNextIvar()) { + if (ivar->isInvalidDecl() || !ivar->getNextIvar()) + continue; + QualType IvarTy = ivar->getType(); + bool IsInvalidIvar = false; + if (IvarTy->isIncompleteArrayType()) { + S.Diag(ivar->getLocation(), diag::err_flexible_array_not_at_end) + << ivar->getDeclName() << IvarTy + << TTK_Class; // Use "class" for Obj-C. + IsInvalidIvar = true; + } else if (const RecordType *RecordTy = IvarTy->getAs<RecordType>()) { + if (RecordTy->getDecl()->hasFlexibleArrayMember()) { + S.Diag(ivar->getLocation(), + diag::err_objc_variable_sized_type_not_at_end) + << ivar->getDeclName() << IvarTy; + IsInvalidIvar = true; + } + } + if (IsInvalidIvar) { + S.Diag(ivar->getNextIvar()->getLocation(), + diag::note_next_ivar_declaration) + << ivar->getNextIvar()->getSynthesize(); + ivar->setInvalidDecl(); + } + } + + // Check if ObjC container adds ivars after variable sized ivar in superclass. + // Perform the check only if OCD is the first container to declare ivars to + // avoid multiple warnings for the same ivar. + ObjCIvarDecl *FirstIvar = + (Ivars.begin() == Ivars.end()) ? nullptr : *Ivars.begin(); + if (FirstIvar && (FirstIvar == IntfDecl->all_declared_ivar_begin())) { + const ObjCInterfaceDecl *SuperClass = IntfDecl->getSuperClass(); + while (SuperClass && SuperClass->ivar_empty()) + SuperClass = SuperClass->getSuperClass(); + if (SuperClass) { + auto IvarIter = SuperClass->ivar_begin(); + std::advance(IvarIter, SuperClass->ivar_size() - 1); + const ObjCIvarDecl *LastIvar = *IvarIter; + if (IsVariableSizedType(LastIvar->getType())) { + S.Diag(FirstIvar->getLocation(), + diag::warn_superclass_variable_sized_type_not_at_end) + << FirstIvar->getDeclName() << LastIvar->getDeclName() + << LastIvar->getType() << SuperClass->getDeclName(); + S.Diag(LastIvar->getLocation(), diag::note_entity_declared_at) + << LastIvar->getDeclName(); + } + } + } +} + // Note: For class/category implementations, allMethods is always null. Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, ArrayRef<DeclGroupPtrTy> allTUVars) { @@ -3858,6 +3982,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, if (IDecl->hasDesignatedInitializers()) DiagnoseMissingDesignatedInitOverrides(IC, IDecl); DiagnoseWeakIvars(*this, IC); + DiagnoseRetainableFlexibleArrayMember(*this, IDecl); bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>(); if (IDecl->getSuperClass() == nullptr) { @@ -3927,6 +4052,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, } } } + DiagnoseVariableSizedIvars(*this, OCD); if (isInterfaceDeclKind) { // Reject invalid vardecls. for (unsigned i = 0, e = allTUVars.size(); i != e; i++) { @@ -4209,6 +4335,10 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, // Then merge the declarations. mergeObjCMethodDecls(ObjCMethod, overridden); + } + + for (ObjCMethodDecl *overridden : overrides) { + CheckObjCMethodOverride(ObjCMethod, overridden); if (ObjCMethod->isImplicit() && overridden->isImplicit()) continue; // Conflicting properties are detected elsewhere. @@ -4433,7 +4563,7 @@ Decl *Sema::ActOnMethodDeclaration( } LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc, - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); @@ -4670,7 +4800,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. - if (T.getAddressSpace() != 0) { + if (T.getAddressSpace() != LangAS::Default) { Diag(IdLoc, diag::err_arg_with_address_space); Invalid = true; } @@ -4716,7 +4846,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { } if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) - << getLangOpts().CPlusPlus1z; + << getLangOpts().CPlusPlus17; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index deb6cbb53aff5..67d1b02d1fca8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -145,7 +145,7 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { bool Sema::CheckDistantExceptionSpec(QualType T) { // C++17 removes this rule in favor of putting exception specifications into // the type system. - if (getLangOpts().CPlusPlus1z) + if (getLangOpts().CPlusPlus17) return false; if (const PointerType *PT = T->getAs<PointerType>()) @@ -237,10 +237,10 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { - // Just completely ignore this under -fno-exceptions prior to C++1z. - // In C++1z onwards, the exception specification is part of the type and + // Just completely ignore this under -fno-exceptions prior to C++17. + // In C++17 onwards, the exception specification is part of the type and // we will diagnose mismatches anyway, so it's better to check for them here. - if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus1z) + if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17) return false; OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); @@ -872,7 +872,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { // This is not an error in C++17 onwards, unless the noexceptness doesn't // match, but in that case we have a full-on type mismatch, not just a // type sugar mismatch. - if (getLangOpts().CPlusPlus1z) { + if (getLangOpts().CPlusPlus17) { DiagID = diag::warn_incompatible_exception_specs; NestedDiagID = diag::warn_deep_exception_specs_differ; } @@ -892,7 +892,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(), ToFunc, From->getSourceRange().getBegin(), FromFunc, SourceLocation()) && - !getLangOpts().CPlusPlus1z; + !getLangOpts().CPlusPlus17; } bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, @@ -953,7 +953,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { QualType T; // In C++1z, just look at the function type of the callee. - if (S.getLangOpts().CPlusPlus1z && isa<CallExpr>(E)) { + if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) { E = cast<CallExpr>(E)->getCallee(); T = E->getType(); if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index d3d7d8b67c70c..929806ac6bfaf 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -79,7 +79,8 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { if (const auto *A = D->getAttr<UnusedAttr>()) { // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) // should diagnose them. - if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) { + if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused && + A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) { const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext()); if (DC && !DC->hasAttr<UnusedAttr>()) S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); @@ -425,14 +426,6 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); if (Ty->isFunctionType()) { - // If we are here, we are not calling a function but taking - // its address (which is not allowed in OpenCL v1.0 s6.8.a.3). - if (getLangOpts().OpenCL) { - if (Diagnose) - Diag(E->getExprLoc(), diag::err_opencl_taking_function_address); - return ExprError(); - } - if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc())) @@ -722,8 +715,10 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { return ExprError(); E = Res.get(); - // If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to - // double. + // If this is a 'float' or '__fp16' (CVR qualified or typedef) + // promote to double. + // Note that default argument promotion applies only to float (and + // half/fp16); it does not apply to _Float16. const BuiltinType *BTy = Ty->getAs<BuiltinType>(); if (BTy && (BTy->getKind() == BuiltinType::Half || BTy->getKind() == BuiltinType::Float)) { @@ -995,7 +990,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, return ResultType; } -/// \brief Hande arithmetic conversion from integer to float. Helper function +/// \brief Handle arithmetic conversion from integer to float. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, ExprResult &IntExpr, @@ -1502,8 +1497,9 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/false) == Sema::LOLR_Error) + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ true) == Sema::LOLR_Error) return ExprError(); return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); @@ -1594,8 +1590,9 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, ArgTy, - /*AllowRaw*/false, /*AllowTemplate*/false, - /*AllowStringTemplate*/true)) { + /*AllowRaw*/ false, /*AllowTemplate*/ false, + /*AllowStringTemplate*/ true, + /*DiagnoseMissing*/ true)) { case LOLR_Cooked: { llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); @@ -1628,6 +1625,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { } case LOLR_Raw: case LOLR_Template: + case LOLR_ErrorNoDiagnostic: llvm_unreachable("unexpected literal operator lookup result"); case LOLR_Error: return ExprError(); @@ -2806,6 +2804,8 @@ ExprResult Sema::BuildDeclarationNameExpr( { QualType type = VD->getType(); + if (type.isNull()) + return ExprError(); if (auto *FPT = type->getAs<FunctionProtoType>()) { // C++ [except.spec]p17: // An exception-specification is considered to be needed when: @@ -3250,11 +3250,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, CookedTy, - /*AllowRaw*/true, /*AllowTemplate*/true, - /*AllowStringTemplate*/false)) { + /*AllowRaw*/ true, /*AllowTemplate*/ true, + /*AllowStringTemplate*/ false, + /*DiagnoseMissing*/ !Literal.isImaginary)) { + case LOLR_ErrorNoDiagnostic: + // Lookup failure for imaginary constants isn't fatal, there's still the + // GNU extension producing _Complex types. + break; case LOLR_Error: return ExprError(); - case LOLR_Cooked: { Expr *Lit; if (Literal.isFloatingLiteral()) { @@ -3322,6 +3326,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Ty = Context.FloatTy; else if (Literal.isLong) Ty = Context.LongDoubleTy; + else if (Literal.isFloat16) + Ty = Context.Float16Ty; else if (Literal.isFloat128) Ty = Context.Float128Ty; else @@ -3470,10 +3476,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } // If this is an imaginary literal, create the ImaginaryLiteral wrapper. - if (Literal.isImaginary) + if (Literal.isImaginary) { Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); + Diag(Tok.getLocation(), diag::ext_imaginary_constant); + } return Res; } @@ -4477,6 +4485,22 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. + // + // FIXME: Pass in a correct Pattern argument, otherwise + // getTemplateInstantiationArgs uses the lexical context of FD, e.g. + // + // template<typename T> + // struct A { + // static int FooImpl(); + // + // template<typename Tp> + // // bug: default argument A<T>::FooImpl() is evaluated with 2-level + // // template argument list [[T], [Tp]], should be [[Tp]]. + // friend A<Tp> Foo(int a); + // }; + // + // template<typename T> + // A<T> Foo(int a = A<T>::FooImpl()); MultiLevelTemplateArgumentList MutiLevelArgList = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); @@ -5041,7 +5065,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, } NeedsNewDecl = true; - unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace(); + LangAS AS = ArgType->getPointeeType().getAddressSpace(); QualType PointeeType = ParamType->getPointeeType(); PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); @@ -5104,6 +5128,87 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn, } } +static bool enclosingClassIsRelatedToClassInWhichMembersWereFound( + const UnresolvedMemberExpr *const UME, Sema &S) { + + const auto GetFunctionLevelDCIfCXXClass = + [](Sema &S) -> const CXXRecordDecl * { + const DeclContext *const DC = S.getFunctionLevelDeclContext(); + if (!DC || !DC->getParent()) + return nullptr; + + // If the call to some member function was made from within a member + // function body 'M' return return 'M's parent. + if (const auto *MD = dyn_cast<CXXMethodDecl>(DC)) + return MD->getParent()->getCanonicalDecl(); + // else the call was made from within a default member initializer of a + // class, so return the class. + if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) + return RD->getCanonicalDecl(); + return nullptr; + }; + // If our DeclContext is neither a member function nor a class (in the + // case of a lambda in a default member initializer), we can't have an + // enclosing 'this'. + + const CXXRecordDecl *const CurParentClass = GetFunctionLevelDCIfCXXClass(S); + if (!CurParentClass) + return false; + + // The naming class for implicit member functions call is the class in which + // name lookup starts. + const CXXRecordDecl *const NamingClass = + UME->getNamingClass()->getCanonicalDecl(); + assert(NamingClass && "Must have naming class even for implicit access"); + + // If the unresolved member functions were found in a 'naming class' that is + // related (either the same or derived from) to the class that contains the + // member function that itself contained the implicit member access. + + return CurParentClass == NamingClass || + CurParentClass->isDerivedFrom(NamingClass); +} + +static void +tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + Sema &S, const UnresolvedMemberExpr *const UME, SourceLocation CallLoc) { + + if (!UME) + return; + + LambdaScopeInfo *const CurLSI = S.getCurLambda(); + // Only try and implicitly capture 'this' within a C++ Lambda if it hasn't + // already been captured, or if this is an implicit member function call (if + // it isn't, an attempt to capture 'this' should already have been made). + if (!CurLSI || CurLSI->ImpCaptureStyle == CurLSI->ImpCap_None || + !UME->isImplicitAccess() || CurLSI->isCXXThisCaptured()) + return; + + // Check if the naming class in which the unresolved members were found is + // related (same as or is a base of) to the enclosing class. + + if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S)) + return; + + + DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent(); + // If the enclosing function is not dependent, then this lambda is + // capture ready, so if we can capture this, do so. + if (!EnclosingFunctionCtx->isDependentContext()) { + // If the current lambda and all enclosing lambdas can capture 'this' - + // then go ahead and capture 'this' (since our unresolved overload set + // contains at least one non-static member function). + if (!S.CheckCXXThisCapture(CallLoc, /*Explcit*/ false, /*Diagnose*/ false)) + S.CheckCXXThisCapture(CallLoc); + } else if (S.CurContext->isDependentContext()) { + // ... since this is an implicit member reference, that might potentially + // involve a 'this' capture, mark 'this' for potential capture in + // enclosing lambdas. + if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None) + CurLSI->addPotentialThisCapture(CallLoc); + } +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -5152,6 +5257,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } else { + + tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + *this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()), + Fn->getLocStart()); + return new (Context) CallExpr( Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } @@ -5651,8 +5761,8 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { case Type::STK_CPointer: { - unsigned SrcAS = SrcTy->getPointeeType().getAddressSpace(); - unsigned DestAS = DestTy->getPointeeType().getAddressSpace(); + LangAS SrcAS = SrcTy->getPointeeType().getAddressSpace(); + LangAS DestAS = DestTy->getPointeeType().getAddressSpace(); if (SrcAS != DestAS) return CK_AddressSpaceConversion; return CK_BitCast; @@ -5924,9 +6034,9 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // In OpenCL, casts between vectors of different types are not allowed. // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) - || (getLangOpts().OpenCL && - (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { + if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) || + (getLangOpts().OpenCL && + !Context.hasSameUnqualifiedType(DestTy, SrcTy))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; return ExprError(); @@ -6256,9 +6366,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, Qualifiers lhQual = lhptee.getQualifiers(); Qualifiers rhQual = rhptee.getQualifiers(); - unsigned ResultAddrSpace = 0; - unsigned LAddrSpace = lhQual.getAddressSpace(); - unsigned RAddrSpace = rhQual.getAddressSpace(); + LangAS ResultAddrSpace = LangAS::Default; + LangAS LAddrSpace = lhQual.getAddressSpace(); + LangAS RAddrSpace = rhQual.getAddressSpace(); if (S.getLangOpts().OpenCL) { // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address // spaces is disallowed. @@ -7132,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, commonExpr = commonRes.get(); } + // If the common expression is a class or array prvalue, materialize it + // so that we can safely refer to it multiple times. + if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() || + commonExpr->getType()->isArrayType())) { + ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr); + if (MatExpr.isInvalid()) + return ExprError(); + commonExpr = MatExpr.get(); + } + opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(), commonExpr->getType(), commonExpr->getValueKind(), @@ -7391,11 +7511,19 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, // usually happen on valid code. OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue); ExprResult RHSPtr = &RHSExpr; - CastKind K = CK_Invalid; + CastKind K; return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false); } +/// This helper function returns true if QT is a vector type that has element +/// type ElementType. +static bool isVector(QualType QT, QualType ElementType) { + if (const VectorType *VT = QT->getAs<VectorType>()) + return VT->getElementType() == ElementType; + return false; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -7514,6 +7642,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (unsupportedTypeConversion(*this, LHSType, RHSType)) return Incompatible; + // Disallow assigning a _Complex to a real type in C++ mode since it simply + // discards the imaginary part. + if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() && + !LHSType->getAs<ComplexType>()) + return Incompatible; + // Arithmetic conversions. if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { @@ -7526,8 +7660,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* if (isa<PointerType>(RHSType)) { - unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); - unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); + LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + LangAS AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -7562,10 +7696,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // U^ -> void* if (RHSType->getAs<BlockPointerType>()) { if (LHSPointer->getPointeeType()->isVoidType()) { - unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); - unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); + LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return Compatible; @@ -7579,12 +7713,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (isa<BlockPointerType>(LHSType)) { // U^ -> T^ if (RHSType->isBlockPointerType()) { - unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); - unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>() - ->getPointeeType() - .getAddressSpace(); + LangAS AddrSpaceL = LHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); + LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>() + ->getPointeeType() + .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -7769,7 +7903,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, } } - CastKind Kind = CK_Invalid; + CastKind Kind; if (CheckAssignmentConstraints(it->getType(), RHS, Kind) == Compatible) { RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind); @@ -7885,7 +8019,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, } } - CastKind Kind = CK_Invalid; + CastKind Kind; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); @@ -7980,7 +8114,7 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, unsigned &DiagID) { // The conversion to apply to the scalar before splatting it, // if necessary. - CastKind scalarCast = CK_Invalid; + CastKind scalarCast = CK_NoOp; if (vectorEltTy->isIntegralType(S.Context)) { if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() || @@ -8011,13 +8145,32 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, // Adjust scalar if desired. if (scalar) { - if (scalarCast != CK_Invalid) + if (scalarCast != CK_NoOp) *scalar = S.ImpCastExprToType(scalar->get(), vectorEltTy, scalarCast); *scalar = S.ImpCastExprToType(scalar->get(), vectorTy, CK_VectorSplat); } return false; } +/// Convert vector E to a vector with the same number of elements but different +/// element type. +static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) { + const auto *VecTy = E->getType()->getAs<VectorType>(); + assert(VecTy && "Expression E must be a vector"); + QualType NewVecTy = S.Context.getVectorType(ElementType, + VecTy->getNumElements(), + VecTy->getVectorKind()); + + // Look through the implicit cast. Return the subexpression if its type is + // NewVecTy. + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getSubExpr()->getType() == NewVecTy) + return ICE->getSubExpr(); + + auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast; + return S.ImpCastExprToType(E, NewVecTy, Cast); +} + /// Test if a (constant) integer Int can be casted to another integer type /// IntTy without losing precision. static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, @@ -8459,6 +8612,21 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, << 0 /* one pointer */ << Pointer->getSourceRange(); } +/// \brief Diagnose invalid arithmetic on a null pointer. +/// +/// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n' +/// idiom, which we recognize as a GNU extension. +/// +static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc, + Expr *Pointer, bool IsGNUIdiom) { + if (IsGNUIdiom) + S.Diag(Loc, diag::warn_gnu_null_ptr_arith) + << Pointer->getSourceRange(); + else + S.Diag(Loc, diag::warn_pointer_arith_null_ptr) + << S.getLangOpts().CPlusPlus << Pointer->getSourceRange(); +} + /// \brief Diagnose invalid arithmetic on two function pointers. static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS) { @@ -8753,6 +8921,21 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, if (!IExp->getType()->isIntegerType()) return InvalidOperands(Loc, LHS, RHS); + // Adding to a null pointer results in undefined behavior. + if (PExp->IgnoreParenCasts()->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNotNull)) { + // In C++ adding zero to a null pointer is defined. + llvm::APSInt KnownVal; + if (!getLangOpts().CPlusPlus || + (!IExp->isValueDependent() && + (!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) { + // Check the conditions to see if this is the 'p = nullptr + n' idiom. + bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension( + Context, BO_Add, PExp, IExp); + diagnoseArithmeticOnNullPointer(*this, Loc, PExp, IsGNUIdiom); + } + } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) return QualType(); @@ -8814,6 +8997,20 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, // The result type of a pointer-int computation is the pointer type. if (RHS.get()->getType()->isIntegerType()) { + // Subtracting from a null pointer should produce a warning. + // The last argument to the diagnose call says this doesn't match the + // GNU int-to-pointer idiom. + if (LHS.get()->IgnoreParenCasts()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) { + // In C++ adding zero to a null pointer is defined. + llvm::APSInt KnownVal; + if (!getLangOpts().CPlusPlus || + (!RHS.get()->isValueDependent() && + (!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) { + diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false); + } + } + if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get())) return QualType(); @@ -8849,6 +9046,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, LHS.get(), RHS.get())) return QualType(); + // FIXME: Add warnings for nullptr - ptr. + // The pointee type may have zero size. As an extension, a structure or // union may have zero size or an array may have zero length. In this // case subtraction does not make sense. @@ -9124,9 +9323,11 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, return; // Ignore anonymous enums. - if (!LHSEnumType->getDecl()->getIdentifier()) + if (!LHSEnumType->getDecl()->getIdentifier() && + !LHSEnumType->getDecl()->getTypedefNameForAnonDecl()) return; - if (!RHSEnumType->getDecl()->getIdentifier()) + if (!RHSEnumType->getDecl()->getIdentifier() && + !RHSEnumType->getDecl()->getTypedefNameForAnonDecl()) return; if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) @@ -9614,8 +9815,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } - unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace(); - unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace(); + LangAS AddrSpaceL = LCanPointeeTy.getAddressSpace(); + LangAS AddrSpaceR = RCanPointeeTy.getAddressSpace(); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; if (LHSIsNull && !RHSIsNull) @@ -10145,22 +10346,23 @@ static bool IsTypeModifiable(QualType Ty, bool IsDereference) { return !Ty.isConstQualified(); } +// Update err_typecheck_assign_const and note_typecheck_assign_const +// when this enum is changed. +enum { + ConstFunction, + ConstVariable, + ConstMember, + ConstMethod, + NestedConstMember, + ConstUnknown, // Keep as last element +}; + /// Emit the "read-only variable not assignable" error and print notes to give /// more information about why the variable is not assignable, such as pointing /// to the declaration of a const variable, showing that a method is const, or /// that the function is returning a const reference. static void DiagnoseConstAssignment(Sema &S, const Expr *E, SourceLocation Loc) { - // Update err_typecheck_assign_const and note_typecheck_assign_const - // when this enum is changed. - enum { - ConstFunction, - ConstVariable, - ConstMember, - ConstMethod, - ConstUnknown, // Keep as last element - }; - SourceRange ExprRange = E->getSourceRange(); // Only emit one error on the first const found. All other consts will emit @@ -10270,6 +10472,66 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown; } +enum OriginalExprKind { + OEK_Variable, + OEK_Member, + OEK_LValue +}; + +static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, + const RecordType *Ty, + SourceLocation Loc, SourceRange Range, + OriginalExprKind OEK, + bool &DiagnosticEmitted, + bool IsNested = false) { + // We walk the record hierarchy breadth-first to ensure that we print + // diagnostics in field nesting order. + // First, check every field for constness. + for (const FieldDecl *Field : Ty->getDecl()->fields()) { + if (Field->getType().isConstQualified()) { + if (!DiagnosticEmitted) { + S.Diag(Loc, diag::err_typecheck_assign_const) + << Range << NestedConstMember << OEK << VD + << IsNested << Field; + DiagnosticEmitted = true; + } + S.Diag(Field->getLocation(), diag::note_typecheck_assign_const) + << NestedConstMember << IsNested << Field + << Field->getType() << Field->getSourceRange(); + } + } + // Then, recurse. + for (const FieldDecl *Field : Ty->getDecl()->fields()) { + QualType FTy = Field->getType(); + if (const RecordType *FieldRecTy = FTy->getAs<RecordType>()) + DiagnoseRecursiveConstFields(S, VD, FieldRecTy, Loc, Range, + OEK, DiagnosticEmitted, true); + } +} + +/// Emit an error for the case where a record we are trying to assign to has a +/// const-qualified field somewhere in its hierarchy. +static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E, + SourceLocation Loc) { + QualType Ty = E->getType(); + assert(Ty->isRecordType() && "lvalue was not record?"); + SourceRange Range = E->getSourceRange(); + const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>(); + bool DiagEmitted = false; + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + DiagnoseRecursiveConstFields(S, ME->getMemberDecl(), RTy, Loc, + Range, OEK_Member, DiagEmitted); + else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + DiagnoseRecursiveConstFields(S, DRE->getDecl(), RTy, Loc, + Range, OEK_Variable, DiagEmitted); + else + DiagnoseRecursiveConstFields(S, nullptr, RTy, Loc, + Range, OEK_LValue, DiagEmitted); + if (!DiagEmitted) + DiagnoseConstAssignment(S, E, Loc); +} + /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { @@ -10345,6 +10607,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_ConstAddrSpace: DiagnoseConstAssignment(S, E, Loc); return true; + case Expr::MLV_ConstQualifiedField: + DiagnoseRecursiveConstFields(S, E, Loc); + return true; case Expr::MLV_ArrayType: case Expr::MLV_ArrayTemporary: DiagID = diag::err_typecheck_array_not_modifiable_lvalue; @@ -10654,7 +10919,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, return QualType(); } // Increment of bool sets it to true, but is deprecated. - S.Diag(OpLoc, S.getLangOpts().CPlusPlus1z ? diag::ext_increment_bool + S.Diag(OpLoc, S.getLangOpts().CPlusPlus17 ? diag::ext_increment_bool : diag::warn_increment_bool) << Op->getSourceRange(); } else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) { @@ -10838,10 +11103,17 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp.get()->IgnoreParens(); - // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. - if (LangOpts.OpenCL && op->getType()->isFunctionType()) { - Diag(op->getExprLoc(), diag::err_opencl_taking_function_address); - return QualType(); + // In OpenCL captures for blocks called as lambda functions + // are located in the private address space. Blocks used in + // enqueue_kernel can be located in a different address space + // depending on a vendor implementation. Thus preventing + // taking an address of the capture to avoid invalid AS casts. + if (LangOpts.OpenCL) { + auto* VarRef = dyn_cast<DeclRefExpr>(op); + if (VarRef && VarRef->refersToEnclosingVariableOrCapture()) { + Diag(op->getExprLoc(), diag::err_opencl_taking_address_capture); + return QualType(); + } } if (getLangOpts().C99) { @@ -11103,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) { case tok::greater: Opc = BO_GT; break; case tok::exclaimequal: Opc = BO_NE; break; case tok::equalequal: Opc = BO_EQ; break; + case tok::spaceship: Opc = BO_Cmp; break; case tok::amp: Opc = BO_And; break; case tok::caret: Opc = BO_Xor; break; case tok::pipe: Opc = BO_Or; break; @@ -11233,6 +11506,70 @@ static NamedDecl *getDeclFromExpr(Expr *E) { return nullptr; } +// This helper function promotes a binary operator's operands (which are of a +// half vector type) to a vector of floats and then truncates the result to +// a vector of either half or short. +static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, + BinaryOperatorKind Opc, QualType ResultTy, + ExprValueKind VK, ExprObjectKind OK, + bool IsCompAssign, SourceLocation OpLoc, + FPOptions FPFeatures) { + auto &Context = S.getASTContext(); + assert((isVector(ResultTy, Context.HalfTy) || + isVector(ResultTy, Context.ShortTy)) && + "Result must be a vector of half or short"); + assert(isVector(LHS.get()->getType(), Context.HalfTy) && + isVector(RHS.get()->getType(), Context.HalfTy) && + "both operands expected to be a half vector"); + + RHS = convertVector(RHS.get(), Context.FloatTy, S); + QualType BinOpResTy = RHS.get()->getType(); + + // If Opc is a comparison, ResultType is a vector of shorts. In that case, + // change BinOpResTy to a vector of ints. + if (isVector(ResultTy, Context.ShortTy)) + BinOpResTy = S.GetSignedVectorType(BinOpResTy); + + if (IsCompAssign) + return new (Context) CompoundAssignOperator( + LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, + OpLoc, FPFeatures); + + LHS = convertVector(LHS.get(), Context.FloatTy, S); + auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, + VK, OK, OpLoc, FPFeatures); + return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S); +} + +static std::pair<ExprResult, ExprResult> +CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, + Expr *RHSExpr) { + ExprResult LHS = LHSExpr, RHS = RHSExpr; + if (!S.getLangOpts().CPlusPlus) { + // C cannot handle TypoExpr nodes on either side of a binop because it + // doesn't handle dependent types properly, so make sure any TypoExprs have + // been dealt with before checking the operands. + LHS = S.CorrectDelayedTyposInExpr(LHS); + RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) { + if (Opc != BO_Assign) + return ExprResult(E); + // Avoid correcting the RHS to the same Expr as the LHS. + Decl *D = getDeclFromExpr(E); + return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; + }); + } + return std::make_pair(LHS, RHS); +} + +/// Returns true if conversion between vectors of halfs and vectors of floats +/// is needed. +static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, + QualType SrcType) { + return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && + !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && + isVector(SrcType, Ctx.HalfTy); +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -11264,22 +11601,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, QualType CompResultTy; // Type of computation result ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + bool ConvertHalfVec = false; - if (!getLangOpts().CPlusPlus) { - // C cannot handle TypoExpr nodes on either side of a binop because it - // doesn't handle dependent types properly, so make sure any TypoExprs have - // been dealt with before checking the operands. - LHS = CorrectDelayedTyposInExpr(LHSExpr); - RHS = CorrectDelayedTyposInExpr(RHSExpr, [Opc, LHS](Expr *E) { - if (Opc != BO_Assign) - return ExprResult(E); - // Avoid correcting the RHS to the same Expr as the LHS. - Decl *D = getDeclFromExpr(E); - return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; - }); - if (!LHS.isUsable() || !RHS.isUsable()) - return ExprError(); - } + std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprError(); if (getLangOpts().OpenCL) { QualType LHSTy = LHSExpr->getType(); @@ -11327,6 +11653,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_Mul: case BO_Div: + ConvertHalfVec = true; ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; @@ -11334,9 +11661,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: + ConvertHalfVec = true; ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc); break; case BO_Sub: + ConvertHalfVec = true; ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: @@ -11347,12 +11676,21 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_LT: case BO_GE: case BO_GT: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); break; case BO_EQ: case BO_NE: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; + case BO_Cmp: + // FIXME: Implement proper semantic checking of '<=>'. + ConvertHalfVec = true; + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); + if (!ResultTy.isNull()) + ResultTy = Context.VoidTy; + break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); LLVM_FALLTHROUGH; @@ -11362,10 +11700,12 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_LAnd: case BO_LOr: + ConvertHalfVec = true; ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: + ConvertHalfVec = true; CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; @@ -11379,11 +11719,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: + ConvertHalfVec = true; CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: + ConvertHalfVec = true; CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); @@ -11416,6 +11758,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + // Some of the binary operations require promoting operands of half vector to + // float vectors and truncating the result back to half vector. For now, we do + // this only when HalfArgsAndReturn is set (that is, when the target is arm or + // arm64). + assert(isVector(RHS.get()->getType(), Context.HalfTy) == + isVector(LHS.get()->getType(), Context.HalfTy) && + "both sides are half vectors or neither sides are"); + ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, + LHS.get()->getType()); + // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); @@ -11438,14 +11790,26 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts())) DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get()); - if (CompResultTy.isNull()) + // Opc is not a compound assignment if CompResultTy is null. + if (CompResultTy.isNull()) { + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, + OpLoc, FPFeatures); return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, FPFeatures); + } + + // Handle compound assignments. if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; OK = LHS.get()->getObjectKind(); } + + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, + OpLoc, FPFeatures); + return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc, FPFeatures); @@ -11693,6 +12057,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { + ExprResult LHS, RHS; + std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprError(); + LHSExpr = LHS.get(); + RHSExpr = RHS.get(); + // We want to end up calling one of checkPseudoObjectAssignment // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if // both expressions are overloadable or either is type-dependent), @@ -11796,6 +12167,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; + bool ConvertHalfVec = false; if (getLangOpts().OpenCL) { QualType Ty = InputExpr->getType(); // The only legal unary operation for atomics is '&'. @@ -11835,6 +12207,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Minus: Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); + // Unary plus and minus require promoting an operand of half vector to a + // float vector and truncating the result back to a half vector. For now, we + // do this only when HalfArgsAndReturns is set (that is, when the target is + // arm or arm64). + ConvertHalfVec = + needsConversionOfHalfVec(true, Context, Input.get()->getType()); + + // If the operand is a half vector, promote it to a float vector. + if (ConvertHalfVec) + Input = convertVector(Input.get(), Context.FloatTy, *this); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; @@ -11972,8 +12354,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); - return new (Context) + auto *UO = new (Context) UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc); + // Convert the result back to a half vector. + if (ConvertHalfVec) + return convertVector(UO, Context.HalfTy, *this); + return UO; } /// \brief Determine whether the given expression is a qualified member @@ -12211,15 +12597,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, && RequireCompleteType(BuiltinLoc, ArgTy, diag::err_offsetof_incomplete_type, TypeRange)) return ExprError(); - - // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a - // GCC extension, diagnose them. - // FIXME: This diagnostic isn't actually visible because the location is in - // a system header! - if (Components.size() != 1) - Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) - << SourceRange(Components[1].LocStart, Components.back().LocEnd); - + bool DidWarnAboutNonPOD = false; QualType CurrentType = ArgTy; SmallVector<OffsetOfNode, 4> Comps; @@ -12482,8 +12860,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, // Look for an explicit signature in that function type. FunctionProtoTypeLoc ExplicitSignature; - TypeLoc tmp = Sig->getTypeLoc().IgnoreParens(); - if ((ExplicitSignature = tmp.getAs<FunctionProtoTypeLoc>())) { + if ((ExplicitSignature = + Sig->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>())) { // Check whether that explicit signature was synthesized by // GetTypeForDeclarator. If so, don't save that as part of the @@ -13366,7 +13744,7 @@ void Sema::PopExpressionEvaluationContext() { // are part of function-signatures. Be mindful that P0315 (Lambdas in // unevaluated contexts) might lift some of these restrictions in a // future version. - if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus1z) + if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus17) for (const auto *L : Rec.Lambdas) Diag(L->getLocStart(), D); } else { @@ -13591,29 +13969,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { - bool AlreadyInstantiated = false; - SourceLocation PointOfInstantiation = Loc; - if (FunctionTemplateSpecializationInfo *SpecInfo - = Func->getTemplateSpecializationInfo()) { - if (SpecInfo->getPointOfInstantiation().isInvalid()) - SpecInfo->setPointOfInstantiation(Loc); - else if (SpecInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = SpecInfo->getPointOfInstantiation(); - } - } else if (MemberSpecializationInfo *MSInfo - = Func->getMemberSpecializationInfo()) { - if (MSInfo->getPointOfInstantiation().isInvalid()) - MSInfo->setPointOfInstantiation(Loc); - else if (MSInfo->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - AlreadyInstantiated = true; - PointOfInstantiation = MSInfo->getPointOfInstantiation(); - } + TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind(); + SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } else if (TSK != TSK_ImplicitInstantiation) { + // Use the point of use as the point of instantiation, instead of the + // point of explicit instantiation (which we track as the actual point of + // instantiation). This gives better backtraces in diagnostics. + PointOfInstantiation = Loc; } - if (!AlreadyInstantiated || Func->isConstexpr()) { + if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || + Func->isConstexpr()) { if (isa<CXXRecordDecl>(Func->getDeclContext()) && cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && CodeSynthesisContexts.size()) @@ -13650,6 +14020,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, !LangOpts.GNUInline && !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>()) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); + else if (isExternalWithNoLinkageType(Func)) + UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } Func->markUsed(Context); @@ -13973,8 +14345,13 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { - if (S.IsOpenMPCapturedDecl(Var)) + if (S.IsOpenMPCapturedDecl(Var)) { + bool HasConst = DeclRefType.isConstQualified(); DeclRefType = DeclRefType.getUnqualifiedType(); + // Don't lose diagnostics about assignments to const. + if (HasConst) + DeclRefType.addConst(); + } ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel); } @@ -13997,6 +14374,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); + if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) + S.setOpenMPCaptureKind(Field, Var, RSI->OpenMPLevel); CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); @@ -14167,6 +14546,7 @@ bool Sema::tryCaptureVariable( bool IsGlobal = !Var->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var))) return true; + Var = Var->getCanonicalDecl(); // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -14248,14 +14628,16 @@ bool Sema::tryCaptureVariable( // just break here. Similarly, global variables that are captured in a // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { - auto IsTargetCap = isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); + bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel); + auto IsTargetCap = !IsOpenMPPrivateDecl && + isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the // enclosing region. Therefore, the capture is not initially nested. if (IsTargetCap) - FunctionScopesIndex--; + adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel); - if (IsTargetCap || isOpenMPPrivateDecl(Var, RSI->OpenMPLevel)) { + if (IsTargetCap || IsOpenMPPrivateDecl) { Nested = !IsTargetCap; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); @@ -14451,9 +14833,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); bool OdrUseContext = isOdrUseContext(SemaRef); + bool UsableInConstantExpr = + Var->isUsableInConstantExpressions(SemaRef.Context); bool NeedDefinition = - OdrUseContext || (isEvaluatableContext(SemaRef) && - Var->isUsableInConstantExpressions(SemaRef.Context)); + OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr); VarTemplateSpecializationDecl *VarSpec = dyn_cast<VarTemplateSpecializationDecl>(Var); @@ -14472,24 +14855,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // instantiations of variable templates, except for those that could be used // in a constant expression. if (NeedDefinition && isTemplateInstantiation(TSK)) { - bool TryInstantiating = TSK == TSK_ImplicitInstantiation; - - if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) { - if (Var->getPointOfInstantiation().isInvalid()) { - // This is a modification of an existing AST node. Notify listeners. - if (ASTMutationListener *L = SemaRef.getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - } else if (!Var->isUsableInConstantExpressions(SemaRef.Context)) - // Don't bother trying to instantiate it again, unless we might need - // its initializer before we get to the end of the TU. - TryInstantiating = false; - } - - if (Var->getPointOfInstantiation().isInvalid()) - Var->setTemplateSpecializationKind(TSK, Loc); + // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit + // instantiation declaration if a variable is usable in a constant + // expression (among other cases). + bool TryInstantiating = + TSK == TSK_ImplicitInstantiation || + (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); if (TryInstantiating) { SourceLocation PointOfInstantiation = Var->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + bool InstantiationDependent = false; bool IsNonDependent = VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( @@ -14498,11 +14878,17 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // Do not instantiate specializations that are still type-dependent. if (IsNonDependent) { - if (Var->isUsableInConstantExpressions(SemaRef.Context)) { - // Do not defer instantiations of variables which could be used in a + if (UsableInConstantExpr) { + // Do not defer instantiations of variables that could be used in a // constant expression. SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); - } else { + } else if (FirstInstantiation || + isa<VarTemplateSpecializationDecl>(Var)) { + // FIXME: For a specialization of a variable template, we don't + // distinguish between "declaration and type implicitly instantiated" + // and "implicit instantiation of definition requested", so we have + // no direct way to avoid enqueueing the pending instantiation + // multiple times. SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } @@ -14522,7 +14908,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, IsVariableAConstantExpression(Var, SemaRef.Context)) { // A reference initialized by a constant expression can never be // odr-used, so simply ignore it. - if (!Var->getType()->isReferenceType()) + if (!Var->getType()->isReferenceType() || + (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var))) SemaRef.MaybeODRUseExprs.insert(E); } else if (OdrUseContext) { MarkVarDeclODRUsed(Var, Loc, SemaRef, @@ -14595,7 +14982,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, ME->getBase(), SemaRef.getLangOpts().AppleKext); if (DM) SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); -} +} /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { @@ -14810,10 +15197,24 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); + return true; } - else - Diag(Loc, PD); - + + // The initializer of a constexpr variable or of the first declaration of a + // static data member is not syntactically a constant evaluated constant, + // but nonetheless is always required to be a constant expression, so we + // can skip diagnosing. + // FIXME: Using the mangling context here is a hack. + if (auto *VD = dyn_cast_or_null<VarDecl>( + ExprEvalContexts.back().ManglingContextDecl)) { + if (VD->isConstexpr() || + (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) + break; + // FIXME: For any other kind of variable, we should build a CFG for its + // initializer and check whether the context in question is reachable. + } + + Diag(Loc, PD); return true; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index a9cf3ec7990b2..9c842ded1e101 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -1377,9 +1378,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, /// \brief Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { - if (FD->isInvalidDecl()) - return false; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) return Method->isUsualDeallocationFunction(); @@ -1409,14 +1407,20 @@ namespace { UsualDeallocFnInfo() : Found(), FD(nullptr) {} UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) : Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())), - HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { + Destroying(false), HasSizeT(false), HasAlignValT(false), + CUDAPref(Sema::CFP_Native) { // A function template declaration is never a usual deallocation function. if (!FD) return; - if (FD->getNumParams() == 3) + unsigned NumBaseParams = 1; + if (FD->isDestroyingOperatorDelete()) { + Destroying = true; + ++NumBaseParams; + } + if (FD->getNumParams() == NumBaseParams + 2) HasAlignValT = HasSizeT = true; - else if (FD->getNumParams() == 2) { - HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType(); + else if (FD->getNumParams() == NumBaseParams + 1) { + HasSizeT = FD->getParamDecl(NumBaseParams)->getType()->isIntegerType(); HasAlignValT = !HasSizeT; } @@ -1430,6 +1434,12 @@ namespace { bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { + // C++ P0722: + // A destroying operator delete is preferred over a non-destroying + // operator delete. + if (Destroying != Other.Destroying) + return Destroying; + // C++17 [expr.delete]p10: // If the type has new-extended alignment, a function with a parameter // of type std::align_val_t is preferred; otherwise a function without @@ -1446,7 +1456,7 @@ namespace { DeclAccessPair Found; FunctionDecl *FD; - bool HasSizeT, HasAlignValT; + bool Destroying, HasSizeT, HasAlignValT; Sema::CUDAFunctionPreference CUDAPref; }; } @@ -1660,9 +1670,13 @@ static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, bool IsAligned = false; if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { + const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); + StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()); + S.Diag(Loc, diag::warn_aligned_allocation_unavailable) - << IsDelete << FD.getType().getAsString() - << S.getASTContext().getTargetInfo().getTriple().str(); + << IsDelete << FD.getType().getAsString() << OSName + << alignedAllocMinVersion(T.getOS()).getAsString(); S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); } } @@ -1734,20 +1748,27 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (AllocType.isNull()) return ExprError(); } else if (Deduced) { + bool Braced = (initStyle == CXXNewExpr::ListInit); + if (NumInits == 1) { + if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) { + Inits = p->getInits(); + NumInits = p->getNumInits(); + Braced = true; + } + } + if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); - if (initStyle == CXXNewExpr::ListInit || - (NumInits == 1 && isa<InitListExpr>(Inits[0]))) - return ExprError(Diag(Inits[0]->getLocStart(), - diag::err_auto_new_list_init) - << AllocType << TypeRange); if (NumInits > 1) { Expr *FirstBad = Inits[1]; return ExprError(Diag(FirstBad->getLocStart(), diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } + if (Braced && !getLangOpts().CPlusPlus17) + Diag(Initializer->getLocStart(), diag::ext_auto_new_list_init) + << AllocType << TypeRange; Expr *Deduce = Inits[0]; QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) @@ -2099,7 +2120,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - else if (AllocType.getAddressSpace()) + else if (AllocType.getAddressSpace() != LangAS::Default) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); @@ -3171,7 +3192,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); - if (Pointee.getAddressSpace()) + if (Pointee.getAddressSpace() != LangAS::Default) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() @@ -3259,16 +3280,39 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, MarkFunctionReferenced(StartLoc, OperatorDelete); - // Check access and ambiguity of operator delete and destructor. + // Check access and ambiguity of destructor if we're going to call it. + // Note that this is required even for a virtual delete. + bool IsVirtualDelete = false; if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { - CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, - PDiag(diag::err_access_dtor) << PointeeElem); + CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, + PDiag(diag::err_access_dtor) << PointeeElem); + IsVirtualDelete = Dtor->isVirtual(); } } diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this); + + // Convert the operand to the type of the first parameter of operator + // delete. This is only necessary if we selected a destroying operator + // delete that we are going to call (non-virtually); converting to void* + // is trivial and left to AST consumers to handle. + QualType ParamType = OperatorDelete->getParamDecl(0)->getType(); + if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) { + Qualifiers Qs = Pointee.getQualifiers(); + if (Qs.hasCVRQualifiers()) { + // Qualifiers are irrelevant to this conversion; we're only looking + // for access and ambiguity. + Qs.removeCVRQualifiers(); + QualType Unqual = Context.getPointerType( + Context.getQualifiedType(Pointee.getUnqualifiedType(), Qs)); + Ex = ImpCastExprToType(Ex.get(), Unqual, CK_NoOp); + } + Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing); + if (Ex.isInvalid()) + return ExprError(); + } } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( @@ -3282,7 +3326,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { - if (!dtor || dtor->isVirtual() || !CallCanBeVirtual) + if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext()) return; // C++ [expr.delete]p3: @@ -3297,6 +3341,12 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>()) return; + // If the superclass is in a system header, there's nothing that can be done. + // The `delete` (where we emit the warning) can be in a system header, + // what matters for this warning is where the deleted type is defined. + if (getSourceManager().isInSystemHeader(PointeeRD->getLocation())) + return; + QualType ClassType = dtor->getThisType(Context)->getPointeeType(); if (PointeeRD->isAbstract()) { // If the class is abstract, we warn by default, because we're @@ -3797,7 +3847,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, << From->getSourceRange(); } - CastKind Kind = CK_Invalid; + CastKind Kind; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); @@ -3817,7 +3867,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Pointer_Member: { - CastKind Kind = CK_Invalid; + CastKind Kind; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); @@ -4141,6 +4191,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: + case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; @@ -4580,6 +4631,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); + case UTT_HasUniqueObjectRepresentations: + return C.hasUniqueObjectRepresentations(T); } } @@ -4790,9 +4843,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); - case BTT_TypeCompatible: - return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), - RhsT.getUnqualifiedType()); + case BTT_TypeCompatible: { + // GCC ignores cv-qualifiers on arrays for this builtin. + Qualifiers LhsQuals, RhsQuals; + QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals); + QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals); + return Self.Context.typesAreCompatible(Lhs, Rhs); + } case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: @@ -5173,9 +5230,16 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, break; case RQ_LValue: - if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) - Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RHSType << 1 << LHS.get()->getSourceRange(); + if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { + // C++2a allows functions with ref-qualifier & if they are also 'const'. + if (Proto->isConst()) + Diag(Loc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue + : diag::ext_pointer_to_const_ref_member_on_rvalue); + else + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RHSType << 1 << LHS.get()->getSourceRange(); + } break; case RQ_RValue: @@ -5702,7 +5766,7 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, // happen in C++17, because it would mean we were computing the composite // pointer type of dependent types, which should never happen. if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { - assert(!S.getLangOpts().CPlusPlus1z && + assert(!S.getLangOpts().CPlusPlus17 && "computing composite pointer type of dependent types"); return FunctionProtoType::ExceptionSpecInfo(); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index c3d0e2db76b67..03ddcc0a3eca9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp @@ -384,7 +384,9 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, } } - if (!HalvingSwizzle) { + // OpenCL mode requires swizzle length to be in accordance with accepted + // sizes. Clang however supports arbitrary lengths for other languages. + if (S.getLangOpts().OpenCL && !HalvingSwizzle) { unsigned SwizzleLength = CompName->getLength(); if (HexSwizzle) @@ -693,8 +695,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Sema::RedeclarationKind Redecl; }; QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(), - R.isForRedeclaration() ? Sema::ForRedeclaration - : Sema::NotForRedeclaration}; + R.redeclarationKind()}; TE = SemaRef.CorrectTypoDelayed( R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, llvm::make_unique<RecordMemberExprValidatorCCC>(RTy), @@ -1001,53 +1002,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, BaseExpr = Converted.get(); } - LambdaScopeInfo *const CurLSI = getCurLambda(); - // If this is an implicit member reference and the overloaded - // name refers to both static and non-static member functions - // (i.e. BaseExpr is null) and if we are currently processing a lambda, - // check if we should/can capture 'this'... - // Keep this example in mind: - // struct X { - // void f(int) { } - // static void f(double) { } - // - // int g() { - // auto L = [=](auto a) { - // return [](int i) { - // return [=](auto b) { - // f(b); - // //f(decltype(a){}); - // }; - // }; - // }; - // auto M = L(0.0); - // auto N = M(3); - // N(5.32); // OK, must not error. - // return 0; - // } - // }; - // - if (!BaseExpr && CurLSI) { - SourceLocation Loc = R.getNameLoc(); - if (SS.getRange().isValid()) - Loc = SS.getRange().getBegin(); - DeclContext *EnclosingFunctionCtx = CurContext->getParent()->getParent(); - // If the enclosing function is not dependent, then this lambda is - // capture ready, so if we can capture this, do so. - if (!EnclosingFunctionCtx->isDependentContext()) { - // If the current lambda and all enclosing lambdas can capture 'this' - - // then go ahead and capture 'this' (since our unresolved overload set - // contains both static and non-static member functions). - if (!CheckCXXThisCapture(Loc, /*Explcit*/false, /*Diagnose*/false)) - CheckCXXThisCapture(Loc); - } else if (CurContext->isDependentContext()) { - // ... since this is an implicit member reference, that might potentially - // involve a 'this' capture, mark 'this' for potential capture in - // enclosing lambdas. - if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None) - CurLSI->addPotentialThisCapture(Loc); - } - } + const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); DeclarationName MemberName = MemberNameInfo.getName(); SourceLocation MemberLoc = MemberNameInfo.getLoc(); @@ -1836,7 +1791,9 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, MemberType = Context.getQualifiedType(MemberType, Combined); } - UnusedPrivateFields.remove(Field); + auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); + if (!(CurMethod && CurMethod->isDefaulted())) + UnusedPrivateFields.remove(Field); ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), FoundDecl, Field); @@ -1848,8 +1805,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, if (getLangOpts().OpenMP && IsArrow && !CurContext->isDependentContext() && isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) { - if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) - return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); + if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) { + return getOpenMPCapturedExpr(PrivateCopy, VK, OK, + MemberNameInfo.getLoc()); + } } return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 28581bad1a7a4..6ed5047c35daa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -564,6 +564,13 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { BoxingMethod = StringWithUTF8StringMethod; BoxedType = NSStringPointer; + // Transfer the nullability from method's return type. + Optional<NullabilityKind> Nullability = + BoxingMethod->getReturnType()->getNullability(Context); + if (Nullability) + BoxedType = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*Nullability), BoxedType, + BoxedType); } } else if (ValueType->isBuiltinType()) { // The other types we support are numeric, char and BOOL/bool. We could also @@ -2705,6 +2712,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } + if (ReceiverType->isObjCIdType() && !isImplicit) + Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id); + // There's a somewhat weird interaction here where we assume that we // won't actually have a method unless we also don't need to do some // of the more detailed type-checking on the receiver. @@ -4314,14 +4324,37 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType, /// Look for an ObjCReclaimReturnedObject cast and destroy it. static Expr *maybeUndoReclaimObject(Expr *e) { - // For now, we just undo operands that are *immediately* reclaim - // expressions, which prevents the vast majority of potential - // problems here. To catch them all, we'd need to rebuild arbitrary - // value-propagating subexpressions --- we can't reliably rebuild - // in-place because of expression sharing. - if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) - if (ice->getCastKind() == CK_ARCReclaimReturnedObject) - return ice->getSubExpr(); + Expr *curExpr = e, *prevExpr = nullptr; + + // Walk down the expression until we hit an implicit cast of kind + // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast. + while (true) { + if (auto *pe = dyn_cast<ParenExpr>(curExpr)) { + prevExpr = curExpr; + curExpr = pe->getSubExpr(); + continue; + } + + if (auto *ce = dyn_cast<CastExpr>(curExpr)) { + if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) + if (ice->getCastKind() == CK_ARCReclaimReturnedObject) { + if (!prevExpr) + return ice->getSubExpr(); + if (auto *pe = dyn_cast<ParenExpr>(prevExpr)) + pe->setSubExpr(ice->getSubExpr()); + else + cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr()); + return e; + } + + prevExpr = curExpr; + curExpr = ce->getSubExpr(); + continue; + } + + // Break out of the loop if curExpr is neither a Paren nor a Cast. + break; + } return e; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index 32024cb335dc3..e4789cdf53bfb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -826,6 +826,34 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } +/// Determine whether Entity is an entity for which it is idiomatic to elide +/// the braces in aggregate initialization. +static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { + // Recursive initialization of the one and only field within an aggregate + // class is considered idiomatic. This case arises in particular for + // initialization of std::array, where the C++ standard suggests the idiom of + // + // std::array<T, N> arr = {1, 2, 3}; + // + // (where std::array is an aggregate struct containing a single array field. + + // FIXME: Should aggregate initialization of a struct with a single + // base class and no members also suppress the warning? + if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent()) + return false; + + auto *ParentRD = + Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); + if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) + if (CXXRD->getNumBases()) + return false; + + auto FieldIt = ParentRD->field_begin(); + assert(FieldIt != ParentRD->field_end() && + "no fields but have initializer for member?"); + return ++FieldIt == ParentRD->field_end(); +} + /// Check whether the range of the initializer \p ParentIList from element /// \p Index onwards can be used to initialize an object of type \p T. Update /// \p Index to indicate how many elements of the list were consumed. @@ -886,7 +914,9 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, } // Complain about missing braces. - if (T->isArrayType() || T->isRecordType()) { + if ((T->isArrayType() || T->isRecordType()) && + !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + !isIdiomaticBraceElisionEntity(Entity)) { SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() @@ -1833,7 +1863,9 @@ void InitListChecker::CheckStructUnionTypes( // worthwhile to skip over the rest of the initializer, though. RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); - bool CheckForMissingFields = true; + bool CheckForMissingFields = + !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); + while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); @@ -3531,12 +3563,13 @@ static OverloadingResult ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, MultiExprArg Args, OverloadCandidateSet &CandidateSet, + QualType DestType, DeclContext::lookup_result Ctors, OverloadCandidateSet::iterator &Best, bool CopyInitializing, bool AllowExplicit, bool OnlyListConstructors, bool IsListInit, bool SecondStepOfCopyInit = false) { - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor); for (NamedDecl *D : Ctors) { auto Info = getConstructorInfo(D); @@ -3587,6 +3620,50 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, } } + // FIXME: Work around a bug in C++17 guaranteed copy elision. + // + // When initializing an object of class type T by constructor + // ([over.match.ctor]) or by list-initialization ([over.match.list]) + // from a single expression of class type U, conversion functions of + // U that convert to the non-reference type cv T are candidates. + // Explicit conversion functions are only candidates during + // direct-initialization. + // + // Note: SecondStepOfCopyInit is only ever true in this case when + // evaluating whether to produce a C++98 compatibility warning. + if (S.getLangOpts().CPlusPlus17 && Args.size() == 1 && + !SecondStepOfCopyInit) { + Expr *Initializer = Args[0]; + auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl(); + if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) { + const auto &Conversions = SourceRD->getVisibleConversionFunctions(); + for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + D = D->getUnderlyingDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(D); + + if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), + ActingDC, Initializer, DestType, + CandidateSet, AllowExplicit, + /*AllowResultConversion*/false); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, + DestType, CandidateSet, AllowExplicit, + /*AllowResultConversion*/false); + } + } + } + } + // Perform overload resolution and return the result. return CandidateSet.BestViableFunction(S, DeclLoc, Best); } @@ -3624,7 +3701,7 @@ static void TryConstructorInitialization(Sema &S, return; } - // C++1z [dcl.init]p17: + // C++17 [dcl.init]p17: // - If the initializer expression is a prvalue and the cv-unqualified // version of the source type is the same class as the class of the // destination, the initializer expression is used to initialize the @@ -3633,7 +3710,7 @@ static void TryConstructorInitialization(Sema &S, // class or delegating to another constructor from a mem-initializer. // ObjC++: Lambda captured by the block in the lambda to block conversion // should avoid copy elision. - if (S.getLangOpts().CPlusPlus1z && + if (S.getLangOpts().CPlusPlus17 && Entity.getKind() != InitializedEntity::EK_Base && Entity.getKind() != InitializedEntity::EK_Delegating && Entity.getKind() != @@ -3686,7 +3763,7 @@ static void TryConstructorInitialization(Sema &S, // the first phase is omitted. if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor())) Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, - CandidateSet, Ctors, Best, + CandidateSet, DestType, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, IsListInit); @@ -3700,7 +3777,7 @@ static void TryConstructorInitialization(Sema &S, if (Result == OR_No_Viable_Function) { AsInitializerList = false; Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs, - CandidateSet, Ctors, Best, + CandidateSet, DestType, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, IsListInit); @@ -3713,6 +3790,24 @@ static void TryConstructorInitialization(Sema &S, return; } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + + // In C++17, ResolveConstructorOverload can select a conversion function + // instead of a constructor. + if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) { + // Add the user-defined conversion step that calls the conversion function. + QualType ConvType = CD->getConversionType(); + assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) && + "should not have selected this conversion function"); + Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType, + HadMultipleCandidates); + if (!S.Context.hasSameType(ConvType, DestType)) + Sequence.AddQualificationConversionStep(DestType, VK_RValue); + if (IsListInit) + Sequence.RewrapReferenceInitList(Entity.getType(), ILE); + return; + } + // C++11 [dcl.init]p6: // If a program calls for the default initialization of an object // of a const-qualified type T, T shall be a class type with a @@ -3741,7 +3836,6 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. - bool HadMultipleCandidates = (CandidateSet.size() > 1); Sequence.AddConstructorInitializationStep( Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates, IsListInit | IsInitListCopy, AsInitializerList); @@ -3984,7 +4078,7 @@ static void TryListInitialization(Sema &S, // value T(v); if a narrowing conversion is required to convert v to // the underlying type of T, the program is ill-formed. auto *ET = DestType->getAs<EnumType>(); - if (S.getLangOpts().CPlusPlus1z && + if (S.getLangOpts().CPlusPlus17 && Kind.getKind() == InitializationKind::IK_DirectList && ET && ET->getDecl()->isFixed() && !S.Context.hasSameUnqualifiedType(E->getType(), DestType) && @@ -4087,7 +4181,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. @@ -4173,7 +4267,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) return Result; FunctionDecl *Function = Best->Function; @@ -4417,7 +4511,7 @@ static void TryReferenceInitializationCore(Sema &S, RefRelationship == Sema::Ref_Related)) && ((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) || (InitCategory.isPRValue() && - (S.getLangOpts().CPlusPlus1z || T2->isRecordType() || + (S.getLangOpts().CPlusPlus17 || T2->isRecordType() || T2->isArrayType())))) { ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_RValue; if (InitCategory.isPRValue() && T2->isRecordType()) { @@ -4687,7 +4781,7 @@ static void TryUserDefinedConversion(Sema &S, // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. @@ -4766,7 +4860,7 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); @@ -4793,7 +4887,7 @@ static void TryUserDefinedConversion(Sema &S, // copy-initialization. // Note that this just performs a simple object copy from the temporary. // - // C++1z: + // C++17: // - if the function is a constructor, the call is a prvalue of the // cv-unqualified version of the destination type whose return object // is initialized by the constructor. The call is used to @@ -4802,7 +4896,7 @@ static void TryUserDefinedConversion(Sema &S, // Therefore we need to do nothing further. // // FIXME: Mark this copy as extraneous. - if (!S.getLangOpts().CPlusPlus1z) + if (!S.getLangOpts().CPlusPlus17) Sequence.AddFinalCopy(DestType); else if (DestType.hasQualifiers()) Sequence.AddQualificationConversionStep(DestType, VK_RValue); @@ -4818,13 +4912,13 @@ static void TryUserDefinedConversion(Sema &S, // The call is used to direct-initialize [...] the object that is the // destination of the copy-initialization. // - // In C++1z, this does not call a constructor if we enter /17.6.1: + // In C++17, this does not call a constructor if we enter /17.6.1: // - If the initializer expression is a prvalue and the cv-unqualified // version of the source type is the same as the class of the // destination [... do not make an extra copy] // // FIXME: Mark this copy as extraneous. - if (!S.getLangOpts().CPlusPlus1z || + if (!S.getLangOpts().CPlusPlus17 || Function->getReturnType()->isReferenceType() || !S.Context.hasSameUnqualifiedType(ConvType, DestType)) Sequence.AddFinalCopy(DestType); @@ -5657,7 +5751,7 @@ static ExprResult CopyObject(Sema &S, OverloadCandidateSet::iterator Best; switch (ResolveConstructorOverload( - S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, /*SecondStepOfCopyInit=*/true)) { @@ -5797,7 +5891,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, // Perform overload resolution. OverloadCandidateSet::iterator Best; OverloadingResult OR = ResolveConstructorOverload( - S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, /*SecondStepOfCopyInit=*/true); @@ -6328,6 +6422,10 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr, if (!VD || !VD->hasLocalStorage()) return; + // __block variables are not moved implicitly. + if (VD->hasAttr<BlocksAttr>()) + return; + QualType SourceType = VD->getType(); if (!SourceType->isRecordType()) return; @@ -7535,8 +7633,7 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; OverloadingResult Ovl - = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best, - true); + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl == OR_Deleted) { S.NoteDeletedFunction(Best->Function); } else { @@ -8339,6 +8436,16 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, return Result; } +/// Determine whether RD is, or is derived from, a specialization of CTD. +static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD, + ClassTemplateDecl *CTD) { + auto NotSpecialization = [&] (const CXXRecordDecl *Candidate) { + auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Candidate); + return !CTSD || !declaresSameEntity(CTSD->getSpecializedTemplate(), CTD); + }; + return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization)); +} + QualType Sema::DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TSInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Inits) { @@ -8405,7 +8512,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( OverloadCandidateSet::iterator Best; auto tryToResolveOverload = [&](bool OnlyListConstructors) -> OverloadingResult { - Candidates.clear(); + Candidates.clear(OverloadCandidateSet::CSK_Normal); for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); if (D->isInvalidDecl()) @@ -8483,6 +8590,17 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( break; } } + } else if (ListInit->getNumInits() == 1) { + // C++ [over.match.class.deduct]: + // As an exception, the first phase in [over.match.list] (considering + // initializer-list constructors) is omitted if the initializer list + // consists of a single expression of type cv U, where U is a + // specialization of C or a class derived from a specialization of C. + Expr *E = ListInit->getInit(0); + auto *RD = E->getType()->getAsCXXRecordDecl(); + if (!isa<InitListExpr>(E) && RD && + isOrIsDerivedFromSpecializationOf(RD, Template)) + TryListConstructors = false; } if (TryListConstructors) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp index b0b7e64711f64..cbfc330ca60b2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp @@ -288,7 +288,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, Normal, DefaultArgument, DataMember, - StaticDataMember + StaticDataMember, + InlineVariable, + VariableTemplate } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -303,6 +305,14 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, } else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) { if (Var->getDeclContext()->isRecord()) Kind = StaticDataMember; + else if (Var->getMostRecentDecl()->isInline()) + Kind = InlineVariable; + else if (Var->getDescribedVarTemplate()) + Kind = VariableTemplate; + else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) { + if (!VTS->isExplicitSpecialization()) + Kind = VariableTemplate; + } } else if (isa<FieldDecl>(ManglingContextDecl)) { Kind = DataMember; } @@ -343,6 +353,10 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, // -- the in-class initializers of class members case DefaultArgument: // -- default arguments appearing in class definitions + case InlineVariable: + // -- the initializers of inline variables + case VariableTemplate: + // -- the initializers of templated variables return &ExprEvalContexts.back().getMangleNumberingContext(Context); } @@ -933,8 +947,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, PrevCaptureLoc = C->Loc, ++C) { if (C->Kind == LCK_This || C->Kind == LCK_StarThis) { if (C->Kind == LCK_StarThis) - Diag(C->Loc, !getLangOpts().CPlusPlus1z - ? diag::ext_star_this_lambda_capture_cxx1z + Diag(C->Loc, !getLangOpts().CPlusPlus17 + ? diag::ext_star_this_lambda_capture_cxx17 : diag::warn_cxx14_compat_star_this_lambda_capture); // C++11 [expr.prim.lambda]p8: @@ -948,17 +962,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // C++1z [expr.prim.lambda]p8: - // If a lambda-capture includes a capture-default that is =, each - // simple-capture of that lambda-capture shall be of the form "& - // identifier" or "* this". [ Note: The form [&,this] is redundant but - // accepted for compatibility with ISO C++14. --end note ] - if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) { - Diag(C->Loc, diag::err_this_capture_with_copy_default) - << FixItHint::CreateRemoval( - SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); - continue; - } + // C++2a [expr.prim.lambda]p8: + // If a lambda-capture includes a capture-default that is =, + // each simple-capture of that lambda-capture shall be of the form + // "&identifier", "this", or "* this". [ Note: The form [&,this] is + // redundant but accepted for compatibility with ISO C++14. --end note ] + if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) + Diag(C->Loc, !getLangOpts().CPlusPlus2a + ? diag::ext_equals_this_lambda_capture_cxx2a + : diag::warn_cxx17_compat_equals_this_lambda_capture); // C++11 [expr.prim.lambda]p12: // If this is captured by a local lambda expression, its nearest @@ -1276,7 +1288,7 @@ static void addFunctionPointerConversion(Sema &S, ConvTy, ConvTSI, /*isInline=*/true, /*isExplicit=*/false, - /*isConstexpr=*/S.getLangOpts().CPlusPlus1z, + /*isConstexpr=*/S.getLangOpts().CPlusPlus17, CallOperator->getBody()->getLocEnd()); Conversion->setAccess(AS_public); Conversion->setImplicit(true); @@ -1599,7 +1611,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // If the lambda expression's call operator is not explicitly marked constexpr // and we are not in a dependent context, analyze the call operator to infer // its constexpr-ness, suppressing diagnostics while doing so. - if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && + if (getLangOpts().CPlusPlus17 && !CallOperator->isInvalidDecl() && !CallOperator->isConstexpr() && !isa<CoroutineBodyStmt>(CallOperator->getBody()) && !Class->getDeclContext()->isDependentContext()) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 85596ed52e9d6..d3f91a4e273d2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -88,13 +88,15 @@ namespace { /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { + Sema &SemaRef; + typedef SmallVector<UnqualUsingEntry, 8> ListTy; ListTy list; llvm::SmallPtrSet<DeclContext*, 8> visited; public: - UnqualUsingDirectiveSet() {} + UnqualUsingDirectiveSet(Sema &SemaRef) : SemaRef(SemaRef) {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { // C++ [namespace.udir]p1: @@ -113,7 +115,8 @@ namespace { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { for (auto *I : S->using_directives()) - visit(I, InnermostFileDC); + if (SemaRef.isVisible(I)) + visit(I, InnermostFileDC); } } } @@ -152,7 +155,7 @@ namespace { while (true) { for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); - if (visited.insert(NS).second) { + if (SemaRef.isVisible(UD) && visited.insert(NS).second) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } @@ -1031,7 +1034,8 @@ struct FindLocalExternScope { FindLocalExternScope(LookupResult &R) : R(R), OldFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_LocalExtern) { - R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary); + R.setFindLocalExtern(R.getIdentifierNamespace() & + (Decl::IDNS_Ordinary | Decl::IDNS_NonMemberOperator)); } void restore() { R.setFindLocalExtern(OldFindLocalExtern); @@ -1084,7 +1088,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // - UnqualUsingDirectiveSet UDirs; + UnqualUsingDirectiveSet UDirs(*this); bool VisitedUsingDirectives = false; bool LeftStartingScope = false; DeclContext *OutsideOfTemplateParamDC = nullptr; @@ -1370,7 +1374,7 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) { // Walk up to the containing context. That might also have been instantiated // from a template. - DeclContext *Context = Entity->getDeclContext(); + DeclContext *Context = Entity->getLexicalDeclContext(); if (Context->isFileContext()) return S.getOwningModule(Entity); return getDefiningModule(S, cast<Decl>(Context)); @@ -1608,11 +1612,39 @@ bool Sema::isVisibleSlow(const NamedDecl *D) { } bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { + // FIXME: If there are both visible and hidden declarations, we need to take + // into account whether redeclaration is possible. Example: + // + // Non-imported module: + // int f(T); // #1 + // Some TU: + // static int f(U); // #2, not a redeclaration of #1 + // int f(T); // #3, finds both, should link with #1 if T != U, but + // // with #2 if T == U; neither should be ambiguous. for (auto *D : R) { if (isVisible(D)) return true; + assert(D->isExternallyDeclarable() && + "should not have hidden, non-externally-declarable result here"); } - return New->isExternallyVisible(); + + // This function is called once "New" is essentially complete, but before a + // previous declaration is attached. We can't query the linkage of "New" in + // general, because attaching the previous declaration can change the + // linkage of New to match the previous declaration. + // + // However, because we've just determined that there is no *visible* prior + // declaration, we can compute the linkage here. There are two possibilities: + // + // * This is not a redeclaration; it's safe to compute the linkage now. + // + // * This is a redeclaration of a prior declaration that is externally + // redeclarable. In that case, the linkage of the declaration is not + // changed by attaching the prior declaration, because both are externally + // declarable (and thus ExternalLinkage or VisibleNoLinkage). + // + // FIXME: This is subtle and fragile. + return New->isExternallyDeclarable(); } /// \brief Retrieve the visible declaration corresponding to D, if any. @@ -1839,22 +1871,19 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); - DeclContext::udir_range UsingDirectives = StartDC->using_directives(); - if (UsingDirectives.begin() == UsingDirectives.end()) return false; + // We have not yet looked into these namespaces, much less added + // their "using-children" to the queue. + SmallVector<NamespaceDecl*, 8> Queue; // We have at least added all these contexts to the queue. llvm::SmallPtrSet<DeclContext*, 8> Visited; Visited.insert(StartDC); - // We have not yet looked into these namespaces, much less added - // their "using-children" to the queue. - SmallVector<NamespaceDecl*, 8> Queue; - // We have already looked into the initial namespace; seed the queue // with its using-children. - for (auto *I : UsingDirectives) { + for (auto *I : StartDC->using_directives()) { NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); - if (Visited.insert(ND).second) + if (S.isVisible(I) && Visited.insert(ND).second) Queue.push_back(ND); } @@ -1902,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, for (auto I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); - if (Visited.insert(Nom).second) + if (S.isVisible(I) && Visited.insert(Nom).second) Queue.push_back(Nom); } } @@ -3121,7 +3150,7 @@ Sema::LiteralOperatorLookupResult Sema::LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef<QualType> ArgTys, bool AllowRaw, bool AllowTemplate, - bool AllowStringTemplate) { + bool AllowStringTemplate, bool DiagnoseMissing) { LookupName(R, S); assert(R.getResultKind() != LookupResult::Ambiguous && "literal operator lookup can't be ambiguous"); @@ -3222,11 +3251,15 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, return LOLR_StringTemplate; // Didn't find anything we could use. - Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) - << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] - << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw - << (AllowTemplate || AllowStringTemplate); - return LOLR_Error; + if (DiagnoseMissing) { + Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) + << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] + << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw + << (AllowTemplate || AllowStringTemplate); + return LOLR_Error; + } + + return LOLR_ErrorNoDiagnostic; } void ADLResult::insert(NamedDecl *New) { @@ -3316,16 +3349,24 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, continue; } - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); + auto *Underlying = D; + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) + Underlying = USD->getTargetDecl(); - if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) + if (!isa<FunctionDecl>(Underlying) && + !isa<FunctionTemplateDecl>(Underlying)) continue; - if (!isVisible(D) && !(D = findAcceptableDecl(*this, D))) - continue; + if (!isVisible(D)) { + D = findAcceptableDecl(*this, D); + if (!D) + continue; + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) + Underlying = USD->getTargetDecl(); + } - Result.insert(D); + // FIXME: Preserve D as the FoundDecl. + Result.insert(Underlying); } } } @@ -3507,6 +3548,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); for (auto I : Ctx->using_directives()) { + if (!Result.getSema().isVisible(I)) + continue; LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited, IncludeDependentBases); @@ -3634,8 +3677,10 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, !Visited.alreadyVisitedContext(S->getEntity())) || (S->getEntity())->isFunctionOrMethod()) { FindLocalExternScope FindLocals(Result); - // Walk through the declarations in this Scope. - for (auto *D : S->decls()) { + // Walk through the declarations in this Scope. The consumer might add new + // decls to the scope as part of deserialization, so make a copy first. + SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end()); + for (Decl *D : ScopeDecls) { if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); @@ -3713,7 +3758,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; - UnqualUsingDirectiveSet UDirs; + UnqualUsingDirectiveSet UDirs(*this); if (getLangOpts().CPlusPlus) { // Find the first namespace or translation-unit scope. while (S && !isNamespaceOrTranslationUnitScope(S)) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index bfb0071a54f9f..ea5b1da46f32f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -1290,6 +1290,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // An abstract type is as bad as an incomplete type. CompleteTypeErr = true; } + if (!CompleteTypeErr) { + const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>(); + if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) { + Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar) + << PropertyIvarType; + CompleteTypeErr = true; // suppress later diagnostics about the ivar + } + } if (CompleteTypeErr) Ivar->setInvalidDecl(); ClassImpDecl->addDecl(Ivar); @@ -1599,7 +1607,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, // meaningless for readonly properties, so don't diagnose if the // atomic property is 'readonly'. checkAtomicPropertyMismatch(*this, SuperProperty, Property, false); - if (Property->getSetterName() != SuperProperty->getSetterName()) { + // Readonly properties from protocols can be implemented as "readwrite" + // with a custom setter name. + if (Property->getSetterName() != SuperProperty->getSetterName() && + !(SuperProperty->isReadOnly() && + isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) { Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "setter" << inheritedName; Diag(SuperProperty->getLocation(), diag::note_property_declare); @@ -1895,7 +1907,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, /* property = */ Prop->getIdentifier(), /* ivar = */ Prop->getDefaultSynthIvarName(Context), Prop->getLocation(), Prop->getQueryKind())); - if (PIDecl) { + if (PIDecl && !Prop->isUnavailable()) { Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis); Diag(IMPDecl->getLocation(), diag::note_while_in_implementation); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index 1ae6f9d6c19c3..b34bb3388d717 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -22,27 +22,36 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeOrdering.h" #include "clang/Basic/OpenMPKinds.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/PointerEmbeddedInt.h" using namespace clang; //===----------------------------------------------------------------------===// // Stack of data-sharing attributes for variables //===----------------------------------------------------------------------===// +static Expr *CheckMapClauseExpressionBase( + Sema &SemaRef, Expr *E, + OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, + OpenMPClauseKind CKind, bool NoDiagnose); + namespace { /// \brief Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { DSA_unspecified = 0, /// \brief Data sharing attribute not specified. DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'. - DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. + DSA_shared = 1 << 1, /// \brief Default data sharing attribute 'shared'. +}; + +/// Attributes of the defaultmap clause. +enum DefaultMapAttributes { + DMA_unspecified, /// Default mapping is not specified. + DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'. }; /// \brief Stack for tracking declarations used in OpenMP directives and @@ -55,7 +64,11 @@ public: Expr *RefExpr = nullptr; DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; - DSAVarData() {} + DSAVarData() = default; + DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, Expr *RefExpr, + DeclRefExpr *PrivateCopy, SourceLocation ImplicitDSALoc) + : DKind(DKind), CKind(CKind), RefExpr(RefExpr), + PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {} }; typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4> OperatorOffsetTy; @@ -84,14 +97,32 @@ private: CriticalsWithHintsTy; typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy> DoacrossDependMapTy; + struct ReductionData { + typedef llvm::PointerEmbeddedInt<BinaryOperatorKind, 16> BOKPtrType; + SourceRange ReductionRange; + llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp; + ReductionData() = default; + void set(BinaryOperatorKind BO, SourceRange RR) { + ReductionRange = RR; + ReductionOp = BO; + } + void set(const Expr *RefExpr, SourceRange RR) { + ReductionRange = RR; + ReductionOp = RefExpr; + } + }; + typedef llvm::DenseMap<ValueDecl *, ReductionData> DeclReductionMapTy; struct SharingMapTy final { DeclSAMapTy SharingMap; + DeclReductionMapTy ReductionMap; AlignedMapTy AlignedMap; MappedExprComponentsTy MappedExprComponents; LoopControlVariablesMapTy LCVMap; DefaultDataSharingAttributes DefaultAttr = DSA_unspecified; SourceLocation DefaultAttrLoc; + DefaultMapAttributes DefaultMapAttr = DMA_unspecified; + SourceLocation DefaultMapAttrLoc; OpenMPDirectiveKind Directive = OMPD_unknown; DeclarationNameInfo DirectiveName; Scope *CurScope = nullptr; @@ -108,11 +139,13 @@ private: bool CancelRegion = false; unsigned AssociatedLoops = 1; SourceLocation InnerTeamsRegionLoc; + /// Reference to the taskgroup task_reduction reference expression. + Expr *TaskgroupReductionRef = nullptr; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), ConstructLoc(Loc) {} - SharingMapTy() {} + SharingMapTy() = default; }; typedef SmallVector<SharingMapTy, 4> StackTy; @@ -145,6 +178,10 @@ public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } + OpenMPClauseKind getClauseParsingMode() const { + assert(isClauseParsingMode() && "Must be in clause parsing mode."); + return ClauseKindMode; + } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } bool isForceVarCapturing() const { return ForceCapturing; } @@ -221,6 +258,39 @@ public: void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, DeclRefExpr *PrivateCopy = nullptr); + /// Adds additional information for the reduction items with the reduction id + /// represented as an operator. + void addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + BinaryOperatorKind BOK); + /// Adds additional information for the reduction items with the reduction id + /// represented as reduction identifier. + void addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + const Expr *ReductionRef); + /// Returns the location and reduction operation from the innermost parent + /// region for the given \p D. + DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, + BinaryOperatorKind &BOK, + Expr *&TaskgroupDescriptor); + /// Returns the location and reduction operation from the innermost parent + /// region for the given \p D. + DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, + const Expr *&ReductionRef, + Expr *&TaskgroupDescriptor); + /// Return reduction reference expression for the current taskgroup. + Expr *getTaskgroupReductionRef() const { + assert(Stack.back().first.back().Directive == OMPD_taskgroup && + "taskgroup reference expression requested for non taskgroup " + "directive."); + return Stack.back().first.back().TaskgroupReductionRef; + } + /// Checks if the given \p VD declaration is actually a taskgroup reduction + /// descriptor variable at the \p Level of OpenMP regions. + bool isTaskgroupReductionRef(ValueDecl *VD, unsigned Level) const { + return Stack.back().first[Level].TaskgroupReductionRef && + cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef) + ->getDecl() == VD; + } + /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. DSAVarData getTopDSA(ValueDecl *D, bool FromParent); @@ -264,6 +334,11 @@ public: OpenMPDirectiveKind getCurrentDirective() const { return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive; } + /// \brief Returns directive kind at specified level. + OpenMPDirectiveKind getDirective(unsigned Level) const { + assert(!isStackEmpty() && "No directive at specified level."); + return Stack.back().first[Level].Directive; + } /// \brief Returns parent directive. OpenMPDirectiveKind getParentDirective() const { if (isStackEmpty() || Stack.back().first.size() == 1) @@ -283,6 +358,12 @@ public: Stack.back().first.back().DefaultAttr = DSA_shared; Stack.back().first.back().DefaultAttrLoc = Loc; } + /// Set default data mapping attribute to 'tofrom:scalar'. + void setDefaultDMAToFromScalar(SourceLocation Loc) { + assert(!isStackEmpty()); + Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar; + Stack.back().first.back().DefaultMapAttrLoc = Loc; + } DefaultDataSharingAttributes getDefaultDSA() const { return isStackEmpty() ? DSA_unspecified @@ -292,6 +373,17 @@ public: return isStackEmpty() ? SourceLocation() : Stack.back().first.back().DefaultAttrLoc; } + DefaultMapAttributes getDefaultDMA() const { + return isStackEmpty() ? DMA_unspecified + : Stack.back().first.back().DefaultMapAttr; + } + DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const { + return Stack.back().first[Level].DefaultMapAttr; + } + SourceLocation getDefaultDMALocation() const { + return isStackEmpty() ? SourceLocation() + : Stack.back().first.back().DefaultMapAttrLoc; + } /// \brief Checks if the specified variable is a threadprivate. bool isThreadPrivate(VarDecl *D) { @@ -479,7 +571,25 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { } } // namespace +static Expr *getExprAsWritten(Expr *E) { + if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) + E = ExprTemp->getSubExpr(); + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + E = MTE->GetTemporaryExpr(); + + while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) + E = Binder->getSubExpr(); + + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExprAsWritten(); + return E->IgnoreParens(); +} + static ValueDecl *getCanonicalDecl(ValueDecl *D) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + D = ME->getMemberDecl(); auto *VD = dyn_cast<VarDecl>(D); auto *FD = dyn_cast<FieldDecl>(D); if (VD != nullptr) { @@ -522,7 +632,6 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, return DVar; } - DVar.DKind = Iter->Directive; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope @@ -533,6 +642,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, return DVar; } + DVar.DKind = Iter->Directive; // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { @@ -691,24 +801,6 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, } } -bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { - D = D->getCanonicalDecl(); - if (!isStackEmpty() && Stack.back().first.size() > 1) { - reverse_iterator I = Iter, E = Stack.back().first.rend(); - Scope *TopScope = nullptr; - while (I != E && !isParallelOrTaskRegion(I->Directive)) - ++I; - if (I == E) - return false; - TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; - Scope *CurScope = getCurScope(); - while (CurScope != TopScope && !CurScope->isDeclScope(D)) - CurScope = CurScope->getParent(); - return CurScope != TopScope; - } - return false; -} - /// \brief Build a variable declaration for OpenMP loop iteration variable. static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, StringRef Name, const AttrVec *Attrs = nullptr) { @@ -736,6 +828,130 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, VK_LValue); } +void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + BinaryOperatorKind BOK) { + D = getCanonicalDecl(D); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + assert( + Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && + "Additional reduction info may be specified only for reduction items."); + auto &ReductionData = Stack.back().first.back().ReductionMap[D]; + assert(ReductionData.ReductionRange.isInvalid() && + Stack.back().first.back().Directive == OMPD_taskgroup && + "Additional reduction info may be specified only once for reduction " + "items."); + ReductionData.set(BOK, SR); + Expr *&TaskgroupReductionRef = + Stack.back().first.back().TaskgroupReductionRef; + if (!TaskgroupReductionRef) { + auto *VD = buildVarDecl(SemaRef, SR.getBegin(), + SemaRef.Context.VoidPtrTy, ".task_red."); + TaskgroupReductionRef = + buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); + } +} + +void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + const Expr *ReductionRef) { + D = getCanonicalDecl(D); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + assert( + Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && + "Additional reduction info may be specified only for reduction items."); + auto &ReductionData = Stack.back().first.back().ReductionMap[D]; + assert(ReductionData.ReductionRange.isInvalid() && + Stack.back().first.back().Directive == OMPD_taskgroup && + "Additional reduction info may be specified only once for reduction " + "items."); + ReductionData.set(ReductionRef, SR); + Expr *&TaskgroupReductionRef = + Stack.back().first.back().TaskgroupReductionRef; + if (!TaskgroupReductionRef) { + auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, + ".task_red."); + TaskgroupReductionRef = + buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); + } +} + +DSAStackTy::DSAVarData +DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, + BinaryOperatorKind &BOK, + Expr *&TaskgroupDescriptor) { + D = getCanonicalDecl(D); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); + if (Stack.back().first.empty()) + return DSAVarData(); + for (auto I = std::next(Stack.back().first.rbegin(), 1), + E = Stack.back().first.rend(); + I != E; std::advance(I, 1)) { + auto &Data = I->SharingMap[D]; + if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + continue; + auto &ReductionData = I->ReductionMap[D]; + if (!ReductionData.ReductionOp || + ReductionData.ReductionOp.is<const Expr *>()) + return DSAVarData(); + SR = ReductionData.ReductionRange; + BOK = ReductionData.ReductionOp.get<ReductionData::BOKPtrType>(); + assert(I->TaskgroupReductionRef && "taskgroup reduction reference " + "expression for the descriptor is not " + "set."); + TaskgroupDescriptor = I->TaskgroupReductionRef; + return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc); + } + return DSAVarData(); +} + +DSAStackTy::DSAVarData +DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, + const Expr *&ReductionRef, + Expr *&TaskgroupDescriptor) { + D = getCanonicalDecl(D); + assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); + if (Stack.back().first.empty()) + return DSAVarData(); + for (auto I = std::next(Stack.back().first.rbegin(), 1), + E = Stack.back().first.rend(); + I != E; std::advance(I, 1)) { + auto &Data = I->SharingMap[D]; + if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + continue; + auto &ReductionData = I->ReductionMap[D]; + if (!ReductionData.ReductionOp || + !ReductionData.ReductionOp.is<const Expr *>()) + return DSAVarData(); + SR = ReductionData.ReductionRange; + ReductionRef = ReductionData.ReductionOp.get<const Expr *>(); + assert(I->TaskgroupReductionRef && "taskgroup reduction reference " + "expression for the descriptor is not " + "set."); + TaskgroupDescriptor = I->TaskgroupReductionRef; + return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc); + } + return DSAVarData(); +} + +bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { + D = D->getCanonicalDecl(); + if (!isStackEmpty() && Stack.back().first.size() > 1) { + reverse_iterator I = Iter, E = Stack.back().first.rend(); + Scope *TopScope = nullptr; + while (I != E && !isParallelOrTaskRegion(I->Directive)) + ++I; + if (I == E) + return false; + TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; + Scope *CurScope = getCurScope(); + while (CurScope != TopScope && !CurScope->isDeclScope(D)) + CurScope = CurScope->getParent(); + return CurScope != TopScope; + } + return false; +} + DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { D = getCanonicalDecl(D); DSAVarData DVar; @@ -759,6 +975,12 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; return DVar; + } else if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) { + DVar.RefExpr = buildDeclRefExpr( + SemaRef, VD, D->getType().getNonReferenceType(), + VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation()); + DVar.CKind = OMPC_threadprivate; + addDSA(D, DVar.RefExpr, OMPC_threadprivate); } if (isStackEmpty()) @@ -811,16 +1033,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { // Explicitly specified attributes and local variables with predetermined // attributes. - auto StartI = std::next(Stack.back().first.rbegin()); + auto I = Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); - if (FromParent && StartI != EndI) - StartI = std::next(StartI); - auto I = std::prev(StartI); + if (FromParent && I != EndI) + std::advance(I, 1); if (I->SharingMap.count(D)) { DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer(); DVar.PrivateCopy = I->SharingMap[D].PrivateCopy; DVar.CKind = I->SharingMap[D].Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; + DVar.DKind = I->Directive; } return DVar; @@ -836,7 +1058,7 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, auto StartI = Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); if (FromParent && StartI != EndI) - StartI = std::next(StartI); + std::advance(StartI, 1); return getDSA(StartI, D); } @@ -848,16 +1070,16 @@ DSAStackTy::hasDSA(ValueDecl *D, if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto I = (FromParent && Stack.back().first.size() > 1) - ? std::next(Stack.back().first.rbegin()) - : Stack.back().first.rbegin(); + auto I = Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); - while (std::distance(I, EndI) > 1) { + if (FromParent && I != EndI) std::advance(I, 1); + for (; I != EndI; std::advance(I, 1)) { if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; - DSAVarData DVar = getDSA(I, D); - if (CPred(DVar.CKind)) + auto NewI = I; + DSAVarData DVar = getDSA(NewI, D); + if (I == NewI && CPred(DVar.CKind)) return DVar; } return {}; @@ -870,21 +1092,20 @@ DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.back().first.rbegin()); + auto StartI = Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); if (FromParent && StartI != EndI) - StartI = std::next(StartI); + std::advance(StartI, 1); if (StartI == EndI || !DPred(StartI->Directive)) return {}; - DSAVarData DVar = getDSA(StartI, D); - return CPred(DVar.CKind) ? DVar : DSAVarData(); + auto NewI = StartI; + DSAVarData DVar = getDSA(NewI, D); + return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData(); } bool DSAStackTy::hasExplicitDSA( ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, unsigned Level, bool NotLastprivate) { - if (CPred(ClauseKindMode)) - return true; if (isStackEmpty()) return false; D = getCanonicalDecl(D); @@ -952,6 +1173,7 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { bool IsByRef = true; // Find the directive that is associated with the provided scope. + D = cast<ValueDecl>(D->getCanonicalDecl()); auto Ty = D->getType(); if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { @@ -1057,8 +1279,13 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { // reference except if it is a pointer that is dereferenced somehow. IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection); } else { - // By default, all the data that has a scalar type is mapped by copy. - IsByRef = !Ty->isScalarType(); + // By default, all the data that has a scalar type is mapped by copy + // (except for reduction variables). + IsByRef = + !Ty->isScalarType() || + DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar || + DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level); } } @@ -1087,6 +1314,17 @@ unsigned Sema::getOpenMPNestingLevel() const { return DSAStack->getNestingLevel(); } +bool Sema::isInOpenMPTargetExecutionDirective() const { + return (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) && + !DSAStack->isClauseParsingMode()) || + DSAStack->hasDirective( + [](OpenMPDirectiveKind K, const DeclarationNameInfo &, + SourceLocation) -> bool { + return isOpenMPTargetExecutionDirective(K); + }, + false); +} + VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); @@ -1099,18 +1337,8 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { // inserted here once support for 'declare target' is added. // auto *VD = dyn_cast<VarDecl>(D); - if (VD && !VD->hasLocalStorage()) { - if (DSAStack->getCurrentDirective() == OMPD_target && - !DSAStack->isClauseParsingMode()) - return VD; - if (DSAStack->hasDirective( - [](OpenMPDirectiveKind K, const DeclarationNameInfo &, - SourceLocation) -> bool { - return isOpenMPTargetExecutionDirective(K); - }, - false)) - return VD; - } + if (VD && !VD->hasLocalStorage() && isInOpenMPTargetExecutionDirective()) + return VD; if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || @@ -1133,10 +1361,59 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { return nullptr; } +void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, + unsigned Level) const { + SmallVector<OpenMPDirectiveKind, 4> Regions; + getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level)); + FunctionScopesIndex -= Regions.size(); +} + bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); return DSAStack->hasExplicitDSA( - D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); + D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, + Level) || + (DSAStack->isClauseParsingMode() && + DSAStack->getClauseParsingMode() == OMPC_private) || + // Consider taskgroup reduction descriptor variable a private to avoid + // possible capture in the region. + (DSAStack->hasExplicitDirective( + [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; }, + Level) && + DSAStack->isTaskgroupReductionRef(D, Level)); +} + +void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + D = getCanonicalDecl(D); + OpenMPClauseKind OMPC = OMPC_unknown; + for (unsigned I = DSAStack->getNestingLevel() + 1; I > Level; --I) { + const unsigned NewLevel = I - 1; + if (DSAStack->hasExplicitDSA(D, + [&OMPC](const OpenMPClauseKind K) { + if (isOpenMPPrivate(K)) { + OMPC = K; + return true; + } + return false; + }, + NewLevel)) + break; + if (DSAStack->checkMappableExprComponentListsForDeclAtLevel( + D, NewLevel, + [](OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind) { return true; })) { + OMPC = OMPC_map; + break; + } + if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, + NewLevel)) { + OMPC = OMPC_firstprivate; + break; + } + } + if (OMPC != OMPC_unknown) + FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC)); } bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) { @@ -1249,7 +1526,7 @@ public: explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); - if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) { return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); } @@ -1568,7 +1845,9 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> { bool ErrorFound; CapturedStmt *CS; llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; + llvm::SmallVector<Expr *, 8> ImplicitMap; llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; + llvm::DenseSet<ValueDecl *> ImplicitDeclarations; public: void VisitDeclRefExpr(DeclRefExpr *E) { @@ -1576,13 +1855,18 @@ public: E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { + VD = VD->getCanonicalDecl(); // Skip internally declared variables. - if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) + if (VD->hasLocalStorage() && !CS->capturesVariable(VD)) return; auto DVar = Stack->getTopDSA(VD, false); // Check if the variable has explicit DSA set and stop analysis if it so. - if (DVar.RefExpr) + if (DVar.RefExpr || !ImplicitDeclarations.insert(VD).second) + return; + + // Skip internally declared static variables. + if (VD->hasGlobalStorage() && !CS->capturesVariable(VD)) return; auto ELoc = E->getExprLoc(); @@ -1598,6 +1882,46 @@ public: return; } + if (isOpenMPTargetExecutionDirective(DKind) && + !Stack->isLoopControlVariable(VD).first) { + if (!Stack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [](OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents, + OpenMPClauseKind) { + // Variable is used if it has been marked as an array, array + // section or the variable iself. + return StackComponents.size() == 1 || + std::all_of( + std::next(StackComponents.rbegin()), + StackComponents.rend(), + [](const OMPClauseMappableExprCommon:: + MappableComponent &MC) { + return MC.getAssociatedDeclaration() == + nullptr && + (isa<OMPArraySectionExpr>( + MC.getAssociatedExpression()) || + isa<ArraySubscriptExpr>( + MC.getAssociatedExpression())); + }); + })) { + bool IsFirstprivate = false; + // By default lambdas are captured as firstprivates. + if (const auto *RD = + VD->getType().getNonReferenceType()->getAsCXXRecordDecl()) + IsFirstprivate = RD->isLambda(); + IsFirstprivate = + IsFirstprivate || + (VD->getType().getNonReferenceType()->isScalarType() && + Stack->getDefaultDMA() != DMA_tofrom_scalar); + if (IsFirstprivate) + ImplicitFirstprivate.emplace_back(E); + else + ImplicitMap.emplace_back(E); + return; + } + } + // OpenMP [2.9.3.6, Restrictions, p.2] // A list item that appears in a reduction clause of the innermost // enclosing worksharing or parallel construct may not be accessed in an @@ -1608,7 +1932,7 @@ public: return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); }, - false); + /*FromParent=*/true); if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); @@ -1627,40 +1951,103 @@ public: if (E->isTypeDependent() || E->isValueDependent() || E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) return; + auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); + OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { - if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { - auto DVar = Stack->getTopDSA(FD, false); - // Check if the variable has explicit DSA set and stop analysis if it - // so. - if (DVar.RefExpr) - return; + if (!FD) + return; + auto DVar = Stack->getTopDSA(FD, false); + // Check if the variable has explicit DSA set and stop analysis if it + // so. + if (DVar.RefExpr || !ImplicitDeclarations.insert(FD).second) + return; - auto ELoc = E->getExprLoc(); - auto DKind = Stack->getCurrentDirective(); - // OpenMP [2.9.3.6, Restrictions, p.2] - // A list item that appears in a reduction clause of the innermost - // enclosing worksharing or parallel construct may not be accessed in - // an explicit task. - DVar = Stack->hasInnermostDSA( - FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K) || - isOpenMPTeamsDirective(K); - }, - false); - if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { - ErrorFound = true; - SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); - ReportOriginalDSA(SemaRef, Stack, FD, DVar); + if (isOpenMPTargetExecutionDirective(DKind) && + !Stack->isLoopControlVariable(FD).first && + !Stack->checkMappableExprComponentListsForDecl( + FD, /*CurrentRegionOnly=*/true, + [](OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents, + OpenMPClauseKind) { + return isa<CXXThisExpr>( + cast<MemberExpr>( + StackComponents.back().getAssociatedExpression()) + ->getBase() + ->IgnoreParens()); + })) { + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3] + // A bit-field cannot appear in a map clause. + // + if (FD->isBitField()) return; - } + ImplicitMap.emplace_back(E); + return; + } + + auto ELoc = E->getExprLoc(); + // OpenMP [2.9.3.6, Restrictions, p.2] + // A list item that appears in a reduction clause of the innermost + // enclosing worksharing or parallel construct may not be accessed in + // an explicit task. + DVar = Stack->hasInnermostDSA( + FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); + }, + /*FromParent=*/true); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { + ErrorFound = true; + SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); + ReportOriginalDSA(SemaRef, Stack, FD, DVar); + return; + } + + // Define implicit data-sharing attributes for task. + DVar = Stack->getImplicitDSA(FD, false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + !Stack->isLoopControlVariable(FD).first) + ImplicitFirstprivate.push_back(E); + return; + } + if (isOpenMPTargetExecutionDirective(DKind)) { + OMPClauseMappableExprCommon::MappableExprComponentList CurComponents; + if (!CheckMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map, + /*NoDiagnose=*/true)) + return; + auto *VD = cast<ValueDecl>( + CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl()); + if (!Stack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [&CurComponents]( + OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents, + OpenMPClauseKind) { + auto CCI = CurComponents.rbegin(); + auto CCE = CurComponents.rend(); + for (const auto &SC : llvm::reverse(StackComponents)) { + // Do both expressions have the same kind? + if (CCI->getAssociatedExpression()->getStmtClass() != + SC.getAssociatedExpression()->getStmtClass()) + if (!(isa<OMPArraySectionExpr>( + SC.getAssociatedExpression()) && + isa<ArraySubscriptExpr>( + CCI->getAssociatedExpression()))) + return false; - // Define implicit data-sharing attributes for task. - DVar = Stack->getImplicitDSA(FD, false); - if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && - !Stack->isLoopControlVariable(FD).first) - ImplicitFirstprivate.push_back(E); + Decl *CCD = CCI->getAssociatedDeclaration(); + Decl *SCD = SC.getAssociatedDeclaration(); + CCD = CCD ? CCD->getCanonicalDecl() : nullptr; + SCD = SCD ? SCD->getCanonicalDecl() : nullptr; + if (SCD != CCD) + return false; + std::advance(CCI, 1); + if (CCI == CCE) + break; + } + return true; + })) { + Visit(E->getBase()); } } else Visit(E->getBase()); @@ -1668,12 +2055,16 @@ public: void VisitOMPExecutableDirective(OMPExecutableDirective *S) { for (auto *C : S->clauses()) { // Skip analysis of arguments of implicitly defined firstprivate clause - // for task directives. - if (C && (!isa<OMPFirstprivateClause>(C) || C->getLocStart().isValid())) + // for task|target directives. + // Skip analysis of arguments of implicitly defined map clause for target + // directives. + if (C && !((isa<OMPFirstprivateClause>(C) || isa<OMPMapClause>(C)) && + C->isImplicit())) { for (auto *CC : C->children()) { if (CC) Visit(CC); } + } } } void VisitStmt(Stmt *S) { @@ -1684,7 +2075,10 @@ public: } bool isErrorFound() { return ErrorFound; } - ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; } + ArrayRef<Expr *> getImplicitFirstprivate() const { + return ImplicitFirstprivate; + } + ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; } llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() { return VarsWithInheritedDSA; } @@ -1700,7 +2094,9 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: - case OMPD_teams: { + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1714,7 +2110,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_target_teams: - case OMPD_target_parallel: { + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: { Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -1745,12 +2145,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_critical: case OMPD_taskgroup: case OMPD_distribute: + case OMPD_distribute_simd: case OMPD_ordered: case OMPD_atomic: case OMPD_target_data: case OMPD_target: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: case OMPD_target_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars @@ -1821,16 +2220,9 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_simd: case OMPD_distribute_parallel_for: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: { + case OMPD_target_teams_distribute_parallel_for_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1845,6 +2237,60 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + + Sema::CapturedParamNameType ParamsTeams[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'target' with no implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsTeams); + + Sema::CapturedParamNameType ParamsParallel[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(".previous.lb.", Context.getSizeType()), + std::make_pair(".previous.ub.", Context.getSizeType()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'teams' or 'parallel'. Both regions have + // the same implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsParallel); + break; + } + case OMPD_target_update: + case OMPD_target_enter_data: + case OMPD_target_exit_data: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), + std::make_pair(".privates.", Context.VoidPtrTy.withConst()), + std::make_pair(".copy_fn.", + Context.getPointerType(CopyFnType).withConst()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); + break; + } case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -1852,13 +2298,10 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: - case OMPD_target_enter_data: - case OMPD_target_exit_data: case OMPD_declare_reduction: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: - case OMPD_target_update: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -1969,12 +2412,23 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, return StmtError(); } + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective()); OMPOrderedClause *OC = nullptr; OMPScheduleClause *SC = nullptr; SmallVector<OMPLinearClause *, 4> LCs; SmallVector<OMPClauseWithPreInit *, 8> PICs; // This is required for proper codegen. for (auto *Clause : Clauses) { + if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && + Clause->getClauseKind() == OMPC_in_reduction) { + // Capture taskgroup task_reduction descriptors inside the tasking regions + // with the corresponding in_reduction items. + auto *IRC = cast<OMPInReductionClause>(Clause); + for (auto *E : IRC->taskgroup_descriptors()) + if (E) + MarkDeclarationsReferencedInExpr(E); + } if (isOpenMPPrivate(Clause->getClauseKind()) || Clause->getClauseKind() == OMPC_copyprivate || (getLangOpts().OpenMPUseTLS && @@ -1988,7 +2442,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } DSAStack->setForceVarCapturing(/*V=*/false); - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { + } else if (CaptureRegions.size() > 1 || + CaptureRegions.back() != OMPD_unknown) { if (auto *C = OMPClauseWithPreInit::get(Clause)) PICs.push_back(C); if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { @@ -2036,13 +2491,11 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, return StmtError(); } StmtResult SR = S; - SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; - getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective()); - for (auto ThisCaptureRegion : llvm::reverse(CaptureRegions)) { + for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) { // Mark all variables in private list clauses as used in inner region. // Required for proper codegen of combined directives. // TODO: add processing for other clauses. - if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { + if (ThisCaptureRegion != OMPD_unknown) { for (auto *C : PICs) { OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion(); // Find the particular capture region for the clause if the @@ -2157,7 +2610,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, ParentRegion == OMPD_target_parallel)) || (CancelRegion == OMPD_for && (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for || - ParentRegion == OMPD_target_parallel_for)) || + ParentRegion == OMPD_target_parallel_for || + ParentRegion == OMPD_distribute_parallel_for || + ParentRegion == OMPD_teams_distribute_parallel_for || + ParentRegion == OMPD_target_teams_distribute_parallel_for)) || (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || @@ -2236,7 +2692,6 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NestingProhibited = ParentRegion != OMPD_target; OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; - Stack->setParentTeamsRegionLoc(Stack->getConstructLoc()); } if (!NestingProhibited && !isOpenMPTargetExecutionDirective(CurrentRegion) && @@ -2390,7 +2845,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; bool ErrorFound = false; ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); - if (AStmt) { + if (AStmt && !CurContext->isDependentContext()) { assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); // Check default data sharing attributes for referenced variables. @@ -2405,13 +2860,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( // Generate list of implicitly defined firstprivate variables. VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA(); - if (!DSAChecker.getImplicitFirstprivate().empty()) { + SmallVector<Expr *, 4> ImplicitFirstprivates( + DSAChecker.getImplicitFirstprivate().begin(), + DSAChecker.getImplicitFirstprivate().end()); + SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(), + DSAChecker.getImplicitMap().end()); + // Mark taskgroup task_reduction descriptors as implicitly firstprivate. + for (auto *C : Clauses) { + if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) { + for (auto *E : IRC->taskgroup_descriptors()) + if (E) + ImplicitFirstprivates.emplace_back(E); + } + } + if (!ImplicitFirstprivates.empty()) { if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( - DSAChecker.getImplicitFirstprivate(), SourceLocation(), - SourceLocation(), SourceLocation())) { + ImplicitFirstprivates, SourceLocation(), SourceLocation(), + SourceLocation())) { ClausesWithImplicit.push_back(Implicit); ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() != - DSAChecker.getImplicitFirstprivate().size(); + ImplicitFirstprivates.size(); + } else + ErrorFound = true; + } + if (!ImplicitMaps.empty()) { + if (OMPClause *Implicit = ActOnOpenMPMapClause( + OMPC_MAP_unknown, OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, + SourceLocation(), SourceLocation(), ImplicitMaps, + SourceLocation(), SourceLocation(), SourceLocation())) { + ClausesWithImplicit.emplace_back(Implicit); + ErrorFound |= + cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size(); } else ErrorFound = true; } @@ -2558,12 +3037,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( break; case OMPD_target_enter_data: Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc, - EndLoc); + EndLoc, AStmt); AllowedNameModifiers.push_back(OMPD_target_enter_data); break; case OMPD_target_exit_data: Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc, - EndLoc); + EndLoc, AStmt); AllowedNameModifiers.push_back(OMPD_target_exit_data); break; case OMPD_taskloop: @@ -2581,9 +3060,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc, VarsWithInheritedDSA); break; case OMPD_target_update: - assert(!AStmt && "Statement is not allowed for target update"); - Res = - ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc); + Res = ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, + EndLoc, AStmt); AllowedNameModifiers.push_back(OMPD_target_update); break; case OMPD_distribute_parallel_for: @@ -3053,21 +3531,6 @@ bool OpenMPIterationSpaceChecker::Dependent() const { (Step && Step->isValueDependent()); } -static Expr *getExprAsWritten(Expr *E) { - if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) - E = ExprTemp->getSubExpr(); - - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - E = MTE->GetTemporaryExpr(); - - while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) - E = Binder->getSubExpr(); - - if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) - E = ICE->getSubExprAsWritten(); - return E->IgnoreParens(); -} - bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewLCRefExpr, Expr *NewLB) { @@ -3249,12 +3712,8 @@ static const ValueDecl *GetInitLCDecl(Expr *E) { CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) { - if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD)) - if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return getCanonicalDecl(ME->getMemberDecl()); + if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) return getCanonicalDecl(VD); - } } if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) @@ -3939,7 +4398,7 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { /// Build preinits statement for the given declarations. static Stmt *buildPreInits(ASTContext &Context, - SmallVectorImpl<Decl *> &PreInits) { + MutableArrayRef<Decl *> PreInits) { if (!PreInits.empty()) { return new (Context) DeclStmt( DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()), @@ -3949,8 +4408,9 @@ static Stmt *buildPreInits(ASTContext &Context, } /// Build preinits statement for the given declarations. -static Stmt *buildPreInits(ASTContext &Context, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { +static Stmt * +buildPreInits(ASTContext &Context, + const llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { if (!Captures.empty()) { SmallVector<Decl *, 16> PreInits; for (auto &Pair : Captures) @@ -5080,7 +5540,8 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + AStmt, + DSAStack->getTaskgroupReductionRef()); } StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, @@ -5924,13 +6385,23 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses), - getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -5995,7 +6466,28 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc) { + SourceLocation EndLoc, Stmt *AStmt) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_enter_data); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + // OpenMP [2.10.2, Restrictions, p. 99] // At least one map clause must appear on the directive. if (!hasClauses(Clauses, OMPC_map)) { @@ -6004,14 +6496,35 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, - Clauses); + return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); } StmtResult Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc) { + SourceLocation EndLoc, Stmt *AStmt) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_exit_data); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + // OpenMP [2.10.3, Restrictions, p. 102] // At least one map clause must appear on the directive. if (!hasClauses(Clauses, OMPC_map)) { @@ -6020,17 +6533,41 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses); + return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); } StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, - SourceLocation EndLoc) { + SourceLocation EndLoc, + Stmt *AStmt) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_update); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + if (!hasClauses(Clauses, OMPC_to, OMPC_from)) { Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required); return StmtError(); } - return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses); + return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); } StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, @@ -6049,6 +6586,8 @@ StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); + DSAStack->setParentTeamsRegionLoc(StartLoc); + return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } @@ -6215,6 +6754,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( // clause must not be specified. if (checkReductionClauseWithNogroup(*this, Clauses)) return StmtError(); + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, @@ -6261,13 +6802,24 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_distribute_parallel_for); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6277,7 +6829,8 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( getCurFunction()->setHasBranchProtectedScope(); return OMPDistributeParallelForDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( @@ -6294,13 +6847,24 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_distribute_parallel_for_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6308,6 +6872,17 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); @@ -6330,20 +6905,41 @@ StmtResult Sema::ActOnOpenMPDistributeSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_distribute_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, - *this, *DSAStack, VarsWithImplicitDSA, B); + nullptr /*ordered not a clause on distribute*/, CS, *this, + *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); @@ -6366,13 +6962,23 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses), - getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6412,13 +7018,23 @@ StmtResult Sema::ActOnOpenMPTargetSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will define the // nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses), - getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6459,14 +7075,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_distribute); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, - *this, *DSAStack, VarsWithImplicitDSA, B); + nullptr /*ordered not a clause on distribute*/, CS, *this, + *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6474,6 +7100,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( "omp teams distribute loop exprs were not built"); getCurFunction()->setHasBranchProtectedScope(); + + DSAStack->setParentTeamsRegionLoc(StartLoc); + return OMPTeamsDistributeDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -6492,13 +7121,25 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_teams_distribute_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6522,6 +7163,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( return StmtError(); getCurFunction()->setHasBranchProtectedScope(); + + DSAStack->setParentTeamsRegionLoc(StartLoc); + return OMPTeamsDistributeSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -6541,12 +7185,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. auto NestedLoopCount = CheckOpenMPLoop( OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6570,6 +7226,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( return StmtError(); getCurFunction()->setHasBranchProtectedScope(); + + DSAStack->setParentTeamsRegionLoc(StartLoc); + return OMPTeamsDistributeParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -6589,12 +7248,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6603,20 +7274,13 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - if (!CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { - if (auto *LC = dyn_cast<OMPLinearClause>(C)) - if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope, - DSAStack)) - return StmtError(); - } - } - getCurFunction()->setHasBranchProtectedScope(); + + DSAStack->setParentTeamsRegionLoc(StartLoc); + return OMPTeamsDistributeParallelForDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, @@ -6634,6 +7298,16 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } getCurFunction()->setHasBranchProtectedScope(); return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, @@ -6654,14 +7328,24 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_target_teams_distribute); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. auto NestedLoopCount = CheckOpenMPLoop( - OMPD_target_teams_distribute, - getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + OMPD_target_teams_distribute, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6703,20 +7387,10 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp target teams distribute parallel for loop exprs were not built"); - if (!CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { - if (auto *LC = dyn_cast<OMPLinearClause>(C)) - if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope, - DSAStack)) - return StmtError(); - } - } - getCurFunction()->setHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( @@ -6760,6 +7434,9 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( } } + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + getCurFunction()->setHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -6779,13 +7456,24 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_target_teams_distribute_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. auto NestedLoopCount = CheckOpenMPLoop( OMPD_target_teams_distribute_simd, getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -6793,6 +7481,20 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp target teams distribute simd loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + getCurFunction()->setHasBranchProtectedScope(); return OMPTargetTeamsDistributeSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -6853,6 +7555,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -6894,16 +7597,23 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, OpenMPDirectiveKind NameModifier = OMPD_unknown) { OpenMPDirectiveKind CaptureRegion = OMPD_unknown; - switch (CKind) { case OMPC_if: switch (DKind) { case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: // If this clause applies to the nested 'parallel' region, capture within // the 'target' region, otherwise do not capture. if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_target; break; + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_teams; + break; case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -6911,15 +7621,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for_simd: case OMPD_target: case OMPD_target_simd: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: case OMPD_target_teams: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_teams_distribute_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: case OMPD_task: @@ -6965,24 +7669,84 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_num_threads: switch (DKind) { case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_target; break; - case OMPD_cancel: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_teams; + break; case OMPD_parallel: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + // Do not capture num_threads-clause expressions. + break; + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: case OMPD_target: case OMPD_target_simd: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_cancel: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_teams: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_num_teams: + switch (DKind) { case OMPD_target_teams: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_target; + break; case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + // Do not capture num_teams-clause expressions. + break; case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: case OMPD_task: @@ -6992,8 +7756,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: - // Do not capture num_threads-clause expressions. - break; + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -7004,7 +7776,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: - case OMPD_teams: case OMPD_simd: case OMPD_for: case OMPD_for_simd: @@ -7018,18 +7789,36 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_ordered: case OMPD_atomic: case OMPD_distribute_simd: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); + llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } break; - case OMPC_num_teams: + case OMPC_thread_limit: switch (DKind) { case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_target; break; + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + // Do not capture thread_limit-clause expressions. + break; + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -7040,14 +7829,56 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel: case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: - case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_simd: + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_schedule: + switch (DKind) { + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_target; + break; case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_teams; + break; + case OMPD_parallel_for: + case OMPD_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: + CaptureRegion = OMPD_parallel; + break; + case OMPD_for: + case OMPD_for_simd: + // Do not capture schedule-clause expressions. + break; case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: @@ -7058,8 +7889,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_teams: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: - // Do not capture num_teams-clause expressions. - break; + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel: + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -7071,8 +7908,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: - case OMPD_for: - case OMPD_for_simd: case OMPD_sections: case OMPD_section: case OMPD_single: @@ -7083,46 +7918,112 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_ordered: case OMPD_atomic: case OMPD_distribute_simd: - llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); + case OMPD_target_teams: + llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } break; - case OMPC_thread_limit: + case OMPC_dist_schedule: switch (DKind) { - case OMPD_target_teams: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + CaptureRegion = OMPD_teams; + break; + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: CaptureRegion = OMPD_target; break; - case OMPD_cancel: - case OMPD_parallel: - case OMPD_parallel_sections: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + CaptureRegion = OMPD_parallel; + break; + case OMPD_distribute: + case OMPD_distribute_simd: + // Do not capture thread_limit-clause expressions. + break; case OMPD_parallel_for: case OMPD_parallel_for_simd: + case OMPD_target_parallel_for_simd: + case OMPD_target_parallel_for: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + case OMPD_teams: case OMPD_target: case OMPD_target_simd: case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_target_teams: + llvm_unreachable("Unexpected OpenMP directive with schedule clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; + case OMPC_device: + switch (DKind) { + case OMPD_target_teams: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: - case OMPD_task: - case OMPD_taskloop: - case OMPD_taskloop_simd: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + // Do not capture device-clause expressions. + break; + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: case OMPD_teams: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: - // Do not capture thread_limit-clause expressions. - break; + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: @@ -7146,17 +8047,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_ordered: case OMPD_atomic: case OMPD_distribute_simd: - llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); + llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } break; - case OMPC_schedule: - case OMPC_dist_schedule: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_default: case OMPC_proc_bind: @@ -7181,7 +8081,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: - case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: @@ -7223,7 +8122,7 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier); - if (CaptureRegion != OMPD_unknown) { + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); @@ -7329,7 +8228,6 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation EndLoc) { Expr *ValExpr = NumThreads; Stmt *HelperValStmt = nullptr; - OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.5, Restrictions] // The num_threads expression must evaluate to a positive integer value. @@ -7338,8 +8236,9 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads); - if (CaptureRegion != OMPD_unknown) { + OpenMPDirectiveKind CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); @@ -7473,6 +8372,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -7631,6 +8531,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -7761,7 +8662,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( << "schedule" << 1 << ChunkSize->getSourceRange(); return nullptr; } - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + } else if (getOpenMPCaptureRegionForClause( + DSAStack->getCurrentDirective(), OMPC_schedule) != + OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); @@ -7829,6 +8732,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: + case OMPC_in_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -7946,6 +8850,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( EndLoc, ReductionIdScopeSpec, ReductionId); break; + case OMPC_in_reduction: + Res = + ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, + EndLoc, ReductionIdScopeSpec, ReductionId); + break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, LinKind, DepLinMapLoc, ColonLoc, EndLoc); @@ -8097,7 +9006,8 @@ getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, } return std::make_pair(nullptr, false); } - return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false); + return std::make_pair( + getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); } OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, @@ -8299,13 +9209,19 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, if (!IsImplicitClause) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); TopDVar = DVar; + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); bool IsConstant = ElemType.isConstant(Context); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more // than one clause on the same directive, except that a variable may be // specified in both firstprivate and lastprivate clauses. + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && - DVar.CKind != OMPC_lastprivate && DVar.RefExpr) { + (isOpenMPDistributeDirective(CurrDir) || + DVar.CKind != OMPC_lastprivate) && + DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); @@ -8333,18 +9249,29 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, continue; } - OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.9.3.4, Restrictions, p.2] // A list item that is private within a parallel region must not appear // in a firstprivate clause on a worksharing construct if any of the // worksharing regions arising from the worksharing construct ever bind // to any of the parallel regions arising from the parallel construct. - if (isOpenMPWorksharingDirective(CurrDir) && + // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] + // A list item that is private within a teams region must not appear in a + // firstprivate clause on a distribute construct if any of the distribute + // regions arising from the distribute construct ever bind to any of the + // teams regions arising from the teams construct. + // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] + // A list item that appears in a reduction clause of a teams construct + // must not appear in a firstprivate clause on a distribute construct if + // any of the distribute regions arising from the distribute construct + // ever bind to any of the teams regions arising from the teams construct. + if ((isOpenMPWorksharingDirective(CurrDir) || + isOpenMPDistributeDirective(CurrDir)) && !isOpenMPParallelDirective(CurrDir) && !isOpenMPTeamsDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared && (isOpenMPParallelDirective(DVar.DKind) || + isOpenMPTeamsDirective(DVar.DKind) || DVar.DKind == OMPD_unknown)) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_firstprivate) @@ -8369,12 +9296,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, [](OpenMPDirectiveKind K) -> bool { return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K); + isOpenMPWorksharingDirective(K) || + isOpenMPTeamsDirective(K); }, - false); + /*FromParent=*/true); if (DVar.CKind == OMPC_reduction && (isOpenMPParallelDirective(DVar.DKind) || - isOpenMPWorksharingDirective(DVar.DKind))) { + isOpenMPWorksharingDirective(DVar.DKind) || + isOpenMPTeamsDirective(DVar.DKind))) { Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate) << getOpenMPDirectiveName(DVar.DKind); ReportOriginalDSA(*this, DSAStack, D, DVar); @@ -8382,61 +9311,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, } } - // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] - // A list item that is private within a teams region must not appear in a - // firstprivate clause on a distribute construct if any of the distribute - // regions arising from the distribute construct ever bind to any of the - // teams regions arising from the teams construct. - // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] - // A list item that appears in a reduction clause of a teams construct - // must not appear in a firstprivate clause on a distribute construct if - // any of the distribute regions arising from the distribute construct - // ever bind to any of the teams regions arising from the teams construct. - // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] - // A list item may appear in a firstprivate or lastprivate clause but not - // both. - if (CurrDir == OMPD_distribute) { - DVar = DSAStack->hasInnermostDSA( - D, [](OpenMPClauseKind C) -> bool { return C == OMPC_private; }, - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPTeamsDirective(K); - }, - false); - if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) { - Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams); - ReportOriginalDSA(*this, DSAStack, D, DVar); - continue; - } - DVar = DSAStack->hasInnermostDSA( - D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPTeamsDirective(K); - }, - false); - if (DVar.CKind == OMPC_reduction && - isOpenMPTeamsDirective(DVar.DKind)) { - Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction); - ReportOriginalDSA(*this, DSAStack, D, DVar); - continue; - } - DVar = DSAStack->getTopDSA(D, false); - if (DVar.CKind == OMPC_lastprivate) { - Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, D, DVar); - continue; - } - } // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (CurrDir == OMPD_target || CurrDir == OMPD_target_parallel || - CurrDir == OMPD_target_teams || - CurrDir == OMPD_target_teams_distribute || - CurrDir == OMPD_target_teams_distribute_parallel_for || - CurrDir == OMPD_target_teams_distribute_parallel_for_simd || - CurrDir == OMPD_target_teams_distribute_simd || - CurrDir == OMPD_target_parallel_for_simd || - CurrDir == OMPD_target_parallel_for) { + if (isOpenMPTargetExecutionDirective(CurrDir)) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -8585,14 +9463,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, continue; Type = Type.getNonReferenceType(); + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && - DVar.CKind != OMPC_firstprivate && + (isOpenMPDistributeDirective(CurrDir) || + DVar.CKind != OMPC_firstprivate) && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) @@ -8601,7 +9484,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, continue; } - OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.14.3.5, Restrictions, p.2] // A list item that is private within a parallel region, or that appears in // the reduction clause of a parallel construct, must not appear in a @@ -8622,18 +9504,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, } } - // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] - // A list item may appear in a firstprivate or lastprivate clause but not - // both. - if (CurrDir == OMPD_distribute) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); - if (DVar.CKind == OMPC_firstprivate) { - Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, D, DVar); - continue; - } - } - // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous default @@ -8770,7 +9640,7 @@ public: return true; DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, - false); + /*FromParent=*/true); if (DVarPrivate.CKind != OMPC_unknown) return true; return false; @@ -8928,6 +9798,9 @@ struct ReductionData { SmallVector<Expr *, 8> RHSs; /// Reduction operation expression. SmallVector<Expr *, 8> ReductionOps; + /// Taskgroup descriptors for the corresponding reduction items in + /// in_reduction clauses. + SmallVector<Expr *, 8> TaskgroupDescriptors; /// List of captures for clause. SmallVector<Decl *, 4> ExprCaptures; /// List of postupdate expressions. @@ -8940,6 +9813,7 @@ struct ReductionData { LHSs.reserve(Size); RHSs.reserve(Size); ReductionOps.reserve(Size); + TaskgroupDescriptors.reserve(Size); ExprCaptures.reserve(Size); ExprPostUpdates.reserve(Size); } @@ -8951,19 +9825,83 @@ struct ReductionData { LHSs.emplace_back(nullptr); RHSs.emplace_back(nullptr); ReductionOps.emplace_back(ReductionOp); + TaskgroupDescriptors.emplace_back(nullptr); } /// Stores reduction data. - void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, - Expr *ReductionOp) { + void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp, + Expr *TaskgroupDescriptor) { Vars.emplace_back(Item); Privates.emplace_back(Private); LHSs.emplace_back(LHS); RHSs.emplace_back(RHS); ReductionOps.emplace_back(ReductionOp); + TaskgroupDescriptors.emplace_back(TaskgroupDescriptor); } }; } // namespace +static bool CheckOMPArraySectionConstantForReduction( + ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, + SmallVectorImpl<llvm::APSInt> &ArraySizes) { + const Expr *Length = OASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + SingleElement = true; + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context)) + return false; + + SingleElement = (ConstantLengthValue.getSExtValue() == 1); + ArraySizes.push_back(ConstantLengthValue); + } + + // Get the base of this array section and walk up from there. + const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); + + // We require length = 1 for all array sections except the right-most to + // guarantee that the memory region is contiguous and has no holes in it. + while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) { + Length = TempOASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context) || + ConstantLengthValue.getSExtValue() != 1) + return false; + + ArraySizes.push_back(ConstantLengthValue); + } + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + } + + // If we have a single element, we don't need to add the implicit lengths. + if (!SingleElement) { + while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) { + // Has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + Base = TempASE->getBase()->IgnoreParenImpCasts(); + } + } + + // This array section can be privatized as a single value or as a constant + // sized array. + return true; +} + static bool ActOnOMPReductionKindClause( Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -8982,7 +9920,6 @@ static bool ActOnOMPReductionKindClause( // C++ // reduction-identifier is either an id-expression or one of the following // operators: +, -, *, &, |, ^, && and || - // FIXME: Only 'min' and 'max' identifiers are supported for now. switch (OOK) { case OO_Plus: case OO_Minus: @@ -9033,6 +9970,7 @@ static bool ActOnOMPReductionKindClause( case OO_GreaterGreaterEqual: case OO_EqualEqual: case OO_ExclaimEqual: + case OO_Spaceship: case OO_PlusPlus: case OO_MinusMinus: case OO_Comma: @@ -9045,7 +9983,7 @@ static bool ActOnOMPReductionKindClause( case NUM_OVERLOADED_OPERATORS: llvm_unreachable("Unexpected reduction identifier"); case OO_None: - if (auto II = DN.getAsIdentifierInfo()) { + if (auto *II = DN.getAsIdentifierInfo()) { if (II->isStr("max")) BOK = BO_GT; else if (II->isStr("min")) @@ -9056,6 +9994,8 @@ static bool ActOnOMPReductionKindClause( SourceRange ReductionIdRange; if (ReductionIdScopeSpec.isValid()) ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); + else + ReductionIdRange.setBegin(ReductionId.getBeginLoc()); ReductionIdRange.setEnd(ReductionId.getEndLoc()); auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end(); @@ -9097,6 +10037,7 @@ static bool ActOnOMPReductionKindClause( if (!D) continue; + Expr *TaskgroupDescriptor = nullptr; QualType Type; auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens()); auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens()); @@ -9167,6 +10108,7 @@ static bool ActOnOMPReductionKindClause( << getOpenMPClauseName(ClauseKind); if (DVar.RefExpr) S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); + continue; } else if (DVar.CKind != OMPC_unknown) { S.Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) @@ -9259,9 +10201,34 @@ static bool ActOnOMPReductionKindClause( auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - if (OASE || - (!ASE && + + // Try if we can determine constant lengths for all array sections and avoid + // the VLA. + bool ConstantLengthOASE = false; + if (OASE) { + bool SingleElement; + llvm::SmallVector<llvm::APSInt, 4> ArraySizes; + ConstantLengthOASE = CheckOMPArraySectionConstantForReduction( + Context, OASE, SingleElement, ArraySizes); + + // If we don't have a single element, we must emit a constant array type. + if (ConstantLengthOASE && !SingleElement) { + for (auto &Size : ArraySizes) { + PrivateTy = Context.getConstantArrayType( + PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); + } + } + } + + if ((OASE && !ConstantLengthOASE) || + (!OASE && !ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { + if (!Context.getTargetInfo().isVLASupported() && + S.shouldDiagnoseTargetSupportFromOpenMP()) { + S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; + S.Diag(ELoc, diag::note_vla_unsupported); + continue; + } // For arrays/array sections only: // Create pseudo array type for private copy. The size for this array will // be generated during codegen. @@ -9269,8 +10236,7 @@ static bool ActOnOMPReductionKindClause( // (type of the variable or single array element). PrivateTy = Context.getVariableArrayType( Type, - new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), - VK_RValue), + new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); } else if (!ASE && !OASE && Context.getAsArrayType(D->getType().getNonReferenceType())) @@ -9352,8 +10318,7 @@ static bool ActOnOMPReductionKindClause( if (Type->isPointerType()) { // Cast to pointer type. auto CastExpr = S.BuildCStyleCastExpr( - SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), - SourceLocation(), Init); + ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init); if (CastExpr.isInvalid()) continue; Init = CastExpr.get(); @@ -9378,6 +10343,7 @@ static bool ActOnOMPReductionKindClause( case BO_GE: case BO_EQ: case BO_NE: + case BO_Cmp: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: @@ -9447,17 +10413,70 @@ static bool ActOnOMPReductionKindClause( S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ReductionOp.get()); } else { - auto *ConditionalOp = new (Context) ConditionalOperator( - ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), - RHSDRE, Type, VK_LValue, OK_Ordinary); + auto *ConditionalOp = new (Context) + ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE, + Type, VK_LValue, OK_Ordinary); ReductionOp = S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ConditionalOp); } - ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get()); + if (ReductionOp.isUsable()) + ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get()); } - if (ReductionOp.isInvalid()) + if (!ReductionOp.isUsable()) + continue; + } + + // OpenMP [2.15.4.6, Restrictions, p.2] + // A list item that appears in an in_reduction clause of a task construct + // must appear in a task_reduction clause of a construct associated with a + // taskgroup region that includes the participating task in its taskgroup + // set. The construct associated with the innermost region that meets this + // condition must specify the same reduction-identifier as the in_reduction + // clause. + if (ClauseKind == OMPC_in_reduction) { + SourceRange ParentSR; + BinaryOperatorKind ParentBOK; + const Expr *ParentReductionOp; + Expr *ParentBOKTD, *ParentReductionOpTD; + DSAStackTy::DSAVarData ParentBOKDSA = + Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK, + ParentBOKTD); + DSAStackTy::DSAVarData ParentReductionOpDSA = + Stack->getTopMostTaskgroupReductionData( + D, ParentSR, ParentReductionOp, ParentReductionOpTD); + bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown; + bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown; + if (!IsParentBOK && !IsParentReductionOp) { + S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction); continue; + } + if ((DeclareReductionRef.isUnset() && IsParentReductionOp) || + (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK || + IsParentReductionOp) { + bool EmitError = true; + if (IsParentReductionOp && DeclareReductionRef.isUsable()) { + llvm::FoldingSetNodeID RedId, ParentRedId; + ParentReductionOp->Profile(ParentRedId, Context, /*Canonical=*/true); + DeclareReductionRef.get()->Profile(RedId, Context, + /*Canonical=*/true); + EmitError = RedId != ParentRedId; + } + if (EmitError) { + S.Diag(ReductionId.getLocStart(), + diag::err_omp_reduction_identifier_mismatch) + << ReductionIdRange << RefExpr->getSourceRange(); + S.Diag(ParentSR.getBegin(), + diag::note_omp_previous_reduction_identifier) + << ParentSR + << (IsParentBOK ? ParentBOKDSA.RefExpr + : ParentReductionOpDSA.RefExpr) + ->getSourceRange(); + continue; + } + } + TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD; + assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined."); } DeclRefExpr *Ref = nullptr; @@ -9497,7 +10516,15 @@ static bool ActOnOMPReductionKindClause( // All reduction items are still marked as reduction (to do not increase // code base size). Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); - RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get()); + if (CurrDir == OMPD_taskgroup) { + if (DeclareReductionRef.isUsable()) + Stack->addTaskgroupReductionData(D, ReductionIdRange, + DeclareReductionRef.get()); + else + Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK); + } + RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(), + TaskgroupDescriptor); } return RD.Vars.empty(); } @@ -9544,6 +10571,27 @@ OMPClause *Sema::ActOnOpenMPTaskReductionClause( buildPostUpdate(*this, RD.ExprPostUpdates)); } +OMPClause *Sema::ActOnOpenMPInReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { + ReductionData RD(VarList.size()); + + if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList, + StartLoc, LParenLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, + UnresolvedReductions, RD)) + return nullptr; + + return OMPInReductionClause::Create( + Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.TaskgroupDescriptors, + buildPreInits(Context, RD.ExprCaptures), + buildPostUpdate(*this, RD.ExprPostUpdates)); +} + bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc) { if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || @@ -9768,11 +10816,19 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, HasErrors = true; continue; } - if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) { - D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts()) - ->getMemberDecl(); - } auto &&Info = Stack->isLoopControlVariable(D); + // OpenMP [2.15.11, distribute simd Construct] + // A list item may not appear in a linear clause, unless it is the loop + // iteration variable. + if (isOpenMPDistributeDirective(Stack->getCurrentDirective()) && + isOpenMPSimdDirective(Stack->getCurrentDirective()) && !Info.first) { + SemaRef.Diag(ELoc, + diag::err_omp_linear_distribute_var_non_loop_iteration); + Updates.push_back(nullptr); + Finals.push_back(nullptr); + HasErrors = true; + continue; + } Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. @@ -10239,23 +11295,26 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, } OpsOffs.push_back({RHS, OOK}); } else { - // OpenMP [2.11.1.1, Restrictions, p.3] - // A variable that is part of another variable (such as a field of a - // structure) but is not an array element or an array section cannot - // appear in a depend clause. - auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); if (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) || (ASE && !ASE->getBase() ->getType() .getNonReferenceType() ->isPointerType() && !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item) - << 0 << RefExpr->getSourceRange(); + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << RefExpr->getSourceRange(); + continue; + } + bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); + getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + ExprResult Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + getDiagnostics().setSuppressAllDiagnostics(Suppress); + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << RefExpr->getSourceRange(); continue; } } @@ -10284,6 +11343,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Device; + Stmt *HelperValStmt = nullptr; // OpenMP [2.9.1, Restrictions] // The device expression must evaluate to a non-negative integer value. @@ -10291,48 +11351,17 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, /*StrictlyPositive=*/false)) return nullptr; - return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc); -} - -static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, - DSAStackTy *Stack, CXXRecordDecl *RD) { - if (!RD || RD->isInvalidDecl()) - return true; - - auto QTy = SemaRef.Context.getRecordType(RD); - if (RD->isDynamicClass()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); - return false; - } - auto *DC = RD; - bool IsCorrect = true; - for (auto *I : DC->decls()) { - if (I) { - if (auto *MD = dyn_cast<CXXMethodDecl>(I)) { - if (MD->isStatic()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(MD->getLocation(), - diag::note_omp_static_member_in_target); - IsCorrect = false; - } - } else if (auto *VD = dyn_cast<VarDecl>(I)) { - if (VD->isStaticDataMember()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(VD->getLocation(), - diag::note_omp_static_member_in_target); - IsCorrect = false; - } - } - } + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_device); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); } - for (auto &I : RD->bases()) { - if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack, - I.getType()->getAsCXXRecordDecl())) - IsCorrect = false; - } - return IsCorrect; + return new (Context) + OMPDeviceClause(ValExpr, HelperValStmt, StartLoc, LParenLoc, EndLoc); } static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, @@ -10341,9 +11370,6 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, if (QTy->isIncompleteType(&ND)) { SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; - } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) { - if (!RD->isInvalidDecl() && !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) - return false; } return true; } @@ -10443,7 +11469,7 @@ static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, static Expr *CheckMapClauseExpressionBase( Sema &SemaRef, Expr *E, OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, - OpenMPClauseKind CKind) { + OpenMPClauseKind CKind, bool NoDiagnose) { SourceLocation ELoc = E->getExprLoc(); SourceRange ERange = E->getSourceRange(); @@ -10493,7 +11519,7 @@ static Expr *CheckMapClauseExpressionBase( if (auto *CurE = dyn_cast<DeclRefExpr>(E)) { if (!isa<VarDecl>(CurE->getDecl())) - break; + return nullptr; RelevantExpr = CurE; @@ -10503,12 +11529,8 @@ static Expr *CheckMapClauseExpressionBase( AllowWholeSizeArraySection = false; // Record the component. - CurComponents.push_back(OMPClauseMappableExprCommon::MappableComponent( - CurE, CurE->getDecl())); - continue; - } - - if (auto *CurE = dyn_cast<MemberExpr>(E)) { + CurComponents.emplace_back(CurE, CurE->getDecl()); + } else if (auto *CurE = dyn_cast<MemberExpr>(E)) { auto *BaseE = CurE->getBase()->IgnoreParenImpCasts(); if (isa<CXXThisExpr>(BaseE)) @@ -10518,9 +11540,14 @@ static Expr *CheckMapClauseExpressionBase( E = BaseE; if (!isa<FieldDecl>(CurE->getMemberDecl())) { - SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) - << CurE->getSourceRange(); - break; + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) + << CurE->getSourceRange(); + return nullptr; + } + if (RelevantExpr) + return nullptr; + continue; } auto *FD = cast<FieldDecl>(CurE->getMemberDecl()); @@ -10529,9 +11556,14 @@ static Expr *CheckMapClauseExpressionBase( // A bit-field cannot appear in a map clause. // if (FD->isBitField()) { - SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) - << CurE->getSourceRange() << getOpenMPClauseName(CKind); - break; + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) + << CurE->getSourceRange() << getOpenMPClauseName(CKind); + return nullptr; + } + if (RelevantExpr) + return nullptr; + continue; } // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] @@ -10543,12 +11575,16 @@ static Expr *CheckMapClauseExpressionBase( // A list item cannot be a variable that is a member of a structure with // a union type. // - if (auto *RT = CurType->getAs<RecordType>()) + if (auto *RT = CurType->getAs<RecordType>()) { if (RT->isUnionType()) { - SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) - << CurE->getSourceRange(); - break; + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << CurE->getSourceRange(); + return nullptr; + } + continue; } + } // If we got a member expression, we should not expect any array section // before that: @@ -10561,18 +11597,17 @@ static Expr *CheckMapClauseExpressionBase( AllowWholeSizeArraySection = false; // Record the component. - CurComponents.push_back( - OMPClauseMappableExprCommon::MappableComponent(CurE, FD)); - continue; - } - - if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { + CurComponents.emplace_back(CurE, FD); + } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { E = CurE->getBase()->IgnoreParenImpCasts(); if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { - SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) - << 0 << CurE->getSourceRange(); - break; + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << CurE->getSourceRange(); + return nullptr; + } + continue; } // If we got an array subscript that express the whole dimension we @@ -10583,15 +11618,12 @@ static Expr *CheckMapClauseExpressionBase( AllowWholeSizeArraySection = false; // Record the component - we don't have any declaration associated. - CurComponents.push_back( - OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); - continue; - } - - if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { + CurComponents.emplace_back(CurE, nullptr); + } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { + assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); E = CurE->getBase()->IgnoreParenImpCasts(); - auto CurType = + QualType CurType = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] @@ -10605,7 +11637,7 @@ static Expr *CheckMapClauseExpressionBase( if (!IsPointer && !CurType->isArrayType()) { SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) << 0 << CurE->getSourceRange(); - break; + return nullptr; } bool NotWhole = @@ -10628,20 +11660,20 @@ static Expr *CheckMapClauseExpressionBase( SemaRef.Diag( ELoc, diag::err_array_section_does_not_specify_contiguous_storage) << CurE->getSourceRange(); - break; + return nullptr; } // Record the component - we don't have any declaration associated. - CurComponents.push_back( - OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); - continue; + CurComponents.emplace_back(CurE, nullptr); + } else { + if (!NoDiagnose) { + // If nothing else worked, this is not a valid map clause expression. + SemaRef.Diag( + ELoc, diag::err_omp_expected_named_var_member_or_array_expression) + << ERange; + } + return nullptr; } - - // If nothing else worked, this is not a valid map clause expression. - SemaRef.Diag(ELoc, - diag::err_omp_expected_named_var_member_or_array_expression) - << ERange; - break; } return RelevantExpr; @@ -10932,8 +11964,8 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // Obtain the array or member expression bases if required. Also, fill the // components array with all the components identified in the process. - auto *BE = - CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind); + auto *BE = CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, + CKind, /*NoDiagnose=*/false); if (!BE) continue; @@ -11123,7 +12155,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( Decls.reserve(ReductionTypes.size()); LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName, - ForRedeclaration); + forRedeclarationInCurContext()); // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions // A reduction-identifier may not be re-declared in the current scope for the // same type or for a type that is compatible according to the base language @@ -11253,7 +12285,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) { DRD->setInvalidDecl(); } -void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { +VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { auto *DRD = cast<OMPDeclareReductionDecl>(D); // Enter new function scope. @@ -11292,10 +12324,11 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { DRD->addDecl(OmpPrivParm); DRD->addDecl(OmpOrigParm); } + return OmpPrivParm; } -void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, - Expr *Initializer) { +void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, + VarDecl *OmpPrivParm) { auto *DRD = cast<OMPDeclareReductionDecl>(D); DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); @@ -11303,10 +12336,16 @@ void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, PopDeclContext(); PopFunctionScopeInfo(); - if (Initializer != nullptr) - DRD->setInitializer(Initializer); - else + if (Initializer != nullptr) { + DRD->setInitializer(Initializer, OMPDeclareReductionDecl::CallInit); + } else if (OmpPrivParm->hasInit()) { + DRD->setInitializer(OmpPrivParm->getInit(), + OmpPrivParm->isDirectInit() + ? OMPDeclareReductionDecl::DirectInit + : OMPDeclareReductionDecl::CopyInit); + } else { DRD->setInvalidDecl(); + } } Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( @@ -11328,7 +12367,6 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation EndLoc) { Expr *ValExpr = NumTeams; Stmt *HelperValStmt = nullptr; - OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [teams Constrcut, Restrictions] // The num_teams expression must evaluate to a positive integer value. @@ -11337,8 +12375,9 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams); - if (CaptureRegion != OMPD_unknown) { + OpenMPDirectiveKind CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); @@ -11354,7 +12393,6 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation EndLoc) { Expr *ValExpr = ThreadLimit; Stmt *HelperValStmt = nullptr; - OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [teams Constrcut, Restrictions] // The thread_limit expression must evaluate to a positive integer value. @@ -11363,8 +12401,9 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit); - if (CaptureRegion != OMPD_unknown) { + OpenMPDirectiveKind CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); @@ -11471,7 +12510,9 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause( << "dist_schedule" << ChunkSize->getSourceRange(); return nullptr; } - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + } else if (getOpenMPCaptureRegionForClause( + DSAStack->getCurrentDirective(), OMPC_dist_schedule) != + OMPD_unknown && !CurContext->isDependentContext()) { llvm::MapVector<Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); @@ -11508,6 +12549,7 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( << Value << getOpenMPClauseName(OMPC_defaultmap); return nullptr; } + DSAStack->setDefaultDMAToFromScalar(StartLoc); return new (Context) OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); @@ -11517,7 +12559,11 @@ bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) { DeclContext *CurLexicalContext = getCurLexicalContext(); if (!CurLexicalContext->isFileContext() && !CurLexicalContext->isExternCContext() && - !CurLexicalContext->isExternCXXContext()) { + !CurLexicalContext->isExternCXXContext() && + !isa<CXXRecordDecl>(CurLexicalContext) && + !isa<ClassTemplateDecl>(CurLexicalContext) && + !isa<ClassTemplatePartialSpecializationDecl>(CurLexicalContext) && + !isa<ClassTemplateSpecializationDecl>(CurLexicalContext)) { Diag(Loc, diag::err_omp_region_not_file_context); return false; } @@ -11574,7 +12620,7 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, ND->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); - checkDeclIsAllowedInOpenMPTarget(nullptr, ND); + checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc()); } else if (ND->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() != MT) { Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) << Id.getName(); @@ -11663,7 +12709,8 @@ static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, return true; } -void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { +void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, + SourceLocation IdLoc) { if (!D || D->isInvalidDecl()) return; SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); @@ -11692,6 +12739,16 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { return; } } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->hasAttr<OMPDeclareTargetDeclAttr>() && + (FD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() == + OMPDeclareTargetDeclAttr::MT_Link)) { + assert(IdLoc.isValid() && "Source location is expected"); + Diag(IdLoc, diag::err_omp_function_in_link_clause); + Diag(FD->getLocation(), diag::note_defined_here) << FD; + return; + } + } if (!E) { // Checking declaration inside declare target region. if (!D->hasAttr<OMPDeclareTargetDeclAttr>() && diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 36f24fd9c463a..268be9430a56e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandidates() { } } -void OverloadCandidateSet::clear() { +void OverloadCandidateSet::clear(CandidateSetKind CSK) { destroyCandidates(); SlabAllocator.Reset(); NumInlineBytesUsed = 0; Candidates.clear(); Functions.clear(); + Kind = CSK; } namespace { @@ -1481,6 +1482,23 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, .getTypePtr()); Changed = true; } + + // Convert FromFPT's ExtParameterInfo if necessary. The conversion is valid + // only if the ExtParameterInfo lists of the two function prototypes can be + // merged and the merged list is identical to ToFPT's ExtParameterInfo list. + SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos; + bool CanUseToFPT, CanUseFromFPT; + if (Context.mergeExtParameterInfo(ToFPT, FromFPT, CanUseToFPT, + CanUseFromFPT, NewParamInfos) && + CanUseToFPT && !CanUseFromFPT) { + FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo(); + ExtInfo.ExtParameterInfos = + NewParamInfos.empty() ? nullptr : NewParamInfos.data(); + QualType QT = Context.getFunctionType(FromFPT->getReturnType(), + FromFPT->getParamTypes(), ExtInfo); + FromFn = QT->getAs<FunctionType>(); + Changed = true; + } } if (!Changed) @@ -2663,8 +2681,12 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, // Argument types are too different. Abort. return false; } - if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType, - ToFunctionType)) + + SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos; + bool CanUseToFPT, CanUseFromFPT; + if (!Context.mergeExtParameterInfo(ToFunctionType, FromFunctionType, + CanUseToFPT, CanUseFromFPT, + NewParamInfos)) return false; ConvertedType = ToType; @@ -3154,6 +3176,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence &User, OverloadCandidateSet &CandidateSet, bool AllowExplicit) { + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); for (auto *D : S.LookupConstructors(To)) { auto Info = getConstructorInfo(D); if (!Info) @@ -3182,7 +3205,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, OverloadCandidateSet::iterator Best; switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(), - Best, true)) { + Best)) { case OR_Deleted: case OR_Success: { // Record the standard conversion we used and the conversion function. @@ -3229,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, bool AllowExplicit, bool AllowObjCConversionOnExplicit) { assert(AllowExplicit || !AllowObjCConversionOnExplicit); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Whether we will only visit constructors. bool ConstructorsOnly = false; @@ -3264,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (Result != OR_No_Viable_Function) return Result; // Never mind. - CandidateSet.clear(); + CandidateSet.clear( + OverloadCandidateSet::CSK_InitByUserDefinedConversion); // If we're list-initializing, we pass the individual elements as // arguments, not the entire list. @@ -3354,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, OverloadCandidateSet::iterator Best; switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(), - Best, true)) { + Best)) { case OR_Success: case OR_Deleted: // Record the standard conversion we used and the conversion function. @@ -4288,7 +4313,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet( + DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { NamedDecl *D = *I; @@ -4358,7 +4384,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, bool HadMultipleCandidates = (CandidateSet.size() > 1); OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { + switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) { case OR_Success: // C++ [over.ics.ref]p1: // @@ -6317,24 +6343,36 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, OverloadCandidateSet& CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, bool SuppressUserConversions, - bool PartialOverloading) { + bool PartialOverloading, + bool FirstArgumentIsBase) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { NamedDecl *D = F.getDecl()->getUnderlyingDecl(); if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + ArrayRef<Expr *> FunctionArgs = Args; if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) { QualType ObjectType; Expr::Classification ObjectClassification; - if (Expr *E = Args[0]) { - // Use the explit base to restrict the lookup: - ObjectType = E->getType(); - ObjectClassification = E->Classify(Context); - } // .. else there is an implit base. + if (Args.size() > 0) { + if (Expr *E = Args[0]) { + // Use the explit base to restrict the lookup: + ObjectType = E->getType(); + ObjectClassification = E->Classify(Context); + } // .. else there is an implit base. + FunctionArgs = Args.slice(1); + } AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(FD)->getParent(), ObjectType, - ObjectClassification, Args.slice(1), CandidateSet, + ObjectClassification, FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); } else { - AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet, + // Slice the first argument (which is the base) when we access + // static method as non-static + if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) && + !isa<CXXConstructorDecl>(FD)))) { + assert(cast<CXXMethodDecl>(FD)->isStatic()); + FunctionArgs = Args.slice(1); + } + AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); } } else { @@ -6767,7 +6805,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); QualType ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -6782,6 +6821,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, ConvType = Conversion->getConversionType().getNonReferenceType(); } + // If we don't allow any conversion of the result type, ignore conversion + // functions that don't convert to exactly (possibly cv-qualified) T. + if (!AllowResultConversion && + !Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType)) + return; + // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion // operator is only a candidate if its return type is the target type or // can be converted to the target type with a qualification conversion. @@ -6935,7 +6980,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion) { assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && "Only conversion function templates permitted here"); @@ -6964,7 +7010,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, - CandidateSet, AllowObjCConversionOnExplicit); + CandidateSet, AllowObjCConversionOnExplicit, + AllowResultConversion); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -7568,53 +7615,62 @@ class BuiltinOperatorOverloadBuilder { SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; OverloadCandidateSet &CandidateSet; - // Define some constants used to index and iterate over the arithemetic types - // provided via the getArithmeticType() method below. - // The "promoted arithmetic types" are the arithmetic + static constexpr int ArithmeticTypesCap = 24; + SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes; + + // Define some indices used to iterate over the arithemetic types in + // ArithmeticTypes. The "promoted arithmetic types" are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). - static const unsigned FirstIntegralType = 4; - static const unsigned LastIntegralType = 21; - static const unsigned FirstPromotedIntegralType = 4, - LastPromotedIntegralType = 12; - static const unsigned FirstPromotedArithmeticType = 0, - LastPromotedArithmeticType = 12; - static const unsigned NumArithmeticTypes = 21; + unsigned FirstIntegralType, + LastIntegralType; + unsigned FirstPromotedIntegralType, + LastPromotedIntegralType; + unsigned FirstPromotedArithmeticType, + LastPromotedArithmeticType; + unsigned NumArithmeticTypes; - /// \brief Get the canonical type for a given arithmetic type index. - CanQualType getArithmeticType(unsigned index) { - assert(index < NumArithmeticTypes); - static CanQualType ASTContext::* const - ArithmeticTypes[NumArithmeticTypes] = { - // Start of promoted types. - &ASTContext::FloatTy, - &ASTContext::DoubleTy, - &ASTContext::LongDoubleTy, - &ASTContext::Float128Ty, + void InitArithmeticTypes() { + // Start of promoted types. + FirstPromotedArithmeticType = 0; + ArithmeticTypes.push_back(S.Context.FloatTy); + ArithmeticTypes.push_back(S.Context.DoubleTy); + ArithmeticTypes.push_back(S.Context.LongDoubleTy); + if (S.Context.getTargetInfo().hasFloat128Type()) + ArithmeticTypes.push_back(S.Context.Float128Ty); - // Start of integral types. - &ASTContext::IntTy, - &ASTContext::LongTy, - &ASTContext::LongLongTy, - &ASTContext::Int128Ty, - &ASTContext::UnsignedIntTy, - &ASTContext::UnsignedLongTy, - &ASTContext::UnsignedLongLongTy, - &ASTContext::UnsignedInt128Ty, - // End of promoted types. + // Start of integral types. + FirstIntegralType = ArithmeticTypes.size(); + FirstPromotedIntegralType = ArithmeticTypes.size(); + ArithmeticTypes.push_back(S.Context.IntTy); + ArithmeticTypes.push_back(S.Context.LongTy); + ArithmeticTypes.push_back(S.Context.LongLongTy); + if (S.Context.getTargetInfo().hasInt128Type()) + ArithmeticTypes.push_back(S.Context.Int128Ty); + ArithmeticTypes.push_back(S.Context.UnsignedIntTy); + ArithmeticTypes.push_back(S.Context.UnsignedLongTy); + ArithmeticTypes.push_back(S.Context.UnsignedLongLongTy); + if (S.Context.getTargetInfo().hasInt128Type()) + ArithmeticTypes.push_back(S.Context.UnsignedInt128Ty); + LastPromotedIntegralType = ArithmeticTypes.size(); + LastPromotedArithmeticType = ArithmeticTypes.size(); + // End of promoted types. - &ASTContext::BoolTy, - &ASTContext::CharTy, - &ASTContext::WCharTy, - &ASTContext::Char16Ty, - &ASTContext::Char32Ty, - &ASTContext::SignedCharTy, - &ASTContext::ShortTy, - &ASTContext::UnsignedCharTy, - &ASTContext::UnsignedShortTy, - // End of integral types. - // FIXME: What about complex? What about half? - }; - return S.Context.*ArithmeticTypes[index]; + ArithmeticTypes.push_back(S.Context.BoolTy); + ArithmeticTypes.push_back(S.Context.CharTy); + ArithmeticTypes.push_back(S.Context.WCharTy); + ArithmeticTypes.push_back(S.Context.Char16Ty); + ArithmeticTypes.push_back(S.Context.Char32Ty); + ArithmeticTypes.push_back(S.Context.SignedCharTy); + ArithmeticTypes.push_back(S.Context.ShortTy); + ArithmeticTypes.push_back(S.Context.UnsignedCharTy); + ArithmeticTypes.push_back(S.Context.UnsignedShortTy); + LastIntegralType = ArithmeticTypes.size(); + NumArithmeticTypes = ArithmeticTypes.size(); + // End of integral types. + // FIXME: What about complex? What about half? + + assert(ArithmeticTypes.size() <= ArithmeticTypesCap && + "Enough inline storage for all arithmetic types."); } /// \brief Helper method to factor out the common pattern of adding overloads @@ -7673,18 +7729,8 @@ public: HasArithmeticOrEnumeralCandidateType), CandidateTypes(CandidateTypes), CandidateSet(CandidateSet) { - // Validate some of our static helper constants in debug builds. - assert(getArithmeticType(FirstPromotedIntegralType) == S.Context.IntTy && - "Invalid first promoted integral type"); - assert(getArithmeticType(LastPromotedIntegralType - 1) - == S.Context.UnsignedInt128Ty && - "Invalid last promoted integral type"); - assert(getArithmeticType(FirstPromotedArithmeticType) - == S.Context.FloatTy && - "Invalid first promoted arithmetic type"); - assert(getArithmeticType(LastPromotedArithmeticType - 1) - == S.Context.UnsignedInt128Ty && - "Invalid last promoted arithmetic type"); + + InitArithmeticTypes(); } // C++ [over.built]p3: @@ -7711,7 +7757,7 @@ public: for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); Arith < NumArithmeticTypes; ++Arith) { addPlusPlusMinusMinusStyleOverloads( - getArithmeticType(Arith), + ArithmeticTypes[Arith], VisibleTypeConversionsQuals.hasVolatile(), VisibleTypeConversionsQuals.hasRestrict()); } @@ -7784,7 +7830,7 @@ public: for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { - QualType ArithTy = getArithmeticType(Arith); + QualType ArithTy = ArithmeticTypes[Arith]; S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet); } @@ -7824,7 +7870,7 @@ public: for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { - QualType IntTy = getArithmeticType(Int); + QualType IntTy = ArithmeticTypes[Int]; S.AddBuiltinCandidate(&IntTy, Args, CandidateSet); } @@ -8052,8 +8098,8 @@ public: Left < LastPromotedArithmeticType; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { - QualType LandR[2] = { getArithmeticType(Left), - getArithmeticType(Right) }; + QualType LandR[2] = { ArithmeticTypes[Left], + ArithmeticTypes[Right] }; S.AddBuiltinCandidate(LandR, Args, CandidateSet); } } @@ -8096,8 +8142,8 @@ public: Left < LastPromotedIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { - QualType LandR[2] = { getArithmeticType(Left), - getArithmeticType(Right) }; + QualType LandR[2] = { ArithmeticTypes[Left], + ArithmeticTypes[Right] }; S.AddBuiltinCandidate(LandR, Args, CandidateSet); } } @@ -8277,18 +8323,18 @@ public: for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = getArithmeticType(Right); + ParamTypes[1] = ArithmeticTypes[Right]; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = - S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.Context.getLValueReferenceType(ArithmeticTypes[Left]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { ParamTypes[0] = - S.Context.getVolatileType(getArithmeticType(Left)); + S.Context.getVolatileType(ArithmeticTypes[Left]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); @@ -8343,15 +8389,15 @@ public: for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = getArithmeticType(Right); + ParamTypes[1] = ArithmeticTypes[Right]; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = - S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.Context.getLValueReferenceType(ArithmeticTypes[Left]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = getArithmeticType(Left); + ParamTypes[0] = ArithmeticTypes[Left]; ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); @@ -8646,6 +8692,9 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, OpBuilder.addGenericBinaryArithmeticOverloads(); break; + case OO_Spaceship: + llvm_unreachable("<=> expressions not supported yet"); + case OO_Percent: case OO_Caret: case OO_Pipe: @@ -8823,10 +8872,9 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). -bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, - const OverloadCandidate &Cand2, - SourceLocation Loc, - bool UserDefinedConversion) { +bool clang::isBetterOverloadCandidate( + Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2, + SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -8908,7 +8956,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, // the type of the entity being initialized) is a better // conversion sequence than the standard conversion sequence // from the return type of F2 to the destination type. - if (UserDefinedConversion && Cand1.Function && Cand2.Function && + if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion && + Cand1.Function && Cand2.Function && isa<CXXConversionDecl>(Cand1.Function) && isa<CXXConversionDecl>(Cand2.Function)) { // First check whether we prefer one of the conversion functions over the @@ -8930,11 +8979,17 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, // C++14 [over.match.best]p1 section 2 bullet 3. } - // -- F1 is generated from a deduction-guide and F2 is not - auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function); - auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function); - if (Guide1 && Guide2 && Guide1->isImplicit() != Guide2->isImplicit()) - return Guide2->isImplicit(); + // FIXME: Work around a defect in the C++17 guaranteed copy elision wording, + // as combined with the resolution to CWG issue 243. + // + // When the context is initialization by constructor ([over.match.ctor] or + // either phase of [over.match.list]), a constructor is preferred over + // a conversion function. + if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 && + Cand1.Function && Cand2.Function && + isa<CXXConstructorDecl>(Cand1.Function) != + isa<CXXConstructorDecl>(Cand2.Function)) + return isa<CXXConstructorDecl>(Cand1.Function); // -- F1 is a non-template function and F2 is a function template // specialization, or, if not that, @@ -8980,6 +9035,21 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, // Inherited from sibling base classes: still ambiguous. } + // Check C++17 tie-breakers for deduction guides. + { + auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function); + auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function); + if (Guide1 && Guide2) { + // -- F1 is generated from a deduction-guide and F2 is not + if (Guide1->isImplicit() != Guide2->isImplicit()) + return Guide2->isImplicit(); + + // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not + if (Guide1->isCopyDeductionCandidate()) + return true; + } + } + // Check for enable_if value-based overload resolution. if (Cand1.Function && Cand2.Function) { Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function); @@ -9079,8 +9149,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( /// \returns The result of overload resolution. OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best, - bool UserDefinedConversion) { + iterator &Best) { llvm::SmallVector<OverloadCandidate *, 16> Candidates; std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); @@ -9114,8 +9183,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, Best = end(); for (auto *Cand : Candidates) if (Cand->Viable) - if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, - UserDefinedConversion)) + if (Best == end() || + isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind)) Best = Cand; // If we didn't find any viable functions, abort. @@ -9127,10 +9196,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. for (auto *Cand : Candidates) { - if (Cand->Viable && - Cand != Best && - !isBetterOverloadCandidate(S, *Best, *Cand, Loc, - UserDefinedConversion)) { + if (Cand->Viable && Cand != Best && + !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) { if (S.isEquivalentInternalLinkageDeclaration(Best->Function, Cand->Function)) { EquivalentCands.push_back(Cand->Function); @@ -10222,9 +10289,12 @@ struct CompareOverloadCandidatesForDisplay { Sema &S; SourceLocation Loc; size_t NumArgs; + OverloadCandidateSet::CandidateSetKind CSK; - CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs) - : S(S), NumArgs(nArgs) {} + CompareOverloadCandidatesForDisplay( + Sema &S, SourceLocation Loc, size_t NArgs, + OverloadCandidateSet::CandidateSetKind CSK) + : S(S), NumArgs(NArgs), CSK(CSK) {} bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { @@ -10238,8 +10308,10 @@ struct CompareOverloadCandidatesForDisplay { // TODO: introduce a tri-valued comparison for overload // candidates. Would be more worthwhile if we had a sort // that could exploit it. - if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true; - if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false; + if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK)) + return true; + if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK)) + return false; } else if (R->Viable) return false; @@ -10446,8 +10518,8 @@ void OverloadCandidateSet::NoteCandidates( } } - std::sort(Cands.begin(), Cands.end(), - CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size())); + std::stable_sort(Cands.begin(), Cands.end(), + CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind)); bool ReportedAmbiguousConversions = false; @@ -10627,7 +10699,7 @@ static bool completeFunctionType(Sema &S, FunctionDecl *FD, SourceLocation Loc, return true; auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (S.getLangOpts().CPlusPlus1z && + if (S.getLangOpts().CPlusPlus17 && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && !S.ResolveExceptionSpec(Loc, FPT)) return true; @@ -11878,7 +11950,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) { ExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *Input) { + Expr *Input, bool PerformADL) { OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc); assert(Op != OO_None && "Invalid opcode for overloaded unary operator"); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); @@ -11929,9 +12001,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); // Add candidates from ADL. - AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray, - /*ExplicitTemplateArgs*/nullptr, - CandidateSet); + if (PerformADL) { + AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray, + /*ExplicitTemplateArgs*/nullptr, + CandidateSet); + } // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); @@ -12069,7 +12143,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS) { + Expr *LHS, Expr *RHS, bool PerformADL) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple @@ -12100,7 +12174,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo, - /*ADL*/ true, IsOverloaded(Fns), + /*ADL*/PerformADL, IsOverloaded(Fns), Fns.begin(), Fns.end()); return new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy, @@ -12143,7 +12217,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not // performed for an assignment operator (nor for operator[] nor operator->, // which don't get here). - if (Opc != BO_Assign) + if (Opc != BO_Assign && PerformADL) AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, /*ExplicitTemplateArgs*/ nullptr, CandidateSet); @@ -12896,7 +12970,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(), - Best)) { + Best)) { case OR_Success: // Overload resolution succeeded; we'll build the appropriate call // below. @@ -13290,7 +13364,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc, Expr *Range, ExprResult *CallExpr) { Scope *S = nullptr; - CandidateSet->clear(); + CandidateSet->clear(OverloadCandidateSet::CSK_Normal); if (!MemberLookup.empty()) { ExprResult MemberRef = BuildMemberReferenceExpr(Range, Range->getType(), Loc, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp index d159172a69908..58980be64a30f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp @@ -1442,8 +1442,7 @@ MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) { Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { InstanceBase = capture(RefExpr->getBaseExpr()); - std::for_each(CallArgs.begin(), CallArgs.end(), - [this](Expr *&Arg) { Arg = capture(Arg); }); + llvm::for_each(CallArgs, [this](Expr *&Arg) { Arg = capture(Arg); }); syntacticBase = Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * { switch (Idx) { case 0: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 2a38a1f8e1d87..ff0f4d9958512 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -127,34 +127,47 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { /// warning from firing. static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { SourceLocation Loc; - bool IsNotEqual, CanAssign, IsRelational; + bool CanAssign; + enum { Equality, Inequality, Relational, ThreeWay } Kind; if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { if (!Op->isComparisonOp()) return false; - IsRelational = Op->isRelationalOp(); + if (Op->getOpcode() == BO_EQ) + Kind = Equality; + else if (Op->getOpcode() == BO_NE) + Kind = Inequality; + else if (Op->getOpcode() == BO_Cmp) + Kind = ThreeWay; + else { + assert(Op->isRelationalOp()); + Kind = Relational; + } Loc = Op->getOperatorLoc(); - IsNotEqual = Op->getOpcode() == BO_NE; CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue(); } else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { switch (Op->getOperator()) { - default: - return false; case OO_EqualEqual: + Kind = Equality; + break; case OO_ExclaimEqual: - IsRelational = false; + Kind = Inequality; break; case OO_Less: case OO_Greater: case OO_GreaterEqual: case OO_LessEqual: - IsRelational = true; + Kind = Relational; + break; + case OO_Spaceship: + Kind = ThreeWay; break; + default: + return false; } Loc = Op->getOperatorLoc(); - IsNotEqual = Op->getOperator() == OO_ExclaimEqual; CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue(); } else { // Not a typo-prone comparison. @@ -167,15 +180,15 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { return false; S.Diag(Loc, diag::warn_unused_comparison) - << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange(); + << (unsigned)Kind << E->getSourceRange(); // If the LHS is a plausible entity to assign to, provide a fixit hint to // correct common typos. - if (!IsRelational && CanAssign) { - if (IsNotEqual) + if (CanAssign) { + if (Kind == Inequality) S.Diag(Loc, diag::note_inequality_comparison_to_or_assign) << FixItHint::CreateReplacement(Loc, "|="); - else + else if (Kind == Equality) S.Diag(Loc, diag::note_equality_comparison_to_assign) << FixItHint::CreateReplacement(Loc, "="); } @@ -602,14 +615,14 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs, /// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of /// potentially integral-promoted expression @p expr. -static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) { - if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr)) - expr = cleanups->getSubExpr(); - while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) { - if (impcast->getCastKind() != CK_IntegralCast) break; - expr = impcast->getSubExpr(); +static QualType GetTypeBeforeIntegralPromotion(const Expr *&E) { + if (const auto *CleanUps = dyn_cast<ExprWithCleanups>(E)) + E = CleanUps->getSubExpr(); + while (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) { + if (ImpCast->getCastKind() != CK_IntegralCast) break; + E = ImpCast->getSubExpr(); } - return expr->getType(); + return E->getType(); } ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) { @@ -743,6 +756,32 @@ static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S, return true; } +static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond, + const Expr *Case) { + QualType CondType = GetTypeBeforeIntegralPromotion(Cond); + QualType CaseType = Case->getType(); + + const EnumType *CondEnumType = CondType->getAs<EnumType>(); + const EnumType *CaseEnumType = CaseType->getAs<EnumType>(); + if (!CondEnumType || !CaseEnumType) + return; + + // Ignore anonymous enums. + if (!CondEnumType->getDecl()->getIdentifier() && + !CondEnumType->getDecl()->getTypedefNameForAnonDecl()) + return; + if (!CaseEnumType->getDecl()->getIdentifier() && + !CaseEnumType->getDecl()->getTypedefNameForAnonDecl()) + return; + + if (S.Context.hasSameUnqualifiedType(CondType, CaseType)) + return; + + S.Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch) + << CondType << CaseType << Cond->getSourceRange() + << Case->getSourceRange(); +} + StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { @@ -760,7 +799,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, QualType CondType = CondExpr->getType(); - Expr *CondExprBeforePromotion = CondExpr; + const Expr *CondExprBeforePromotion = CondExpr; QualType CondTypeBeforePromotion = GetTypeBeforeIntegralPromotion(CondExprBeforePromotion); @@ -843,6 +882,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, break; } + checkEnumTypesInSwitchStmt(*this, CondExpr, Lo); + llvm::APSInt LoVal; if (getLangOpts().CPlusPlus11) { @@ -2452,7 +2493,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // C++1z removes this restriction. QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); if (!Context.hasSameType(BeginType, EndType)) { - Diag(RangeLoc, getLangOpts().CPlusPlus1z + Diag(RangeLoc, getLangOpts().CPlusPlus17 ? diag::warn_for_range_begin_end_types_differ : diag::ext_for_range_begin_end_types_differ) << BeginType << EndType; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp index c182b35bfad4c..fc1cc7bbe544b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp @@ -48,10 +48,10 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { if (E != E2 && E2->isLValue()) { if (!S.getLangOpts().HeinousExtensions) S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) - << E->getSourceRange(); + << E->getSourceRange(); else S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) - << E->getSourceRange(); + << E->getSourceRange(); // Accept, even if we emitted an error diagnostic. return false; } @@ -62,11 +62,13 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { /// isOperandMentioned - Return true if the specified operand # is mentioned /// anywhere in the decomposed asm string. -static bool isOperandMentioned(unsigned OpNo, - ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) { +static bool +isOperandMentioned(unsigned OpNo, + ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) { for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; - if (!Piece.isOperand()) continue; + if (!Piece.isOperand()) + continue; // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. @@ -605,23 +607,31 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return NS; } -static void fillInlineAsmTypeInfo(const ASTContext &Context, QualType T, - llvm::InlineAsmIdentifierInfo &Info) { - // Compute the type size (and array length if applicable?). - Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); - if (T->isArrayType()) { - const ArrayType *ATy = Context.getAsArrayType(T); - Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); - Info.Length = Info.Size / Info.Type; +void Sema::FillInlineAsmIdentifierInfo(Expr *Res, + llvm::InlineAsmIdentifierInfo &Info) { + QualType T = Res->getType(); + Expr::EvalResult Eval; + if (T->isFunctionType() || T->isDependentType()) + return Info.setLabel(Res); + if (Res->isRValue()) { + if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context)) + return Info.setEnum(Eval.Val.getInt().getSExtValue()); + return Info.setLabel(Res); } + unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); + unsigned Type = Size; + if (const auto *ATy = Context.getAsArrayType(T)) + Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); + bool IsGlobalLV = false; + if (Res->EvaluateAsLValue(Eval, Context)) + IsGlobalLV = Eval.isGlobalLValue(); + Info.setVar(Res, IsGlobalLV, Size, Type); } ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, - llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) { - Info.clear(); if (IsUnevaluatedContext) PushExpressionEvaluationContext( @@ -662,12 +672,6 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, return ExprError(); } - fillInlineAsmTypeInfo(Context, T, Info); - - // We can work with the expression as long as it's not an r-value. - if (!Result.get()->isRValue()) - Info.IsVarDecl = true; - return Result; } @@ -677,22 +681,33 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, SmallVector<StringRef, 2> Members; Member.split(Members, "."); - LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(), - LookupOrdinaryName); + NamedDecl *FoundDecl = nullptr; - if (!LookupName(BaseResult, getCurScope())) - return true; - - if(!BaseResult.isSingleResult()) + // MS InlineAsm uses 'this' as a base + if (getLangOpts().CPlusPlus && Base.equals("this")) { + if (const Type *PT = getCurrentThisType().getTypePtrOrNull()) + FoundDecl = PT->getPointeeType()->getAsTagDecl(); + } else { + LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(), + LookupOrdinaryName); + if (LookupName(BaseResult, getCurScope()) && BaseResult.isSingleResult()) + FoundDecl = BaseResult.getFoundDecl(); + } + + if (!FoundDecl) return true; - NamedDecl *FoundDecl = BaseResult.getFoundDecl(); + for (StringRef NextMember : Members) { const RecordType *RT = nullptr; if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) RT = VD->getType()->getAs<RecordType>(); else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) { MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); - RT = TD->getUnderlyingType()->getAs<RecordType>(); + // MS InlineAsm often uses struct pointer aliases as a base + QualType QT = TD->getUnderlyingType(); + if (const auto *PT = QT->getAs<PointerType>()) + QT = PT->getPointeeType(); + RT = QT->getAs<RecordType>(); } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl)) RT = TD->getTypeForDecl()->getAs<RecordType>(); else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl)) @@ -730,9 +745,7 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, ExprResult Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, - llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc) { - Info.clear(); QualType T = E->getType(); if (T->isDependentType()) { @@ -767,14 +780,6 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, ExprResult Result = BuildMemberReferenceExpr( E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(), SourceLocation(), nullptr, FieldResult, nullptr, nullptr); - if (Result.isInvalid()) - return Result; - Info.OpDecl = Result.get(); - - fillInlineAsmTypeInfo(Context, Result.get()->getType(), Info); - - // Fields are "variables" as far as inline assembly is concerned. - Info.IsVarDecl = true; return Result; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp index 4ee3412170a85..e55e20c2827f0 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp @@ -43,11 +43,11 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, return nullptr; } - // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() && + if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() && !A.getScopeName()) - S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName(); + S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName(); FnScope->setHasFallthroughStmt(); return ::new (S.Context) auto(Attr); @@ -100,16 +100,15 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, return nullptr; } - LoopHintAttr::Spelling Spelling; + LoopHintAttr::Spelling Spelling = + LoopHintAttr::Spelling(A.getAttributeSpellingListIndex()); LoopHintAttr::OptionType Option; LoopHintAttr::LoopHintState State; if (PragmaNoUnroll) { // #pragma nounroll - Spelling = LoopHintAttr::Pragma_nounroll; Option = LoopHintAttr::Unroll; State = LoopHintAttr::Disable; } else if (PragmaUnroll) { - Spelling = LoopHintAttr::Pragma_unroll; if (ValueExpr) { // #pragma unroll N Option = LoopHintAttr::UnrollCount; @@ -121,7 +120,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, } } else { // #pragma clang loop ... - Spelling = LoopHintAttr::Pragma_clang_loop; assert(OptionLoc && OptionLoc->Ident && "Attribute must have valid option info."); Option = llvm::StringSwitch<LoopHintAttr::OptionType>( diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index e9b38551683cf..c70a8ba8f1269 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -778,7 +778,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( - S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); + S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } @@ -1080,7 +1080,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ArrayRef<Decl *> Params, + ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, Expr *RequiresClause) { if (ExportLoc.isValid()) @@ -1088,7 +1088,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, return TemplateParameterList::Create( Context, TemplateLoc, LAngleLoc, - llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()), + llvm::makeArrayRef(Params.data(), Params.size()), RAngleLoc, RequiresClause); } @@ -1133,7 +1133,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Previous(*this, Name, NameLoc, (SS.isEmpty() && TUK == TUK_Friend) ? LookupTagName : LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); if (SS.isNotEmpty() && !SS.isInvalid()) { SemanticContext = computeDeclContext(SS, true); if (!SemanticContext) { @@ -1192,8 +1192,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. - ClassTemplateDecl *PrevClassTemplate - = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + ClassTemplateDecl *PrevClassTemplate = + dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); // We may have found the injected-class-name of a class template, // class template partial specialization, or class template specialization. @@ -1484,6 +1484,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, CurContext->addDecl(Friend); } + if (PrevClassTemplate) + CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate); + if (Invalid) { NewTemplate->setInvalidDecl(); NewClass->setInvalidDecl(); @@ -1834,7 +1837,6 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // for which some class template parameter without a default argument never // appears in a deduced context). bool AddedAny = false; - bool AddedCopyOrMove = false; for (NamedDecl *D : LookupConstructors(Transform.Primary)) { D = D->getUnderlyingDecl(); if (D->isInvalidDecl() || D->isImplicit()) @@ -1851,20 +1853,22 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, Transform.transformConstructor(FTD, CD); AddedAny = true; - - AddedCopyOrMove |= CD->isCopyOrMoveConstructor(); } - // Synthesize an X() -> X<...> guide if there were no declared constructors. - // FIXME: The standard doesn't say (how) to do this. + // C++17 [over.match.class.deduct] + // -- If C is not defined or does not declare any constructors, an + // additional function template derived as above from a hypothetical + // constructor C(). if (!AddedAny) Transform.buildSimpleDeductionGuide(None); - // Synthesize an X(X<...>) -> X<...> guide if there was no declared constructor - // resembling a copy or move constructor. - // FIXME: The standard doesn't say (how) to do this. - if (!AddedCopyOrMove) - Transform.buildSimpleDeductionGuide(Transform.DeducedType); + // -- An additional function template derived as above from a hypothetical + // constructor C(C), called the copy deduction candidate. + cast<CXXDeductionGuideDecl>( + cast<FunctionTemplateDecl>( + Transform.buildSimpleDeductionGuide(Transform.DeducedType)) + ->getTemplatedDecl()) + ->setIsCopyDeductionCandidate(); } /// \brief Diagnose the presence of a default template argument on a @@ -2863,11 +2867,9 @@ static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) { return Cond; } -/// Find the failed subexpression within enable_if, and describe it -/// with a string. -static std::pair<Expr *, std::string> -findFailedEnableIfCondition(Sema &S, Expr *Cond) { - Cond = lookThroughRangesV3Condition(S.PP, Cond); +std::pair<Expr *, std::string> +Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) { + Cond = lookThroughRangesV3Condition(PP, Cond); // Separate out all of the terms in a conjunction. SmallVector<Expr *, 4> Terms; @@ -2876,27 +2878,37 @@ findFailedEnableIfCondition(Sema &S, Expr *Cond) { // Determine which term failed. Expr *FailedCond = nullptr; for (Expr *Term : Terms) { + Expr *TermAsWritten = Term->IgnoreParenImpCasts(); + + // Literals are uninteresting. + if (isa<CXXBoolLiteralExpr>(TermAsWritten) || + isa<IntegerLiteral>(TermAsWritten)) + continue; + // The initialization of the parameter from the argument is // a constant-evaluated context. EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); bool Succeeded; - if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) && + if (Term->EvaluateAsBooleanCondition(Succeeded, Context) && !Succeeded) { - FailedCond = Term->IgnoreParenImpCasts(); + FailedCond = TermAsWritten; break; } } - if (!FailedCond) + if (!FailedCond) { + if (!AllowTopLevelCond) + return { nullptr, "" }; + FailedCond = Cond->IgnoreParenImpCasts(); + } std::string Description; { llvm::raw_string_ostream Out(Description); - FailedCond->printPretty(Out, nullptr, - PrintingPolicy(S.Context.getLangOpts())); + FailedCond->printPretty(Out, nullptr, getPrintingPolicy()); } return { FailedCond, Description }; } @@ -2980,8 +2992,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Expr *FailedCond; std::string FailedDescription; std::tie(FailedCond, FailedDescription) = - findFailedEnableIfCondition( - *this, TemplateArgs[0].getSourceExpression()); + findFailedBooleanCondition( + TemplateArgs[0].getSourceExpression(), + /*AllowTopLevelCond=*/true); // Remove the old SFINAE diagnostic. PartialDiagnosticAt OldDiag = @@ -3668,7 +3681,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // Check that this isn't a redefinition of this specialization, // merging with previous declarations. LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); PrevSpec.addDecl(PrevDecl); D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec)); } else if (Specialization->isStaticDataMember() && @@ -4792,7 +4805,12 @@ bool Sema::CheckTemplateArgumentList( // template. TemplateArgumentListInfo NewArgs = TemplateArgs; - TemplateParameterList *Params = Template->getTemplateParameters(); + // Make sure we get the template parameter list from the most + // recentdeclaration, since that is the only one that has is guaranteed to + // have all the default template argument information. + TemplateParameterList *Params = + cast<TemplateDecl>(Template->getMostRecentDecl()) + ->getTemplateParameters(); SourceLocation RAngleLoc = NewArgs.getRAngleLoc(); @@ -5116,6 +5134,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + return Visit(T->getPointeeType()); +} + bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { return Visit(T->getElementType()); } @@ -5900,7 +5923,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, SourceLocation StartLoc = Arg->getLocStart(); // If the parameter type somehow involves auto, deduce the type now. - if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) { + if (getLangOpts().CPlusPlus17 && ParamType->isUndeducedType()) { // During template argument deduction, we allow 'decltype(auto)' to // match an arbitrary dependent argument. // FIXME: The language rules don't say what happens in this case. @@ -5984,8 +6007,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, EnterExpressionEvaluationContext ConstantEvaluated( *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); - if (getLangOpts().CPlusPlus1z) { - // C++1z [temp.arg.nontype]p1: + if (getLangOpts().CPlusPlus17) { + // C++17 [temp.arg.nontype]p1: // A template-argument for a non-type template parameter shall be // a converted constant expression of the type of the template-parameter. APValue Value; @@ -6152,7 +6175,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- an integral constant-expression of integral or enumeration // type; or // -- the name of a non-type template-parameter; or - SourceLocation NonConstantLoc; llvm::APSInt Value; if (!ArgType->isIntegralOrEnumerationType()) { Diag(Arg->getLocStart(), @@ -8015,15 +8037,6 @@ bool Sema::CheckFunctionTemplateSpecialization( // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); - // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...] - // an explicit specialization (14.8.3) [...] of a concept definition. - if (Specialization->getPrimaryTemplate()->isConcept()) { - Diag(FD->getLocation(), diag::err_concept_specialized) - << 0 /*function*/ << 1 /*explicitly specialized*/; - Diag(Specialization->getLocation(), diag::note_previous_declaration); - return true; - } - FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); assert(SpecInfo && "Function template specialization info missing?"); @@ -8910,15 +8923,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_explicit_instantiation_constexpr); - // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be - // applied only to the definition of a function template or variable template, - // declared in namespace scope. - if (D.getDeclSpec().isConceptSpecified()) { - Diag(D.getDeclSpec().getConceptSpecLoc(), - diag::err_concept_specified_specialization) << 0; - return true; - } - // A deduction guide is not on the list of entities that can be explicitly // instantiated. if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { @@ -8998,15 +9002,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return true; } - // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an - // explicit instantiation (14.8.2) [...] of a concept definition. - if (PrevTemplate->isConcept()) { - Diag(D.getIdentifierLoc(), diag::err_concept_specialized) - << 1 /*variable*/ << 0 /*explicitly instantiated*/; - Diag(PrevTemplate->getLocation(), diag::note_previous_declaration); - return true; - } - // Translate the parser's template argument list into our AST format. TemplateArgumentListInfo TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId); @@ -9049,7 +9044,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!HasNoEffect) { // Instantiate static data member or variable template. - Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (PrevTemplate) { // Merge attributes. @@ -9217,10 +9211,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return (Decl*) nullptr; } - Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + // In MSVC mode, dllimported explicit instantiation definitions are treated as + // instantiation declarations. + if (TSK == TSK_ExplicitInstantiationDefinition && + Specialization->hasAttr<DLLImportAttr>() && + Context.getTargetInfo().getCXXABI().isMicrosoft()) + TSK = TSK_ExplicitInstantiationDeclaration; + + Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + if (Specialization->isDefined()) { // Let the ASTConsumer know that this function has been explicitly // instantiated now, and its linkage might have changed. @@ -9243,16 +9245,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); - // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an - // explicit instantiation (14.8.2) [...] of a concept definition. - if (FunTmpl && FunTmpl->isConcept() && - !D.getDeclSpec().isConceptSpecified()) { - Diag(D.getIdentifierLoc(), diag::err_concept_specialized) - << 0 /*function*/ << 0 /*explicitly instantiated*/; - Diag(FunTmpl->getLocation(), diag::note_previous_declaration); - return true; - } - CheckExplicitInstantiationScope(*this, FunTmpl? (NamedDecl *)FunTmpl : Specialization->getInstantiatedFromMemberFunction(), @@ -9513,7 +9505,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, Expr *FailedCond; std::string FailedDescription; std::tie(FailedCond, FailedDescription) = - findFailedEnableIfCondition(*this, Cond); + findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true); Diag(FailedCond->getExprLoc(), diag::err_typename_nested_not_found_requirement) @@ -9591,7 +9583,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // A type-specifier of the form // typename[opt] nested-name-specifier[opt] template-name // is a placeholder for a deduced class type [...]. - if (getLangOpts().CPlusPlus1z) { + if (getLangOpts().CPlusPlus17) { if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { return Context.getElaboratedType( Keyword, QualifierLoc.getNestedNameSpecifier(), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index 983b1ea795dda..564692b030200 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -344,7 +344,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( } Deduced[NTTP->getIndex()] = Result; - if (!S.getLangOpts().CPlusPlus1z) + if (!S.getLangOpts().CPlusPlus17) return Sema::TDK_Success; if (NTTP->isExpandedParameterPack()) @@ -354,8 +354,9 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( // expanded NTTP should be a pack expansion type? return Sema::TDK_Success; - // Get the type of the parameter for deduction. - QualType ParamType = NTTP->getType(); + // Get the type of the parameter for deduction. If it's a (dependent) array + // or function type, we will not have decayed it yet, so do that now. + QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType()); if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType)) ParamType = Expansion->getPattern(); @@ -1843,6 +1844,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_NonDeducedMismatch; } + // (clang extension) + // + // T __attribute__(((address_space(N)))) + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *AddressSpaceParam = + cast<DependentAddressSpaceType>(Param); + + if (const DependentAddressSpaceType *AddressSpaceArg = + dyn_cast<DependentAddressSpaceType>(Arg)) { + // Perform deduction on the pointer type. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, + Deduced); + } + + if (isTargetAddressSpace(Arg.getAddressSpace())) { + llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), + false); + ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); + + // Perform deduction on the pointer types. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + ArgAddressSpace, S.Context.IntTy, + true, Info, Deduced); + } + + return Sema::TDK_NonDeducedMismatch; + } + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: @@ -2695,6 +2749,17 @@ static bool isSimpleTemplateIdType(QualType T) { = T->getAs<TemplateSpecializationType>()) return Spec->getTemplateName().getAsTemplateDecl() != nullptr; + // C++17 [temp.local]p2: + // the injected-class-name [...] is equivalent to the template-name followed + // by the template-arguments of the class template specialization or partial + // specialization enclosed in <> + // ... which means it's equivalent to a simple-template-id. + // + // This only arises during class template argument deduction for a copy + // deduction candidate, where it permits slicing. + if (T->getAs<InjectedClassNameType>()) + return true; + return false; } @@ -2869,7 +2934,7 @@ Sema::SubstituteExplicitTemplateArguments( // so substitution into the type must also substitute into the exception // specification. SmallVector<QualType, 4> ExceptionStorage; - if (getLangOpts().CPlusPlus1z && + if (getLangOpts().CPlusPlus17 && SubstExceptionSpec( Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, MultiLevelTemplateArgumentList(*ExplicitArgumentList))) @@ -2907,17 +2972,26 @@ Sema::SubstituteExplicitTemplateArguments( /// \brief Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. -static bool -CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, +static Sema::TemplateDeductionResult +CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, + Sema::OriginalCallArg OriginalArg, QualType DeducedA) { ASTContext &Context = S.Context; + auto Failed = [&]() -> Sema::TemplateDeductionResult { + Info.FirstArg = TemplateArgument(DeducedA); + Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); + Info.CallArgIndex = OriginalArg.ArgIdx; + return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested + : Sema::TDK_DeducedMismatch; + }; + QualType A = OriginalArg.OriginalArgType; QualType OriginalParamType = OriginalArg.OriginalParamType; // Check for type equality (top-level cv-qualifiers are ignored). if (Context.hasSameUnqualifiedType(A, DeducedA)) - return false; + return Sema::TDK_Success; // Strip off references on the argument types; they aren't needed for // the following checks. @@ -2941,7 +3015,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, // the deduced A can be F. QualType Tmp; if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp)) - return false; + return Sema::TDK_Success; Qualifiers AQuals = A.getQualifiers(); Qualifiers DeducedAQuals = DeducedA.getQualifiers(); @@ -2961,7 +3035,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, if (AQuals == DeducedAQuals) { // Qualifiers match; there's nothing to do. } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { - return true; + return Failed(); } else { // Qualifiers are compatible, so have the argument type adopt the // deduced argument type's qualifiers as if we had performed the @@ -2982,7 +3056,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, (S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion) || S.IsFunctionConversion(A, DeducedA, ResultTy))) - return false; + return Sema::TDK_Success; // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. [...] @@ -3003,13 +3077,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, } if (Context.hasSameUnqualifiedType(A, DeducedA)) - return false; + return Sema::TDK_Success; if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && S.IsDerivedFrom(SourceLocation(), A, DeducedA)) - return false; + return Sema::TDK_Success; - return true; + return Failed(); } /// Find the pack index for a particular parameter index in an instantiation of @@ -3165,13 +3239,9 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( DeducedA = CacheEntry; } - if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { - Info.FirstArg = TemplateArgument(DeducedA); - Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); - Info.CallArgIndex = OriginalArg.ArgIdx; - return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested - : TDK_DeducedMismatch; - } + if (auto TDK = + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) + return TDK; } } @@ -3838,7 +3908,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // so we can check that the exception specification matches. auto *SpecializationFPT = Specialization->getType()->castAs<FunctionProtoType>(); - if (getLangOpts().CPlusPlus1z && + if (getLangOpts().CPlusPlus17 && isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) && !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) return TDK_MiscellaneousDeductionFailure; @@ -4231,6 +4301,31 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, DependentDeductionDepth); } +/// Attempt to produce an informative diagostic explaining why auto deduction +/// failed. +/// \return \c true if diagnosed, \c false if not. +static bool diagnoseAutoDeductionFailure(Sema &S, + Sema::TemplateDeductionResult TDK, + TemplateDeductionInfo &Info, + ArrayRef<SourceRange> Ranges) { + switch (TDK) { + case Sema::TDK_Inconsistent: { + // Inconsistent deduction means we were deducing from an initializer list. + auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction); + D << Info.FirstArg << Info.SecondArg; + for (auto R : Ranges) + D << R; + return true; + } + + // FIXME: Are there other cases for which a custom diagnostic is more useful + // than the basic "types don't match" diagnostic? + + default: + return false; + } +} + /// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// Note that this is done even if the initializer is dependent. (This is @@ -4318,12 +4413,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, // If deduction failed, don't diagnose if the initializer is dependent; it // might acquire a matching type in the instantiation. - auto DeductionFailed = [&]() -> DeduceAutoResult { + auto DeductionFailed = [&](TemplateDeductionResult TDK, + ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } + if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) + return DAR_FailedAlreadyDiagnosed; return DAR_Failed; }; @@ -4337,12 +4435,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) return DAR_Failed; + SourceRange DeducedFromInitRange; for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { - if (DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i), + Expr *Init = InitList->getInit(i); + + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( + *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced, OriginalCallArgs, /*Decomposed*/ true, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(); + return DeductionFailed(TDK, {DeducedFromInitRange, + Init->getSourceRange()}); + + if (DeducedFromInitRange.isInvalid() && + Deduced[0].getKind() != TemplateArgument::Null) + DeducedFromInitRange = Init->getSourceRange(); } } else { if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { @@ -4350,15 +4456,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; } - if (DeduceTemplateArgumentsFromCallArgument( + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(); + return DeductionFailed(TDK, {}); } // Could be null if somehow 'auto' appears in a non-deduced context. if (Deduced[0].getKind() != TemplateArgument::Type) - return DeductionFailed(); + return DeductionFailed(TDK_Incomplete, {}); QualType DeducedType = Deduced[0].getAsType(); @@ -4378,9 +4484,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, for (const OriginalCallArg &OriginalArg : OriginalCallArgs) { assert((bool)InitList == OriginalArg.DecomposedParam && "decomposed non-init-list in auto deduction?"); - if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { + if (auto TDK = + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { Result = QualType(); - return DeductionFailed(); + return DeductionFailed(TDK, {}); } } @@ -5045,9 +5152,9 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (NTTP->getDepth() == Depth) Used[NTTP->getIndex()] = true; - // In C++1z mode, additional arguments may be deduced from the type of a + // In C++17 mode, additional arguments may be deduced from the type of a // non-type argument. - if (Ctx.getLangOpts().CPlusPlus1z) + if (Ctx.getLangOpts().CPlusPlus17) MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); } @@ -5174,6 +5281,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, break; } + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *DependentASType = + cast<DependentAddressSpaceType>(T); + MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(), + OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, + DependentASType->getAddrSpaceExpr(), + OnlyDeduced, Depth, Used); + break; + } + case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index f4f0c804aee1a..a48e2466a84d4 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -496,8 +496,8 @@ void Sema::PrintInstantiationStack() { SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); Template->printName(OS); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Active->template_arguments(), getPrintingPolicy()); + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << OS.str() @@ -562,8 +562,8 @@ void Sema::PrintInstantiationStack() { SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); FD->printName(OS); - TemplateSpecializationType::PrintTemplateArgumentList( - OS, Active->template_arguments(), getPrintingPolicy()); + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << OS.str() @@ -975,7 +975,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); @@ -1122,14 +1122,10 @@ TemplateName TemplateInstantiator::TransformTemplateName( Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); assert(!Template.isNull() && "Null template template argument"); - - // We don't ever want to substitute for a qualified template name, since - // the qualifier is handled separately. So, look through the qualified - // template name to its underlying declaration. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getTemplateDecl()); + assert(!Template.getAsQualifiedTemplateName() && + "template decl to substitute is qualified?"); Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); return Template; @@ -1143,7 +1139,7 @@ TemplateName TemplateInstantiator::TransformTemplateName( TemplateArgument Arg = SubstPack->getArgumentPack(); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return Arg.getAsTemplate(); + return Arg.getAsTemplate().getNameToSubstitute(); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -2030,12 +2026,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod(); LocalInstantiationScope Scope(*this, MergeWithParentScope); - // All dllexported classes created during instantiation should be fully - // emitted after instantiation completes. We may not be ready to emit any - // delayed classes already on the stack, so save them away and put them back - // later. - decltype(DelayedDllExportClasses) ExportedClasses; - std::swap(ExportedClasses, DelayedDllExportClasses); + // Some class state isn't processed immediately but delayed till class + // instantiation completes. We may not be ready to handle any delayed state + // already on the stack as it might correspond to a different class, so save + // it now and put it back later. + SavePendingParsedClassStateRAII SavedPendingParsedClassState(*this); // Pull attributes from the pattern onto the instantiation. InstantiateAttrs(TemplateArgs, Pattern, Instantiation); @@ -2122,9 +2117,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // default arg exprs for default constructors if necessary now. ActOnFinishCXXNonNestedClass(Instantiation); - // Put back the delayed exported classes that we moved out of the way. - std::swap(ExportedClasses, DelayedDllExportClasses); - // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), @@ -2621,7 +2613,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, continue; Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); - InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); + InstantiateVariableDefinition(PointOfInstantiation, Var); } else { Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 4a26efcc9431e..f627f6017f382 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1195,7 +1195,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Look for a previous declaration of the template in the owning // context. LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + Sema::LookupOrdinaryName, + SemaRef.forRedeclarationInCurContext()); SemaRef.LookupQualifiedName(R, DC); if (R.isSingleResult()) { @@ -1650,11 +1651,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } FunctionDecl *Function; - if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) + if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) { Function = CXXDeductionGuideDecl::Create( - SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(), - D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd()); - else { + SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(), + D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd()); + if (DGuide->isCopyDeductionCandidate()) + cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate(); + } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo, D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), @@ -1685,7 +1688,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params[P]->setOwningFunction(Function); Function->setParams(Params); - SourceLocation InstantiateAtPOI; if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1736,7 +1738,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, SemaRef, Function->getDeclName(), SourceLocation(), D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + D->isLocalExternDecl() ? Sema::ForExternalRedeclaration + : SemaRef.forRedeclarationInCurContext()); if (DependentFunctionTemplateSpecializationInfo *Info = D->getDependentSpecializationInfo()) { @@ -2054,7 +2057,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setInvalidDecl(); LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForExternalRedeclaration); if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -2493,7 +2496,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { bool CheckRedeclaration = Owner->isRecord(); LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(), @@ -2712,7 +2715,7 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( return nullptr; LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForExternalRedeclaration); TemplateArgumentListInfo TemplateArgs; TemplateArgumentListInfo *TemplateArgsPtr = nullptr; @@ -2800,8 +2803,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); // Initializers instantiation sequence. if (D->getInitializer()) { - SemaRef.ActOnOpenMPDeclareReductionInitializerStart( - /*S=*/nullptr, NewDRD); + VarDecl *OmpPrivParm = + SemaRef.ActOnOpenMPDeclareReductionInitializerStart( + /*S=*/nullptr, NewDRD); const char *Names[] = {"omp_orig", "omp_priv"}; for (auto &Name : Names) { DeclarationName DN(&SemaRef.Context.Idents.get(Name)); @@ -2809,17 +2813,28 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( auto Lookup = NewDRD->lookup(DN); if (!OldLookup.empty() && !Lookup.empty()) { assert(Lookup.size() == 1 && OldLookup.size() == 1); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - OldLookup.front(), Lookup.front()); + auto *OldVD = cast<VarDecl>(OldLookup.front()); + auto *NewVD = cast<VarDecl>(Lookup.front()); + SemaRef.InstantiateVariableInitializer(NewVD, OldVD, TemplateArgs); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldVD, NewVD); } } - SubstInitializer = - SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); - SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, - SubstInitializer); + if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) { + SubstInitializer = + SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); + } else { + IsCorrect = IsCorrect && OmpPrivParm->hasInit(); + } + SemaRef.ActOnOpenMPDeclareReductionInitializerEnd( + NewDRD, SubstInitializer, OmpPrivParm); } - IsCorrect = IsCorrect && SubstCombiner && - (!D->getInitializer() || SubstInitializer); + IsCorrect = + IsCorrect && SubstCombiner && + (!D->getInitializer() || + (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit && + SubstInitializer) || + (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit && + !SubstInitializer && !SubstInitializer)); } else IsCorrect = false; @@ -3753,7 +3768,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, bool Recursive, bool DefinitionRequired, bool AtEndOfTU) { - if (Function->isInvalidDecl() || Function->isDefined()) + if (Function->isInvalidDecl() || Function->isDefined() || + isa<CXXDeductionGuideDecl>(Function)) return; // Never instantiate an explicit specialization except if it is a class scope @@ -4005,6 +4021,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs) { + assert(PatternDecl->isThisDeclarationADefinition() && + "don't have a definition to instantiate from"); // Do substitution on the type of the declaration TypeSourceInfo *DI = @@ -4016,6 +4034,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( // Update the type of this variable template specialization. VarSpec->setType(DI->getType()); + // Convert the declaration into a definition now. + VarSpec->setCompleteDefinition(); + // Instantiate the initializer. InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs); @@ -4063,7 +4084,8 @@ void Sema::BuildVariableInstantiation( *this, NewVar->getDeclName(), NewVar->getLocation(), NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + NewVar->isLocalExternDecl() ? Sema::ForExternalRedeclaration + : forRedeclarationInCurContext()); if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() && (!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() || @@ -4120,6 +4142,9 @@ void Sema::BuildVariableInstantiation( void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { + if (ASTMutationListener *L = getASTContext().getASTMutationListener()) + L->VariableDefinitionInstantiated(Var); + // We propagate the 'inline' flag with the initializer, because it // would otherwise imply that the variable is a definition for a // non-static data member. @@ -4129,12 +4154,8 @@ void Sema::InstantiateVariableInitializer( Var->setImplicitlyInline(); if (OldVar->getInit()) { - if (Var->isStaticDataMember() && !OldVar->isOutOfLine()) - PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::ConstantEvaluated, OldVar); - else - PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::PotentiallyEvaluated, OldVar); + EnterExpressionEvaluationContext Evaluated( + *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var); // Instantiate the initializer. ExprResult Init; @@ -4162,8 +4183,6 @@ void Sema::InstantiateVariableInitializer( // because of a bogus initializer. Var->setInvalidDecl(); } - - PopExpressionEvaluationContext(); } else { if (Var->isStaticDataMember()) { if (!Var->isOutOfLine()) @@ -4188,26 +4207,16 @@ void Sema::InstantiateVariableInitializer( /// /// \param PointOfInstantiation the point at which the instantiation was /// required. Note that this is not precisely a "point of instantiation" -/// for the function, but it's close. +/// for the variable, but it's close. /// -/// \param Var the already-instantiated declaration of a static member -/// variable of a class template specialization. +/// \param Var the already-instantiated declaration of a templated variable. /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. /// /// \param DefinitionRequired if true, then we are performing an explicit -/// instantiation where an out-of-line definition of the member variable -/// is required. Complain if there is no such definition. -void Sema::InstantiateStaticDataMemberDefinition( - SourceLocation PointOfInstantiation, - VarDecl *Var, - bool Recursive, - bool DefinitionRequired) { - InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive, - DefinitionRequired); -} - +/// instantiation where a definition of the variable is required. Complain +/// if there is no such definition. void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, bool DefinitionRequired, bool AtEndOfTU) { @@ -4264,6 +4273,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate // it now. + // + // FIXME: This largely duplicates what we would do below. The difference + // is that along this path we may instantiate an initializer from an + // in-class declaration of the template and instantiate the definition + // from a separate out-of-class definition. if (PatternDecl->isStaticDataMember() && (PatternDecl = PatternDecl->getFirstDecl())->hasInit() && !Var->hasInit()) { @@ -4351,10 +4365,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, return; // C++11 [temp.explicit]p10: - // Except for inline functions, [...] explicit instantiation declarations + // Except for inline functions, const variables of literal types, variables + // of reference types, [...] explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. - if (TSK == TSK_ExplicitInstantiationDeclaration) + if (TSK == TSK_ExplicitInstantiationDeclaration && + !Var->isUsableInConstantExpressions(getASTContext())) return; // Make sure to pass the instantiated variable to the consumer at the end. @@ -4427,7 +4443,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // Merge the definition with the declaration. LookupResult R(*this, Var->getDeclName(), Var->getLocation(), - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); R.addDecl(OldVar); MergeVarDecl(Var, R); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index 9f572007d8a77..d81837dad5085 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -26,6 +26,19 @@ using namespace clang; // Visitor that collects unexpanded parameter packs //---------------------------------------------------------------------------- +/// \brief Retrieve the depth and index of a parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(NamedDecl *ND) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + namespace { /// \brief A class that collects unexpanded parameter packs. class CollectUnexpandedParameterPacksVisitor : @@ -36,15 +49,36 @@ namespace { SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; - bool InLambda; + bool InLambda = false; + unsigned DepthLimit = (unsigned)-1; + + void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { + if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) { + // For now, the only problematic case is a generic lambda's templated + // call operator, so we don't need to look for all the other ways we + // could have reached a dependent parameter pack. + auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()); + auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr; + if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit) + return; + } else if (getDepthAndIndex(ND).first >= DepthLimit) + return; + Unexpanded.push_back({ND, Loc}); + } + void addUnexpanded(const TemplateTypeParmType *T, + SourceLocation Loc = SourceLocation()) { + if (T->getDepth() < DepthLimit) + Unexpanded.push_back({T, Loc}); + } + public: explicit CollectUnexpandedParameterPacksVisitor( - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) - : Unexpanded(Unexpanded), InLambda(false) { } + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + : Unexpanded(Unexpanded) {} bool shouldWalkTypesOfTypeLocs() const { return false; } - + //------------------------------------------------------------------------ // Recording occurrences of (unexpanded) parameter packs. //------------------------------------------------------------------------ @@ -52,7 +86,7 @@ namespace { /// \brief Record occurrences of template type parameter packs. bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { if (TL.getTypePtr()->isParameterPack()) - Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc())); + addUnexpanded(TL.getTypePtr(), TL.getNameLoc()); return true; } @@ -63,7 +97,7 @@ namespace { /// Ideally, this routine would never be used. bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { if (T->isParameterPack()) - Unexpanded.push_back(std::make_pair(T, SourceLocation())); + addUnexpanded(T); return true; } @@ -72,18 +106,18 @@ namespace { /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { if (E->getDecl()->isParameterPack()) - Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation())); + addUnexpanded(E->getDecl(), E->getLocation()); return true; } /// \brief Record occurrences of template template parameter packs. bool TraverseTemplateName(TemplateName Template) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>( - Template.getAsTemplateDecl())) + if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) { if (TTP->isParameterPack()) - Unexpanded.push_back(std::make_pair(TTP, SourceLocation())); + addUnexpanded(TTP); + } return inherited::TraverseTemplateName(Template); } @@ -127,7 +161,7 @@ namespace { return true; } - /// \brief Suppress traversel into types with location information + /// \brief Suppress traversal into types with location information /// that do not contain unexpanded parameter packs. bool TraverseTypeLoc(TypeLoc TL) { if ((!TL.getType().isNull() && @@ -138,13 +172,48 @@ namespace { return true; } - /// \brief Suppress traversal of non-parameter declarations, since - /// they cannot contain unexpanded parameter packs. + /// \brief Suppress traversal of parameter packs. bool TraverseDecl(Decl *D) { - if ((D && isa<ParmVarDecl>(D)) || InLambda) - return inherited::TraverseDecl(D); + // A function parameter pack is a pack expansion, so cannot contain + // an unexpanded parameter pack. Likewise for a template parameter + // pack that contains any references to other packs. + if (D->isParameterPack()) + return true; - return true; + return inherited::TraverseDecl(D); + } + + /// \brief Suppress traversal of pack-expanded attributes. + bool TraverseAttr(Attr *A) { + if (A->isPackExpansion()) + return true; + + return inherited::TraverseAttr(A); + } + + /// \brief Suppress traversal of pack expansion expressions and types. + ///@{ + bool TraversePackExpansionType(PackExpansionType *T) { return true; } + bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; } + bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; } + bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; } + + ///@} + + /// \brief Suppress traversal of using-declaration pack expansion. + bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + if (D->isPackExpansion()) + return true; + + return inherited::TraverseUnresolvedUsingValueDecl(D); + } + + /// \brief Suppress traversal of using-declaration pack expansion. + bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + if (D->isPackExpansion()) + return true; + + return inherited::TraverseUnresolvedUsingTypenameDecl(D); } /// \brief Suppress traversal of template argument pack expansions. @@ -163,6 +232,22 @@ namespace { return inherited::TraverseTemplateArgumentLoc(ArgLoc); } + /// \brief Suppress traversal of base specifier pack expansions. + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) { + if (Base.isPackExpansion()) + return true; + + return inherited::TraverseCXXBaseSpecifier(Base); + } + + /// \brief Suppress traversal of mem-initializer pack expansions. + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + if (Init->isPackExpansion()) + return true; + + return inherited::TraverseConstructorInitializer(Init); + } + /// \brief Note whether we're traversing a lambda containing an unexpanded /// parameter pack. In this case, the unexpanded pack can occur anywhere, /// including all the places where we normally wouldn't look. Within a @@ -175,25 +260,27 @@ namespace { return true; bool WasInLambda = InLambda; - InLambda = true; + unsigned OldDepthLimit = DepthLimit; - // If any capture names a function parameter pack, that pack is expanded - // when the lambda is expanded. - for (LambdaExpr::capture_iterator I = Lambda->capture_begin(), - E = Lambda->capture_end(); - I != E; ++I) { - if (I->capturesVariable()) { - VarDecl *VD = I->getCapturedVar(); - if (VD->isParameterPack()) - Unexpanded.push_back(std::make_pair(VD, I->getLocation())); - } - } + InLambda = true; + if (auto *TPL = Lambda->getTemplateParameterList()) + DepthLimit = TPL->getDepth(); inherited::TraverseLambdaExpr(Lambda); InLambda = WasInLambda; + DepthLimit = OldDepthLimit; return true; } + + /// Suppress traversal within pack expansions in lambda captures. + bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C, + Expr *Init) { + if (C->isPackExpansion()) + return true; + + return inherited::TraverseLambdaCapture(Lambda, C, Init); + } }; } @@ -220,13 +307,33 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, if (Unexpanded.empty()) return false; - // If we are within a lambda expression, that lambda contains an unexpanded + // If we are within a lambda expression and referencing a pack that is not + // a parameter of the lambda itself, that lambda contains an unexpanded // parameter pack, and we are done. // FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it // later. + SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences; for (unsigned N = FunctionScopes.size(); N; --N) { if (sema::LambdaScopeInfo *LSI = dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) { + if (N == FunctionScopes.size()) { + for (auto &Param : Unexpanded) { + auto *PD = dyn_cast_or_null<ParmVarDecl>( + Param.first.dyn_cast<NamedDecl *>()); + if (PD && PD->getDeclContext() == LSI->CallOperator) + LambdaParamPackReferences.push_back(Param); + } + } + + // If we have references to a parameter pack of the innermost enclosing + // lambda, only diagnose those ones. We don't know whether any other + // unexpanded parameters referenced herein are actually unexpanded; + // they might be expanded at an outer level. + if (!LambdaParamPackReferences.empty()) { + Unexpanded = LambdaParamPackReferences; + break; + } + LSI->ContainsUnexpandedParameterPack = true; return false; } @@ -520,19 +627,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions); } -/// \brief Retrieve the depth and index of a parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(NamedDecl *ND) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - bool Sema::CheckParameterPacksForExpansion( SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, @@ -725,6 +819,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_half: case TST_float: case TST_double: + case TST_Float16: case TST_float128: case TST_bool: case TST_decimal32: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index 598a11300b876..2fffe8e179707 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -1392,8 +1392,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { else Result = Context.Int128Ty; break; - case DeclSpec::TST_half: Result = Context.HalfTy; break; - case DeclSpec::TST_float: Result = Context.FloatTy; break; + case DeclSpec::TST_float16: Result = Context.Float16Ty; break; + case DeclSpec::TST_half: Result = Context.HalfTy; break; + case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) Result = Context.LongDoubleTy; @@ -2179,9 +2180,18 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(Loc, diag::err_opencl_vla); return QualType(); } - // CUDA device code doesn't support VLAs. - if (getLangOpts().CUDA && T->isVariableArrayType()) - CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget(); + + if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { + if (getLangOpts().CUDA) { + // CUDA device code doesn't support VLAs. + CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget(); + } else if (!getLangOpts().OpenMP || + shouldDiagnoseTargetSupportFromOpenMP()) { + // Some targets don't support VLAs. + Diag(Loc, diag::err_vla_unsupported); + return QualType(); + } + } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOpts().C99) { @@ -2834,8 +2844,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case Declarator::TemplateParamContext: if (isa<DeducedTemplateSpecializationType>(Deduced)) Error = 19; // Template parameter - else if (!SemaRef.getLangOpts().CPlusPlus1z) - Error = 8; // Template parameter (until C++1z) + else if (!SemaRef.getLangOpts().CPlusPlus17) + Error = 8; // Template parameter (until C++17) break; case Declarator::BlockLiteralContext: Error = 9; // Block literal @@ -3064,6 +3074,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D, S.Diag(D.getCommaLoc(), diag::note_empty_parens_function_call) << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << D.getIdentifier(); + Result.suppressDiagnostics(); } } @@ -3105,6 +3116,99 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D, } } +/// Produce an appropriate diagnostic for a declarator with top-level +/// parentheses. +static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { + DeclaratorChunk &Paren = D.getTypeObject(D.getNumTypeObjects() - 1); + assert(Paren.Kind == DeclaratorChunk::Paren && + "do not have redundant top-level parentheses"); + + // This is a syntactic check; we're not interested in cases that arise + // during template instantiation. + if (S.inTemplateInstantiation()) + return; + + // Check whether this could be intended to be a construction of a temporary + // object in C++ via a function-style cast. + bool CouldBeTemporaryObject = + S.getLangOpts().CPlusPlus && D.isExpressionContext() && + !D.isInvalidType() && D.getIdentifier() && + D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier && + (T->isRecordType() || T->isDependentType()) && + D.getDeclSpec().getTypeQualifiers() == 0 && D.isFirstDeclarator(); + + for (auto &C : D.type_objects()) { + switch (C.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Paren: + continue; + + case DeclaratorChunk::Array: + if (!C.Arr.NumElts) + CouldBeTemporaryObject = false; + continue; + + case DeclaratorChunk::Reference: + // FIXME: Suppress the warning here if there is no initializer; we're + // going to give an error anyway. + // We assume that something like 'T (&x) = y;' is highly likely to not + // be intended to be a temporary object. + CouldBeTemporaryObject = false; + continue; + + case DeclaratorChunk::Function: + // In a new-type-id, function chunks require parentheses. + if (D.getContext() == Declarator::CXXNewContext) + return; + LLVM_FALLTHROUGH; + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: + // These cannot appear in expressions. + CouldBeTemporaryObject = false; + continue; + } + } + + // FIXME: If there is an initializer, assume that this is not intended to be + // a construction of a temporary object. + + // Check whether the name has already been declared; if not, this is not a + // function-style cast. + if (CouldBeTemporaryObject) { + LookupResult Result(S, D.getIdentifier(), SourceLocation(), + Sema::LookupOrdinaryName); + if (!S.LookupName(Result, S.getCurScope())) + CouldBeTemporaryObject = false; + Result.suppressDiagnostics(); + } + + SourceRange ParenRange(Paren.Loc, Paren.EndLoc); + + if (!CouldBeTemporaryObject) { + S.Diag(Paren.Loc, diag::warn_redundant_parens_around_declarator) + << ParenRange << FixItHint::CreateRemoval(Paren.Loc) + << FixItHint::CreateRemoval(Paren.EndLoc); + return; + } + + S.Diag(Paren.Loc, diag::warn_parens_disambiguated_as_variable_declaration) + << ParenRange << D.getIdentifier(); + auto *RD = T->getAsCXXRecordDecl(); + if (!RD || !RD->hasDefinition() || RD->hasNonTrivialDestructor()) + S.Diag(Paren.Loc, diag::note_raii_guard_add_name) + << FixItHint::CreateInsertion(Paren.Loc, " varname") << T + << D.getIdentifier(); + // FIXME: A cast to void is probably a better suggestion in cases where it's + // valid (when there is no initializer and we're not in a condition). + S.Diag(D.getLocStart(), diag::note_function_style_cast_add_parentheses) + << FixItHint::CreateInsertion(D.getLocStart(), "(") + << FixItHint::CreateInsertion(S.getLocForEndOfToken(D.getLocEnd()), ")"); + S.Diag(Paren.Loc, diag::note_remove_parens_for_variable_declaration) + << FixItHint::CreateRemoval(Paren.Loc) + << FixItHint::CreateRemoval(Paren.EndLoc); +} + /// Helper for figuring out the default CC for a function declarator type. If /// this is the outermost chunk, then we can determine the CC from the /// declarator context. If not, then this could be either a member function @@ -3387,13 +3491,20 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator, isCFError = (S.CFError == recordDecl); } else { // Check whether this is CFError, which we identify based on its bridge - // to NSError. + // to NSError. CFErrorRef used to be declared with "objc_bridge" but is + // now declared with "objc_bridge_mutable", so look for either one of + // the two attributes. if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) { - if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) { - if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) { - S.CFError = recordDecl; - isCFError = true; - } + IdentifierInfo *bridgedType = nullptr; + if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) + bridgedType = bridgeAttr->getBridgedType(); + else if (auto bridgeAttr = + recordDecl->getAttr<ObjCBridgeMutableAttr>()) + bridgedType = bridgeAttr->getBridgedType(); + + if (bridgedType == S.getNSErrorIdent()) { + S.CFError = recordDecl; + isCFError = true; } } } @@ -3499,7 +3610,8 @@ static void fixItNullability(Sema &S, DiagnosticBuilder &Diag, static void emitNullabilityConsistencyWarning(Sema &S, SimplePointerKind PointerKind, - SourceLocation PointerLoc) { + SourceLocation PointerLoc, + SourceLocation PointerEndLoc) { assert(PointerLoc.isValid()); if (PointerKind == SimplePointerKind::Array) { @@ -3509,14 +3621,15 @@ static void emitNullabilityConsistencyWarning(Sema &S, << static_cast<unsigned>(PointerKind); } - if (PointerLoc.isMacroID()) + auto FixItLoc = PointerEndLoc.isValid() ? PointerEndLoc : PointerLoc; + if (FixItLoc.isMacroID()) return; auto addFixIt = [&](NullabilityKind Nullability) { - auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it); + auto Diag = S.Diag(FixItLoc, diag::note_nullability_fix_it); Diag << static_cast<unsigned>(Nullability); Diag << static_cast<unsigned>(PointerKind); - fixItNullability(S, Diag, PointerLoc, Nullability); + fixItNullability(S, Diag, FixItLoc, Nullability); }; addFixIt(NullabilityKind::Nullable); addFixIt(NullabilityKind::NonNull); @@ -3528,9 +3641,10 @@ static void emitNullabilityConsistencyWarning(Sema &S, /// /// If the file has \e not seen other uses of nullability, this particular /// pointer is saved for possible later diagnosis. See recordNullabilitySeen(). -static void checkNullabilityConsistency(Sema &S, - SimplePointerKind pointerKind, - SourceLocation pointerLoc) { +static void +checkNullabilityConsistency(Sema &S, SimplePointerKind pointerKind, + SourceLocation pointerLoc, + SourceLocation pointerEndLoc = SourceLocation()) { // Determine which file we're performing consistency checking for. FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc); if (file.isInvalid()) @@ -3551,6 +3665,7 @@ static void checkNullabilityConsistency(Sema &S, if (fileNullability.PointerLoc.isInvalid() && !S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) { fileNullability.PointerLoc = pointerLoc; + fileNullability.PointerEndLoc = pointerEndLoc; fileNullability.PointerKind = static_cast<unsigned>(pointerKind); } @@ -3558,7 +3673,7 @@ static void checkNullabilityConsistency(Sema &S, } // Complain about missing nullability. - emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc); + emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc, pointerEndLoc); } /// Marks that a nullability feature has been used in the file containing @@ -3584,7 +3699,8 @@ static void recordNullabilitySeen(Sema &S, SourceLocation loc) { return; auto kind = static_cast<SimplePointerKind>(fileNullability.PointerKind); - emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc); + emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc, + fileNullability.PointerEndLoc); } /// Returns true if any of the declarator chunks before \p endIndex include a @@ -3894,6 +4010,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Returns true if _Nonnull was inferred. auto inferPointerNullability = [&](SimplePointerKind pointerKind, SourceLocation pointerLoc, + SourceLocation pointerEndLoc, AttributeList *&attrs) -> AttributeList * { // We've seen a pointer. if (NumPointersRemaining > 0) @@ -3949,7 +4066,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Fallthrough. case CAMN_Yes: - checkNullabilityConsistency(S, pointerKind, pointerLoc); + checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc); } return nullptr; }; @@ -3972,6 +4089,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (auto *attr = inferPointerNullability( pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), + D.getDeclSpec().getLocEnd(), D.getMutableDeclSpec().getAttributes().getListRef())) { T = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*inferNullability),T,T); @@ -3999,6 +4117,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren; switch (DeclType.Kind) { case DeclaratorChunk::Paren: + if (i == 0) + warnAboutRedundantParens(S, D, T); T = S.BuildParenType(T); break; case DeclaratorChunk::BlockPointer: @@ -4007,8 +4127,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL; // Handle pointer nullability. - inferPointerNullability(SimplePointerKind::BlockPointer, - DeclType.Loc, DeclType.getAttrListRef()); + inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc, + DeclType.EndLoc, DeclType.getAttrListRef()); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) { @@ -4030,7 +4150,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc, - DeclType.getAttrListRef()); + DeclType.EndLoc, DeclType.getAttrListRef()); if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); @@ -4175,7 +4295,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getSourceRange(); D.setInvalidType(true); } else if (D.getName().getKind() == - UnqualifiedId::IK_DeductionGuideName) { + UnqualifiedId::IK_DeductionGuideName) { if (T != Context.DependentTy) { S.Diag(D.getDeclSpec().getLocStart(), diag::err_deduction_guide_with_complex_decl) @@ -4343,7 +4463,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Exception specs are not allowed in typedefs. Complain, but add it // anyway. - if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z) + if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus17) S.Diag(FTI.getExceptionSpecLocBeg(), diag::err_exception_spec_in_typedef) << (D.getContext() == Declarator::AliasDeclContext || @@ -4356,7 +4476,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex)); - if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) { + if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus + && !LangOpts.OpenCL) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T, EI); } else { @@ -4478,6 +4599,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, HasAnyInterestingExtParameterInfos = true; } + if (Param->hasAttr<NoEscapeAttr>()) { + ExtParameterInfos[i] = ExtParameterInfos[i].withIsNoEscape(true); + HasAnyInterestingExtParameterInfos = true; + } + ParamTys.push_back(ParamTy); } @@ -4524,8 +4650,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType ClsType; // Handle pointer nullability. - inferPointerNullability(SimplePointerKind::MemberPointer, - DeclType.Loc, DeclType.getAttrListRef()); + inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc, + DeclType.EndLoc, DeclType.getAttrListRef()); if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. @@ -4828,7 +4954,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { TypeSourceInfo *ReturnTypeInfo = nullptr; QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); - if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount) inferARCWriteback(state, T); @@ -5378,6 +5503,18 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { ATL.setParensRange(SourceRange()); } +static void fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, + const AttributeList *Attrs) { + while (Attrs && Attrs->getKind() != AttributeList::AT_AddressSpace) + Attrs = Attrs->getNext(); + + assert(Attrs && "no address_space attribute found at the expected location!"); + + DASTL.setAttrNameLoc(Attrs->getLoc()); + DASTL.setAttrExprOperand(Attrs->getArgAsExpr(0)); + DASTL.setAttrOperandParensRange(SourceRange()); +} + /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -5400,6 +5537,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + + if (DependentAddressSpaceTypeLoc DASTL = + CurrTL.getAs<DependentAddressSpaceTypeLoc>()) { + fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs()); + CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc(); + } + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) { @@ -5492,16 +5636,77 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { // Type Attribute Processing //===----------------------------------------------------------------------===// +/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression +/// is uninstantiated. If instantiated it will apply the appropriate address space +/// to the type. This function allows dependent template variables to be used in +/// conjunction with the address_space attribute +QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc) { + if (!AddrSpace->isValueDependent()) { + + // If this type is already address space qualified, reject it. + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified + // by qualifiers for two or more different address spaces." + if (T.getAddressSpace() != LangAS::Default) { + Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return QualType(); + } + + llvm::APSInt addrSpace(32); + if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "'address_space'" << AANT_ArgumentIntegerConstant + << AddrSpace->getSourceRange(); + return QualType(); + } + + // Bounds checking. + if (addrSpace.isSigned()) { + if (addrSpace.isNegative()) { + Diag(AttrLoc, diag::err_attribute_address_space_negative) + << AddrSpace->getSourceRange(); + return QualType(); + } + addrSpace.setIsSigned(false); + } + + llvm::APSInt max(addrSpace.getBitWidth()); + max = + Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace; + if (addrSpace > max) { + Diag(AttrLoc, diag::err_attribute_address_space_too_high) + << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); + return QualType(); + } + + LangAS ASIdx = + getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue())); + + return Context.getAddrSpaceQualType(T, ASIdx); + } + + // A check with similar intentions as checking if a type already has an + // address space except for on a dependent types, basically if the + // current type is already a DependentAddressSpaceType then its already + // lined up to have another address space on it and we can't have + // multiple address spaces on the one pointer indirection + if (T->getAs<DependentAddressSpaceType>()) { + Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return QualType(); + } + + return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc); +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ - // If this type is already address space qualified, reject it. // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by // qualifiers for two or more different address spaces." - if (Type.getAddressSpace()) { + if (Type.getAddressSpace() != LangAS::Default) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); Attr.setInvalid(); return; @@ -5515,46 +5720,43 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, return; } - unsigned ASIdx; + LangAS ASIdx; if (Attr.getKind() == AttributeList::AT_AddressSpace) { + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; - Attr.setInvalid(); - return; - } - Expr *ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - llvm::APSInt addrSpace(32); - if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() || - !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << ASArgExpr->getSourceRange(); + << Attr.getName() << 1; Attr.setInvalid(); return; } - // Bounds checking. - if (addrSpace.isSigned()) { - if (addrSpace.isNegative()) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) - << ASArgExpr->getSourceRange(); - Attr.setInvalid(); + Expr *ASArgExpr; + if (Attr.isArgIdent(0)) { + // Special case where the argument is a template id. + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId id; + id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); + + ExprResult AddrSpace = S.ActOnIdExpression( + S.getCurScope(), SS, TemplateKWLoc, id, false, false); + if (AddrSpace.isInvalid()) return; - } - addrSpace.setIsSigned(false); + + ASArgExpr = static_cast<Expr *>(AddrSpace.get()); + } else { + ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); } - llvm::APSInt max(addrSpace.getBitWidth()); - max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace; - if (addrSpace > max) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) - << (unsigned)max.getZExtValue() << ASArgExpr->getSourceRange(); + + // Create the DependentAddressSpaceType or append an address space onto + // the type. + QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); + + if (!T.isNull()) + Type = T; + else Attr.setInvalid(); - return; - } - ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()) + - LangAS::FirstTargetAddressSpace; } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { @@ -5566,13 +5768,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, ASIdx = LangAS::opencl_constant; break; case AttributeList::AT_OpenCLGenericAddressSpace: ASIdx = LangAS::opencl_generic; break; + case AttributeList::AT_OpenCLPrivateAddressSpace: + ASIdx = LangAS::opencl_private; break; default: - assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace); - ASIdx = 0; break; + llvm_unreachable("Invalid address space"); } + + Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } - - Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } /// Does this type have a "direct" ownership qualifier? That is, @@ -6800,6 +7003,92 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr, } } +static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, + QualType &T, TypeAttrLocation TAL) { + Declarator &D = State.getDeclarator(); + + // Handle the cases where address space should not be deduced. + // + // The pointee type of a pointer type is alwasy deduced since a pointer always + // points to some memory location which should has an address space. + // + // There are situations that at the point of certain declarations, the address + // space may be unknown and better to be left as default. For example, when + // definining a typedef or struct type, they are not associated with any + // specific address space. Later on, they may be used with any address space + // to declare a variable. + // + // The return value of a function is r-value, therefore should not have + // address space. + // + // The void type does not occupy memory, therefore should not have address + // space, except when it is used as a pointee type. + // + // Since LLVM assumes function type is in default address space, it should not + // have address space. + auto ChunkIndex = State.getCurrentChunkIndex(); + bool IsPointee = + ChunkIndex > 0 && + (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer || + D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer); + bool IsFuncReturnType = + ChunkIndex > 0 && + D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function; + bool IsFuncType = + ChunkIndex < D.getNumTypeObjects() && + D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function; + if ( // Do not deduce addr space for function return type and function type, + // otherwise it will fail some sema check. + IsFuncReturnType || IsFuncType || + // Do not deduce addr space for member types of struct, except the pointee + // type of a pointer member type. + (D.getContext() == Declarator::MemberContext && !IsPointee) || + // Do not deduce addr space for types used to define a typedef and the + // typedef itself, except the pointee type of a pointer type which is used + // to define the typedef. + (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef && + !IsPointee) || + // Do not deduce addr space of the void type, e.g. in f(void), otherwise + // it will fail some sema check. + (T->isVoidType() && !IsPointee)) + return; + + LangAS ImpAddr; + // Put OpenCL automatic variable in private address space. + // OpenCL v1.2 s6.5: + // The default address space name for arguments to a function in a + // program, or local variables of a function is __private. All function + // arguments shall be in the __private address space. + if (State.getSema().getLangOpts().OpenCLVersion <= 120) { + ImpAddr = LangAS::opencl_private; + } else { + // If address space is not set, OpenCL 2.0 defines non private default + // address spaces for some cases: + // OpenCL 2.0, section 6.5: + // The address space for a variable at program scope or a static variable + // inside a function can either be __global or __constant, but defaults to + // __global if not specified. + // (...) + // Pointers that are declared without pointing to a named address space + // point to the generic address space. + if (IsPointee) { + ImpAddr = LangAS::opencl_generic; + } else { + if (D.getContext() == Declarator::FileContext) { + ImpAddr = LangAS::opencl_global; + } else { + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) { + ImpAddr = LangAS::opencl_global; + } else { + ImpAddr = LangAS::opencl_private; + } + } + } + } + T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr); +} + static void processTypeAttrs(TypeProcessingState &state, QualType &type, TypeAttrLocation TAL, AttributeList *attrs) { // Scan through and apply attributes to this type where it makes sense. Some @@ -6807,7 +7096,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. - bool hasOpenCLAddressSpace = false; while (attrs) { AttributeList &attr = *attrs; attrs = attr.getNext(); // reset to the next here due to early loop continue @@ -6870,7 +7158,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); - hasOpenCLAddressSpace = true; break; OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) @@ -6971,70 +7258,40 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } } - // If address space is not set, OpenCL 2.0 defines non private default - // address spaces for some cases: - // OpenCL 2.0, section 6.5: - // The address space for a variable at program scope or a static variable - // inside a function can either be __global or __constant, but defaults to - // __global if not specified. - // (...) - // Pointers that are declared without pointing to a named address space point - // to the generic address space. - if (state.getSema().getLangOpts().OpenCLVersion >= 200 && - !hasOpenCLAddressSpace && type.getAddressSpace() == 0 && - (TAL == TAL_DeclSpec || TAL == TAL_DeclChunk)) { - Declarator &D = state.getDeclarator(); - if (state.getCurrentChunkIndex() > 0 && - (D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind == - DeclaratorChunk::Pointer || - D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind == - DeclaratorChunk::BlockPointer)) { - type = state.getSema().Context.getAddrSpaceQualType( - type, LangAS::opencl_generic); - } else if (state.getCurrentChunkIndex() == 0 && - D.getContext() == Declarator::FileContext && - !D.isFunctionDeclarator() && !D.isFunctionDefinition() && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - !type->isSamplerT()) - type = state.getSema().Context.getAddrSpaceQualType( - type, LangAS::opencl_global); - else if (state.getCurrentChunkIndex() == 0 && - D.getContext() == Declarator::BlockContext && - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) - type = state.getSema().Context.getAddrSpaceQualType( - type, LangAS::opencl_global); - } + if (!state.getSema().getLangOpts().OpenCL || + type.getAddressSpace() != LangAS::Default) + return; + + deduceOpenCLImplicitAddrSpace(state, type, TAL); } void Sema::completeExprArrayBound(Expr *E) { if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) { - SourceLocation PointOfInstantiation = E->getExprLoc(); - - if (MemberSpecializationInfo *MSInfo = - Var->getMemberSpecializationInfo()) { - // If we don't already have a point of instantiation, this is it. - if (MSInfo->getPointOfInstantiation().isInvalid()) { - MSInfo->setPointOfInstantiation(PointOfInstantiation); + auto *Def = Var->getDefinition(); + if (!Def) { + SourceLocation PointOfInstantiation = E->getExprLoc(); + InstantiateVariableDefinition(PointOfInstantiation, Var); + Def = Var->getDefinition(); - // This is a modification of an existing AST node. Notify - // listeners. - if (ASTMutationListener *L = getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); + // If we don't already have a point of instantiation, and we managed + // to instantiate a definition, this is the point of instantiation. + // Otherwise, we don't request an end-of-TU instantiation, so this is + // not a point of instantiation. + // FIXME: Is this really the right behavior? + if (Var->getPointOfInstantiation().isInvalid() && Def) { + assert(Var->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation && + "explicit instantiation with no point of instantiation"); + Var->setTemplateSpecializationKind( + Var->getTemplateSpecializationKind(), PointOfInstantiation); } - } else { - VarTemplateSpecializationDecl *VarSpec = - cast<VarTemplateSpecializationDecl>(Var); - if (VarSpec->getPointOfInstantiation().isInvalid()) - VarSpec->setPointOfInstantiation(PointOfInstantiation); } - InstantiateVariableDefinition(PointOfInstantiation, Var); - - // Update the type to the newly instantiated definition's type both - // here and within the expression. - if (VarDecl *Def = Var->getDefinition()) { + // Update the type to the definition's type both here and within the + // expression. + if (Def) { DRE->setDecl(Def); QualType T = Def->getType(); DRE->setType(T); @@ -7303,11 +7560,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // Give the external AST source a chance to complete the type. if (auto *Source = Context.getExternalSource()) { - if (Tag) - Source->CompleteType(Tag->getDecl()); - else - Source->CompleteType(IFace->getDecl()); - + if (Tag) { + TagDecl *TagD = Tag->getDecl(); + if (TagD->hasExternalLexicalStorage()) + Source->CompleteType(TagD); + } else { + ObjCInterfaceDecl *IFaceD = IFace->getDecl(); + if (IFaceD->hasExternalLexicalStorage()) + Source->CompleteType(IFace->getDecl()); + } // If the external source completed the type, go through the motions // again to ensure we're allowed to use the completed type. if (!T->isIncompleteType()) diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index 91da9f88c59b8..96969ea87a135 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -835,6 +835,18 @@ public: Expr *SizeExpr, SourceLocation AttributeLoc); + /// \brief Build a new DependentAddressSpaceType or return the pointee + /// type variable with the correct address space (retrieved from + /// AddrSpaceExpr) applied to it. The former will be returned in cases + /// where the address space remains dependent. + /// + /// By default, performs semantic analysis when building the type with address + /// space applied. Subclasses may override this routine to provide different + /// behavior. + QualType RebuildDependentAddressSpaceType(QualType PointeeType, + Expr *AddrSpaceExpr, + SourceLocation AttributeLoc); + /// \brief Build a new function type. /// /// By default, performs semantic analysis when building the function type. @@ -1666,6 +1678,22 @@ public: ReductionId, UnresolvedReductions); } + /// Build a new OpenMP 'in_reduction' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPInReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { + return getSema().ActOnOpenMPInReductionClause( + VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, + ReductionId, UnresolvedReductions); + } + /// \brief Build a new OpenMP 'linear' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -4171,7 +4199,6 @@ TreeTransform<Derived>::TransformTypeWithDeducedTST(TypeSourceInfo *DI) { TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - Qualifiers Quals; auto QTL = TL.getAs<QualifiedTypeLoc>(); if (QTL) TL = QTL.getUnqualifiedLoc(); @@ -4769,7 +4796,53 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( return Result; } -template<typename Derived> +template <typename Derived> +QualType TreeTransform<Derived>::TransformDependentAddressSpaceType( + TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { + const DependentAddressSpaceType *T = TL.getTypePtr(); + + QualType pointeeType = getDerived().TransformType(T->getPointeeType()); + + if (pointeeType.isNull()) + return QualType(); + + // Address spaces are constant expressions. + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExprResult AddrSpace = getDerived().TransformExpr(T->getAddrSpaceExpr()); + AddrSpace = SemaRef.ActOnConstantExpression(AddrSpace); + if (AddrSpace.isInvalid()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || pointeeType != T->getPointeeType() || + AddrSpace.get() != T->getAddrSpaceExpr()) { + Result = getDerived().RebuildDependentAddressSpaceType( + pointeeType, AddrSpace.get(), T->getAttributeLoc()); + if (Result.isNull()) + return QualType(); + } + + // Result might be dependent or not. + if (isa<DependentAddressSpaceType>(Result)) { + DependentAddressSpaceTypeLoc NewTL = + TLB.push<DependentAddressSpaceTypeLoc>(Result); + + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrExprOperand(TL.getAttrExprOperand()); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + + } else { + TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo( + Result, getDerived().getBaseLocation()); + TransformType(TLB, DI->getTypeLoc()); + } + + return Result; +} + +template <typename Derived> QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, VectorTypeLoc TL) { const VectorType *T = TL.getTypePtr(); @@ -6585,8 +6658,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { // Rebuild the switch statement. StmtResult Switch - = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), - S->getInit(), Cond); + = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Init.get(), Cond); if (Switch.isInvalid()) return StmtError(); @@ -8461,6 +8533,51 @@ OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause( template <typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + CXXScopeSpec ReductionIdScopeSpec; + ReductionIdScopeSpec.Adopt(C->getQualifierLoc()); + + DeclarationNameInfo NameInfo = C->getNameInfo(); + if (NameInfo.getName()) { + NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); + if (!NameInfo.getName()) + return nullptr; + } + // Build a list of all UDR decls with the same names ranged by the Scopes. + // The Scope boundary is a duplication of the previous decl. + llvm::SmallVector<Expr *, 16> UnresolvedReductions; + for (auto *E : C->reduction_ops()) { + // Transform all the decls. + if (E) { + auto *ULE = cast<UnresolvedLookupExpr>(E); + UnresolvedSet<8> Decls; + for (auto *D : ULE->decls()) { + NamedDecl *InstD = + cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D)); + Decls.addDecl(InstD, InstD->getAccess()); + } + UnresolvedReductions.push_back(UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo, + /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end())); + } else + UnresolvedReductions.push_back(nullptr); + } + return getDerived().RebuildOMPInReductionClause( + Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(), + C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); +} + +template <typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) { llvm::SmallVector<Expr *, 16> Vars; Vars.reserve(C->varlist_size()); @@ -12253,10 +12370,18 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType, IndexTypeQuals, BracketsRange); } -template<typename Derived> -QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType, - unsigned NumElements, - VectorType::VectorKind VecKind) { +template <typename Derived> +QualType TreeTransform<Derived>::RebuildDependentAddressSpaceType( + QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc) { + return SemaRef.BuildAddressSpaceAttr(PointeeType, AddrSpaceExpr, + AttributeLoc); +} + +template <typename Derived> +QualType +TreeTransform<Derived>::RebuildVectorType(QualType ElementType, + unsigned NumElements, + VectorType::VectorKind VecKind) { // FIXME: semantic checking! return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind); } @@ -12510,10 +12635,14 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // Compute the transformed set of functions (and function templates) to be // used during overload resolution. UnresolvedSet<16> Functions; + bool RequiresADL; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) { - assert(ULE->requiresADL()); Functions.append(ULE->decls_begin(), ULE->decls_end()); + // If the overload could not be resolved in the template definition + // (because we had a dependent argument), ADL is performed as part of + // template instantiation. + RequiresADL = ULE->requiresADL(); } else { // If we've resolved this to a particular non-member function, just call // that function. If we resolved it to a member function, @@ -12521,6 +12650,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl(); if (!isa<CXXMethodDecl>(ND)) Functions.addDecl(ND); + RequiresADL = false; } // Add any functions found via argument-dependent lookup. @@ -12531,7 +12661,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (NumArgs == 1 || isPostIncDec) { UnaryOperatorKind Opc = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); - return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First); + return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First, + RequiresADL); } if (Op == OO_Subscript) { @@ -12555,8 +12686,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // Create the overloaded operator invocation for binary operators. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); - ExprResult Result - = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]); + ExprResult Result = SemaRef.CreateOverloadedBinOp( + OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL); if (Result.isInvalid()) return ExprError(); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp index 684ec243035e9..9c6f03cd0bb7d 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp @@ -91,6 +91,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; + case BuiltinType::Float16: + ID = PREDEF_TYPE_FLOAT16_ID; + break; case BuiltinType::Float128: ID = PREDEF_TYPE_FLOAT128_ID; break; diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h index cbc5f04738b14..6aca453bbb890 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h @@ -27,7 +27,8 @@ enum DeclUpdateKind { UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, UPD_CXX_ADDED_FUNCTION_DEFINITION, - UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, + UPD_CXX_ADDED_VAR_DEFINITION, + UPD_CXX_POINT_OF_INSTANTIATION, UPD_CXX_INSTANTIATED_CLASS_DEFINITION, UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index 50be74f6bf6e8..111ac4fcdaa42 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -1,4 +1,4 @@ -//===-- ASTReader.cpp - AST File Reader -----------------------------------===// +//===- ASTReader.cpp - AST File Reader ------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -19,28 +19,41 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/ODRHash.h" #include "clang/AST/RawCommentList.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/CommentOptions.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MemoryBufferCache.h" +#include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/Specifiers.h" @@ -57,41 +70,61 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Lex/Token.h" +#include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Weak.h" +#include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstdio> -#include <cstring> #include <ctime> #include <iterator> #include <limits> #include <map> #include <memory> -#include <new> #include <string> #include <system_error> #include <tuple> @@ -171,19 +204,23 @@ bool ChainedASTReaderListener::ReadPreprocessorOptions( SuggestedPredefines) || Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines); } + void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M, unsigned Value) { First->ReadCounter(M, Value); Second->ReadCounter(M, Value); } + bool ChainedASTReaderListener::needsInputFileVisitation() { return First->needsInputFileVisitation() || Second->needsInputFileVisitation(); } + bool ChainedASTReaderListener::needsSystemInputFileVisitation() { return First->needsSystemInputFileVisitation() || Second->needsSystemInputFileVisitation(); } + void ChainedASTReaderListener::visitModuleFile(StringRef Filename, ModuleKind Kind) { First->visitModuleFile(Filename, Kind); @@ -216,7 +253,7 @@ void ChainedASTReaderListener::readModuleFileExtension( // PCH validator implementation //===----------------------------------------------------------------------===// -ASTReaderListener::~ASTReaderListener() {} +ASTReaderListener::~ASTReaderListener() = default; /// \brief Compare the given set of language options against an existing set of /// language options. @@ -409,17 +446,16 @@ bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, namespace { - typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> > - MacroDefinitionsMap; - typedef llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > - DeclsMap; +using MacroDefinitionsMap = + llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>; +using DeclsMap = llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8>>; -} // end anonymous namespace +} // namespace static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags, DiagnosticsEngine &Diags, bool Complain) { - typedef DiagnosticsEngine::Level Level; + using Level = DiagnosticsEngine::Level; // Check current mappings for new -Werror mappings, and the stored mappings // for cases that were explicitly mapped to *not* be errors that are now @@ -603,8 +639,8 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, std::pair<StringRef, bool> Existing = ExistingMacros[MacroName]; // Check whether we know anything about this macro name or not. - llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known - = ASTFileMacros.find(MacroName); + llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>::iterator Known = + ASTFileMacros.find(MacroName); if (!Validate || Known == ASTFileMacros.end()) { // FIXME: Check whether this identifier was referenced anywhere in the // AST file. If so, we should reject the AST file. Unfortunately, this @@ -770,6 +806,7 @@ unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { std::pair<unsigned, unsigned> ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; + unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); return std::make_pair(KeyLen, DataLen); @@ -778,6 +815,7 @@ ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { ASTSelectorLookupTrait::internal_key_type ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { using namespace llvm::support; + SelectorTable &SelTable = Reader.getContext().Selectors; unsigned N = endian::readNext<uint16_t, little, unaligned>(d); IdentifierInfo *FirstII = Reader.getLocalIdentifier( @@ -838,6 +876,7 @@ unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) { std::pair<unsigned, unsigned> ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; + unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); return std::make_pair(KeyLen, DataLen); @@ -868,6 +907,7 @@ static bool readBit(unsigned &Bits) { IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) { using namespace llvm::support; + unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); return Reader.getGlobalIdentifierID(F, RawID >> 1); } @@ -885,6 +925,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, const unsigned char* d, unsigned DataLen) { using namespace llvm::support; + unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); bool IsInteresting = RawID & 0x01; @@ -1027,6 +1068,7 @@ unsigned DeclarationNameKey::getHash() const { ModuleFile * ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { using namespace llvm::support; + uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d); return Reader.getLocalModuleFile(F, ModuleFileID); } @@ -1034,6 +1076,7 @@ ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { std::pair<unsigned, unsigned> ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) { using namespace llvm::support; + unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); return std::make_pair(KeyLen, DataLen); @@ -1079,6 +1122,7 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, unsigned DataLen, data_type_builder &Val) { using namespace llvm::support; + for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) { uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d); Val.insert(Reader.getGlobalDeclID(F, LocalID)); @@ -1176,6 +1220,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F, // Parse the file names std::map<int, int> FileIDs; + FileIDs[-1] = -1; // For unspecified filenames. for (unsigned I = 0; Record[Idx]; ++I) { // Extract the file name auto Filename = ReadPath(F, Record, Idx); @@ -1278,7 +1323,9 @@ resolveFileRelativeToOriginalDir(const std::string &Filename, const std::string &CurrDir) { assert(OriginalDir != CurrDir && "No point trying to resolve the file if the PCH dir didn't change"); + using namespace llvm::sys; + SmallString<128> filePath(Filename); fs::make_absolute(filePath); assert(path::is_absolute(OriginalDir)); @@ -1672,6 +1719,7 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) { std::pair<unsigned, unsigned> HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; + unsigned KeyLen = (unsigned) endian::readNext<uint16_t, little, unaligned>(d); unsigned DataLen = (unsigned) *d++; return std::make_pair(KeyLen, DataLen); @@ -1680,6 +1728,7 @@ HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; + internal_key_type ikey; ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d)); ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d)); @@ -1691,8 +1740,9 @@ HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { HeaderFileInfoTrait::data_type HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, unsigned DataLen) { - const unsigned char *End = d + DataLen; using namespace llvm::support; + + const unsigned char *End = d + DataLen; HeaderFileInfo HFI; unsigned Flags = *d++; // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. @@ -1813,7 +1863,7 @@ namespace { unsigned PriorGeneration; unsigned &NumIdentifierLookups; unsigned &NumIdentifierLookupHits; - IdentifierInfo *Found; + IdentifierInfo *Found = nullptr; public: IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, @@ -1822,10 +1872,7 @@ namespace { : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), PriorGeneration(PriorGeneration), NumIdentifierLookups(NumIdentifierLookups), - NumIdentifierLookupHits(NumIdentifierLookupHits), - Found() - { - } + NumIdentifierLookupHits(NumIdentifierLookupHits) {} bool operator()(ModuleFile &M) { // If we've already searched this module file, skip it now. @@ -1858,7 +1905,7 @@ namespace { IdentifierInfo *getIdentifierInfo() const { return Found; } }; -} // end anonymous namespace +} // namespace void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { // Note that we are loading an identifier. @@ -1985,10 +2032,9 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II, MD = PP.AllocateDefMacroDirective(MI, Loc); break; } - case MacroDirective::MD_Undefine: { + case MacroDirective::MD_Undefine: MD = PP.AllocateUndefMacroDirective(Loc); break; - } case MacroDirective::MD_Visibility: bool isPublic = Record[Idx++]; MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic); @@ -2060,14 +2106,12 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { StringRef Filename = FI.Filename; const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false); - // If we didn't find the file, resolve it relative to the // original directory from which this AST file was created. - if (File == nullptr && !F.OriginalDir.empty() && !CurrentDir.empty() && - F.OriginalDir != CurrentDir) { - std::string Resolved = resolveFileRelativeToOriginalDir(Filename, - F.OriginalDir, - CurrentDir); + if (File == nullptr && !F.OriginalDir.empty() && !F.BaseDirectory.empty() && + F.OriginalDir != F.BaseDirectory) { + std::string Resolved = resolveFileRelativeToOriginalDir( + Filename, F.OriginalDir, F.BaseDirectory); if (!Resolved.empty()) File = FileMgr.getFile(Resolved); } @@ -2126,7 +2170,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { if (Complain) { // Build a list of the PCH imports that got us here (in reverse). SmallVector<ModuleFile *, 4> ImportStack(1, &F); - while (ImportStack.back()->ImportedBy.size() > 0) + while (!ImportStack.back()->ImportedBy.empty()) ImportStack.push_back(ImportStack.back()->ImportedBy[0]); // The top-level PCH is stale. @@ -2487,7 +2531,23 @@ ASTReader::ReadControlBlock(ModuleFile &F, {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++]}}}; - auto ImportedFile = ReadPath(F, Record, Idx); + + std::string ImportedName = ReadString(Record, Idx); + std::string ImportedFile; + + // For prebuilt and explicit modules first consult the file map for + // an override. Note that here we don't search prebuilt module + // directories, only the explicit name to file mappings. Also, we will + // still verify the size/signature making sure it is essentially the + // same file but perhaps in a different location. + if (ImportedKind == MK_PrebuiltModule || ImportedKind == MK_ExplicitModule) + ImportedFile = PP.getHeaderSearchInfo().getPrebuiltModuleFileName( + ImportedName, /*FileMapOnly*/ true); + + if (ImportedFile.empty()) + ImportedFile = ReadPath(F, Record, Idx); + else + SkipPath(Record, Idx); // If our client can't cope with us being out of date, we can't cope with // our dependency being missing. @@ -2608,7 +2668,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case llvm::BitstreamEntry::Error: Error("error at end of module block in AST file"); return Failure; - case llvm::BitstreamEntry::EndBlock: { + case llvm::BitstreamEntry::EndBlock: // Outside of C++, we do not store a lookup map for the translation unit. // Instead, mark it as needing a lookup map to be built if this module // contains any declarations lexically within it (which it always does!). @@ -2621,7 +2681,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } return Success; - } case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case DECLTYPES_BLOCK_ID: @@ -2981,8 +3040,20 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case PP_CONDITIONAL_STACK: if (!Record.empty()) { + unsigned Idx = 0, End = Record.size() - 1; + bool ReachedEOFWhileSkipping = Record[Idx++]; + llvm::Optional<Preprocessor::PreambleSkipInfo> SkipInfo; + if (ReachedEOFWhileSkipping) { + SourceLocation HashToken = ReadSourceLocation(F, Record, Idx); + SourceLocation IfTokenLoc = ReadSourceLocation(F, Record, Idx); + bool FoundNonSkipPortion = Record[Idx++]; + bool FoundElse = Record[Idx++]; + SourceLocation ElseLoc = ReadSourceLocation(F, Record, Idx); + SkipInfo.emplace(HashToken, IfTokenLoc, FoundNonSkipPortion, + FoundElse, ElseLoc); + } SmallVector<PPConditionalInfo, 4> ConditionalStack; - for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { + while (Idx < End) { auto Loc = ReadSourceLocation(F, Record, Idx); bool WasSkipping = Record[Idx++]; bool FoundNonSkip = Record[Idx++]; @@ -2990,7 +3061,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ConditionalStack.push_back( {Loc, WasSkipping, FoundNonSkip, FoundElse}); } - PP.setReplayablePreambleConditionalStack(ConditionalStack); + PP.setReplayablePreambleConditionalStack(ConditionalStack, SkipInfo); } break; @@ -3144,7 +3215,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - case DECL_UPDATE_OFFSETS: { + case DECL_UPDATE_OFFSETS: if (Record.size() % 2 != 0) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); return Failure; @@ -3160,9 +3231,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); } break; - } - case OBJC_CATEGORIES_MAP: { + case OBJC_CATEGORIES_MAP: if (F.LocalNumObjCCategoriesInMap != 0) { Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); return Failure; @@ -3171,7 +3241,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { F.LocalNumObjCCategoriesInMap = Record[0]; F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data(); break; - } case OBJC_CATEGORIES: F.ObjCCategories.swap(Record); @@ -3185,7 +3254,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; - case HEADER_SEARCH_TABLE: { + case HEADER_SEARCH_TABLE: F.HeaderFileInfoTableData = Blob.data(); F.LocalNumHeaderFileInfos = Record[1]; if (Record[0]) { @@ -3202,7 +3271,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { PP.getHeaderSearchInfo().SetExternalLookup(this); } break; - } case FP_PRAGMA_OPTIONS: // Later tables overwrite earlier ones. @@ -3270,6 +3338,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ReadSourceLocation(F, Record, I).getRawEncoding()); } break; + case DELETE_EXPRS_TO_ANALYZE: for (unsigned I = 0, N = Record.size(); I != N;) { DelayedDeleteExprs.push_back(getGlobalDeclID(F, Record[I++])); @@ -3283,7 +3352,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } break; - case IMPORTED_MODULES: { + case IMPORTED_MODULES: if (!F.isModule()) { // If we aren't loading a module (which has its own exports), make // all of the imported modules visible. @@ -3299,7 +3368,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } } break; - } case MACRO_OFFSET: { if (F.LocalNumMacros != 0) { @@ -3325,10 +3393,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - case LATE_PARSED_TEMPLATE: { + case LATE_PARSED_TEMPLATE: LateParsedTemplates.append(Record.begin(), Record.end()); break; - } case OPTIMIZE_PRAGMA_OPTIONS: if (Record.size() != 1) { @@ -3384,6 +3451,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { PragmaPackStackEntry Entry; Entry.Value = Record[Idx++]; Entry.Location = ReadSourceLocation(F, Record[Idx++]); + Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]); PragmaPackStrings.push_back(ReadString(Record, Idx)); Entry.SlotLabel = PragmaPackStrings.back(); PragmaPackStack.push_back(Entry); @@ -3409,8 +3477,7 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { } // Continuous range maps we may be updating in our module. - typedef ContinuousRangeMap<uint32_t, int, 2>::Builder - RemapBuilder; + using RemapBuilder = ContinuousRangeMap<uint32_t, int, 2>::Builder; RemapBuilder SLocRemap(F.SLocRemap); RemapBuilder IdentifierRemap(F.IdentifierRemap); RemapBuilder MacroRemap(F.MacroRemap); @@ -3421,12 +3488,18 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { RemapBuilder TypeRemap(F.TypeRemap); while (Data < DataEnd) { - // FIXME: Looking up dependency modules by filename is horrible. + // FIXME: Looking up dependency modules by filename is horrible. Let's + // start fixing this with prebuilt and explicit modules and see how it + // goes... using namespace llvm::support; + ModuleKind Kind = static_cast<ModuleKind>( + endian::readNext<uint8_t, little, unaligned>(Data)); uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data); StringRef Name = StringRef((const char*)Data, Len); Data += Len; - ModuleFile *OM = ModuleMgr.lookup(Name); + ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule + ? ModuleMgr.lookupByModuleName(Name) + : ModuleMgr.lookupByFileName(Name)); if (!OM) { std::string Msg = "SourceLocation remap refers to unknown module, cannot find "; @@ -3497,15 +3570,22 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, if (!ModMap) { assert(ImportedBy && "top-level import should be verified"); if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) { - if (auto *ASTFE = M ? M->getASTFile() : nullptr) + if (auto *ASTFE = M ? M->getASTFile() : nullptr) { // This module was defined by an imported (explicit) module. Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName << ASTFE->getName(); - else + } else { // This module was built with a different module map. Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName << ImportedBy->FileName << F.ModuleMapPath; + // In case it was imported by a PCH, there's a chance the user is + // just missing to include the search path to the directory containing + // the modulemap. + if (ImportedBy->Kind == MK_PCH) + Diag(diag::note_imported_by_pch_module_not_found) + << llvm::sys::path::parent_path(F.ModuleMapPath); + } } return OutOfDate; } @@ -3568,7 +3648,6 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, return Success; } - /// \brief Move the given method to the back of the global list of methods. static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { // Find the entry for this selector in the method pool. @@ -4065,13 +4144,6 @@ ASTReader::ReadASTCore(StringRef FileName, assert(M && "Missing module file"); - // FIXME: This seems rather a hack. Should CurrentDir be part of the - // module? - if (FileName != "-") { - CurrentDir = llvm::sys::path::parent_path(FileName); - if (CurrentDir.empty()) CurrentDir = "."; - } - ModuleFile &F = *M; BitstreamCursor &Stream = F.Stream; Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer)); @@ -4228,7 +4300,7 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( // Read all of the records in the options block. RecordData Record; ASTReadResult Result = Success; - while (1) { + while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { @@ -4248,11 +4320,10 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( Record.clear(); switch ( (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) { - case SIGNATURE: { + case SIGNATURE: if (F) std::copy(Record.begin(), Record.end(), F->Signature.data()); break; - } case DIAGNOSTIC_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; if (Listener && ValidateDiagnosticOptions && @@ -4581,9 +4652,7 @@ namespace { ExistingTargetOpts(ExistingTargetOpts), ExistingPPOpts(ExistingPPOpts), ExistingModuleCachePath(ExistingModuleCachePath), - FileMgr(FileMgr) - { - } + FileMgr(FileMgr) {} bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override { @@ -4613,7 +4682,7 @@ namespace { } }; -} // end anonymous namespace +} // namespace bool ASTReader::readASTFileControlBlock( StringRef Filename, FileManager &FileMgr, @@ -4697,15 +4766,12 @@ bool ASTReader::readASTFileControlBlock( StringRef Blob; unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); switch ((ControlRecordTypes)RecCode) { - case METADATA: { + case METADATA: if (Record[0] != VERSION_MAJOR) return true; - if (Listener.ReadFullVersionInformation(Blob)) return true; - break; - } case MODULE_NAME: Listener.ReadModuleName(Blob); break; @@ -4764,6 +4830,7 @@ bool ASTReader::readASTFileControlBlock( while (Idx < N) { // Read information about the AST file. Idx += 5; // ImportLoc, Size, ModTime, Signature + SkipString(Record, Idx); // Module name; FIXME: pass to listener? std::string Filename = ReadString(Record, Idx); ResolveImportedPath(Filename, ModuleDir); Listener.visitImport(Filename); @@ -4856,7 +4923,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; - Module::ModuleKind ModuleKind = Module::ModuleMapModule; RecordData Record; while (true) { llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); @@ -4904,6 +4970,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { unsigned Idx = 0; SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); + Module::ModuleKind Kind = (Module::ModuleKind)Record[Idx++]; bool IsFramework = Record[Idx++]; bool IsExplicit = Record[Idx++]; bool IsSystem = Record[Idx++]; @@ -4950,7 +5017,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { CurrentModule->PresumedModuleMapFile = F.ModuleMapPath; } - CurrentModule->Kind = ModuleKind; + CurrentModule->Kind = Kind; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; @@ -5012,10 +5079,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // them here. break; - case SUBMODULE_TOPHEADER: { + case SUBMODULE_TOPHEADER: CurrentModule->addTopHeaderFilename(Blob); break; - } case SUBMODULE_UMBRELLA_DIR: { std::string Dirname = Blob; @@ -5049,11 +5115,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } - ModuleKind = (Module::ModuleKind)Record[2]; break; } - case SUBMODULE_IMPORTS: { + case SUBMODULE_IMPORTS: for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; @@ -5064,9 +5129,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { UnresolvedModuleRefs.push_back(Unresolved); } break; - } - case SUBMODULE_EXPORTS: { + case SUBMODULE_EXPORTS: for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; @@ -5081,12 +5145,11 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // the parsed, unresolved exports around. CurrentModule->UnresolvedExports.clear(); break; - } - case SUBMODULE_REQUIRES: { + + case SUBMODULE_REQUIRES: CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(), PP.getTargetInfo()); break; - } case SUBMODULE_LINK_LIBRARY: CurrentModule->LinkLibraries.push_back( @@ -5109,7 +5172,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - case SUBMODULE_INITIALIZERS: + case SUBMODULE_INITIALIZERS: { if (!ContextObj) break; SmallVector<uint32_t, 16> Inits; @@ -5118,6 +5181,11 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } + + case SUBMODULE_EXPORT_AS: + CurrentModule->ExportAsModule = Blob.str(); + break; + } } } @@ -5406,10 +5474,12 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { llvm_unreachable("Invalid PreprocessorDetailRecordTypes"); } -/// \brief \arg SLocMapI points at a chunk of a module that contains no -/// preprocessed entities or the entities it contains are not the ones we are -/// looking for. Find the next module that contains entities and return the ID +/// \brief Find the next module that contains entities and return the ID /// of the first entry. +/// +/// \param SLocMapI points at a chunk of a module that contains no +/// preprocessed entities or the entities it contains are not the ones we are +/// looking for. PreprocessedEntityID ASTReader::findNextPreprocessedEntity( GlobalSLocOffsetMapType::const_iterator SLocMapI) const { ++SLocMapI; @@ -5429,7 +5499,7 @@ struct PPEntityComp { const ASTReader &Reader; ModuleFile &M; - PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { } + PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) {} bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { SourceLocation LHS = getLoc(L); @@ -5452,7 +5522,7 @@ struct PPEntityComp { } }; -} // end anonymous namespace +} // namespace PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc, bool EndsAfter) const { @@ -5468,7 +5538,9 @@ PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc, return findNextPreprocessedEntity(SLocMapI); ModuleFile &M = *SLocMapI->second; - typedef const PPEntityOffset *pp_iterator; + + using pp_iterator = const PPEntityOffset *; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; @@ -5546,12 +5618,10 @@ namespace { /// \brief Visitor used to search for information about a header file. class HeaderFileInfoVisitor { const FileEntry *FE; - Optional<HeaderFileInfo> HFI; public: - explicit HeaderFileInfoVisitor(const FileEntry *FE) - : FE(FE) { } + explicit HeaderFileInfoVisitor(const FileEntry *FE) : FE(FE) {} bool operator()(ModuleFile &M) { HeaderFileInfoLookupTable *Table @@ -5571,7 +5641,7 @@ namespace { Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } }; -} // end anonymous namespace +} // namespace HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { HeaderFileInfoVisitor Visitor(FE); @@ -5709,7 +5779,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { // Preserve the property that the imaginary root file describes the // current state. - auto &T = Diag.DiagStatesByLoc.Files[FileID()].StateTransitions; + FileID NullFile; + auto &T = Diag.DiagStatesByLoc.Files[NullFile].StateTransitions; if (T.empty()) T.push_back({CurState, 0}); else @@ -6091,6 +6162,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); return Context.getObjCTypeParamType(Decl, Protos); } + case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); @@ -6250,6 +6322,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, AttrLoc); } + + case TYPE_DEPENDENT_ADDRESS_SPACE: { + unsigned Idx = 0; + + // DependentAddressSpaceType + QualType PointeeType = readType(*Loc.F, Record, Idx); + Expr *AddrSpaceExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + + return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr, + AttrLoc); + } } llvm_unreachable("Invalid TypeCode!"); } @@ -6275,7 +6359,9 @@ void ASTReader::readExceptionSpec(ModuleFile &ModuleFile, } } -class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> { +namespace clang { + +class TypeLocReader : public TypeLocVisitor<TypeLocReader> { ModuleFile *F; ASTReader *Reader; const ASTReader::RecordData &Record; @@ -6310,6 +6396,8 @@ public: void VisitArrayTypeLoc(ArrayTypeLoc); }; +} // namespace clang + void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } @@ -6383,6 +6471,17 @@ void TypeLocReader::VisitDependentSizedArrayTypeLoc( VisitArrayTypeLoc(TL); } +void TypeLocReader::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + + TL.setAttrNameLoc(ReadSourceLocation()); + SourceRange range; + range.setBegin(ReadSourceLocation()); + range.setEnd(ReadSourceLocation()); + TL.setAttrOperandParensRange(range); + TL.setAttrExprOperand(Reader->ReadExpr(*F)); +} + void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); @@ -6415,23 +6514,28 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } + void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } + void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } + void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); } + void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } + void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } @@ -6485,10 +6589,12 @@ void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } + void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } + void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setTemplateKeywordLoc(ReadSourceLocation()); @@ -6501,6 +6607,7 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc( Reader->GetTemplateArgumentLocInfo( *F, TL.getTypePtr()->getArg(i).getKind(), Record, Idx)); } + void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); @@ -6611,13 +6718,11 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; - case PREDEF_TYPE_CHAR_U_ID: case PREDEF_TYPE_CHAR_S_ID: // FIXME: Check that the signedness of CharTy is correct! T = Context.CharTy; break; - case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; @@ -6669,6 +6774,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; + case PREDEF_TYPE_FLOAT16_ID: + T = Context.Float16Ty; + break; case PREDEF_TYPE_FLOAT128_ID: T = Context.Float128Ty; break; @@ -6728,19 +6836,15 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; - case PREDEF_TYPE_AUTO_RREF_DEDUCT: T = Context.getAutoRRefDeductType(); break; - case PREDEF_TYPE_ARC_UNBRIDGED_CAST: T = Context.ARCUnbridgedCastTy; break; - case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; - case PREDEF_TYPE_OMP_ARRAY_SECTION: T = Context.OMPArraySectionTy; break; @@ -7227,7 +7331,7 @@ public: } }; -} // end anonymous namespace +} // namespace void ASTReader::FindFileRegionDecls(FileID File, unsigned Offset, unsigned Length, @@ -7423,30 +7527,25 @@ void ASTReader::PrintStats() { NumVisibleDeclContextsRead, TotalVisibleDeclContexts, ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts * 100)); - if (TotalNumMethodPoolEntries) { + if (TotalNumMethodPoolEntries) std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", NumMethodPoolEntriesRead, TotalNumMethodPoolEntries, ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries * 100)); - } - if (NumMethodPoolLookups) { + if (NumMethodPoolLookups) std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n", NumMethodPoolHits, NumMethodPoolLookups, ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0)); - } - if (NumMethodPoolTableLookups) { + if (NumMethodPoolTableLookups) std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n", NumMethodPoolTableHits, NumMethodPoolTableLookups, ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups * 100.0)); - } - - if (NumIdentifierLookupHits) { + if (NumIdentifierLookupHits) std::fprintf(stderr, " %u / %u identifier table lookups succeeded (%f%%)\n", NumIdentifierLookupHits, NumIdentifierLookups, (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); - } if (GlobalIndex) { std::fprintf(stderr, "\n"); @@ -7466,7 +7565,8 @@ dumpModuleIDMap(StringRef Name, if (Map.begin() == Map.end()) return; - typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType; + using MapType = ContinuousRangeMap<Key, ModuleFile *, InitialCapacity>; + llvm::errs() << Name << ":\n"; for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); I != IEnd; ++I) { @@ -7579,13 +7679,14 @@ void ASTReader::UpdateSema() { "Expected a default alignment value"); SemaObj->PackStack.Stack.emplace_back( PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue, - SemaObj->PackStack.CurrentPragmaLocation); + SemaObj->PackStack.CurrentPragmaLocation, + PragmaPackStack.front().PushLocation); DropFirst = true; } for (const auto &Entry : llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value, - Entry.Location); + Entry.Location, Entry.PushLocation); if (PragmaPackCurrentLocation.isInvalid()) { assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && "Expected a default alignment value"); @@ -7662,7 +7763,7 @@ namespace clang { StringRef Next() override; }; -} // end namespace clang +} // namespace clang ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader, bool SkipModules) @@ -7720,7 +7821,7 @@ public: } }; -} // end anonymous namespace. +} // namespace IdentifierIterator *ASTReader::getIdentifiers() { if (!loadGlobalIndex()) { @@ -7742,19 +7843,17 @@ namespace serialization { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; - unsigned InstanceBits; - unsigned FactoryBits; - bool InstanceHasMoreThanOneDecl; - bool FactoryHasMoreThanOneDecl; + unsigned InstanceBits = 0; + unsigned FactoryBits = 0; + bool InstanceHasMoreThanOneDecl = false; + bool FactoryHasMoreThanOneDecl = false; SmallVector<ObjCMethodDecl *, 4> InstanceMethods; SmallVector<ObjCMethodDecl *, 4> FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) - : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration), - InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false), - FactoryHasMoreThanOneDecl(false) {} + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) {} bool operator()(ModuleFile &M) { if (!M.SelectorLookupTable) @@ -7802,14 +7901,16 @@ namespace serialization { unsigned getInstanceBits() const { return InstanceBits; } unsigned getFactoryBits() const { return FactoryBits; } + bool instanceHasMoreThanOneDecl() const { return InstanceHasMoreThanOneDecl; } + bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; } }; -} // end namespace serialization -} // end namespace clang +} // namespace serialization +} // namespace clang /// \brief Add the given set of methods to the method list. static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods, @@ -7952,7 +8053,7 @@ void ASTReader::ReadUnusedLocalTypedefNameCandidates( } void ASTReader::ReadReferencedSelectors( - SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) { + SmallVectorImpl<std::pair<Selector, SourceLocation>> &Sels) { if (ReferencedSelectorsData.empty()) return; @@ -7970,7 +8071,7 @@ void ASTReader::ReadReferencedSelectors( } void ASTReader::ReadWeakUndeclaredIdentifiers( - SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) { + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo>> &WeakIDs) { if (WeakUndeclaredIdentifiers.empty()) return; @@ -8002,7 +8103,7 @@ void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) { } void ASTReader::ReadPendingInstantiations( - SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) { + SmallVectorImpl<std::pair<ValueDecl *, SourceLocation>> &Pending) { for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++])); SourceLocation Loc @@ -8276,8 +8377,8 @@ ASTReader::getSourceDescriptor(unsigned ID) { } ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { - auto I = BodySource.find(FD); - if (I == BodySource.end()) + auto I = DefinitionSource.find(FD); + if (I == DefinitionSource.end()) return EK_ReplyHazy; return I->second ? EK_Never : EK_Always; } @@ -8714,11 +8815,10 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F, break; } - case NestedNameSpecifier::Global: { + case NestedNameSpecifier::Global: NNS = NestedNameSpecifier::GlobalSpecifier(Context); // No associated value, and there can't be a prefix. break; - } case NestedNameSpecifier::Super: { CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx); @@ -8895,7 +8995,7 @@ void ASTReader::ReadComments() { ASTContext &Context = getContext(); std::vector<RawComment *> Comments; for (SmallVectorImpl<std::pair<BitstreamCursor, - serialization::ModuleFile *> >::iterator + serialization::ModuleFile *>>::iterator I = CommentsCursors.begin(), E = CommentsCursors.end(); I != E; ++I) { @@ -8985,7 +9085,7 @@ std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { return M->ModuleName; // Not from a module. - return ""; + return {}; } void ASTReader::finishPendingActions() { @@ -8995,8 +9095,8 @@ void ASTReader::finishPendingActions() { !PendingUpdateRecords.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. - typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > - TopLevelDeclsMap; + using TopLevelDeclsMap = + llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2>>; TopLevelDeclsMap TopLevelDecls; while (!PendingIdentifierInfos.empty()) { @@ -9167,7 +9267,8 @@ void ASTReader::diagnoseOdrViolations() { Merge.first->decls_begin(); Merge.first->bases_begin(); Merge.first->vbases_begin(); - for (auto *RD : Merge.second) { + for (auto &RecordPair : Merge.second) { + auto *RD = RecordPair.first; RD->decls_begin(); RD->bases_begin(); RD->vbases_begin(); @@ -9273,14 +9374,326 @@ void ASTReader::diagnoseOdrViolations() { bool Diagnosed = false; CXXRecordDecl *FirstRecord = Merge.first; std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord); - for (CXXRecordDecl *SecondRecord : Merge.second) { + for (auto &RecordPair : Merge.second) { + CXXRecordDecl *SecondRecord = RecordPair.first; // Multiple different declarations got merged together; tell the user // where they came from. if (FirstRecord == SecondRecord) continue; std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord); + + auto *FirstDD = FirstRecord->DefinitionData; + auto *SecondDD = RecordPair.second; + + assert(FirstDD && SecondDD && "Definitions without DefinitionData"); + + // Diagnostics from DefinitionData are emitted here. + if (FirstDD != SecondDD) { + enum ODRDefinitionDataDifference { + NumBases, + NumVBases, + BaseType, + BaseVirtual, + BaseAccess, + }; + auto ODRDiagError = [FirstRecord, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRDefinitionDataDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_definition_data) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, + this](SourceLocation Loc, SourceRange Range, + ODRDefinitionDataDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_definition_data) + << SecondModule << Range << DiffType; + }; + + ODRHash Hash; + auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { + Hash.clear(); + Hash.AddQualType(Ty); + return Hash.CalculateHash(); + }; + + unsigned FirstNumBases = FirstDD->NumBases; + unsigned FirstNumVBases = FirstDD->NumVBases; + unsigned SecondNumBases = SecondDD->NumBases; + unsigned SecondNumVBases = SecondDD->NumVBases; + + auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) { + unsigned NumBases = DD->NumBases; + if (NumBases == 0) return SourceRange(); + auto bases = DD->bases(); + return SourceRange(bases[0].getLocStart(), + bases[NumBases - 1].getLocEnd()); + }; + + if (FirstNumBases != SecondNumBases) { + ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD), + NumBases) + << FirstNumBases; + ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), + NumBases) + << SecondNumBases; + Diagnosed = true; + break; + } + + if (FirstNumVBases != SecondNumVBases) { + ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD), + NumVBases) + << FirstNumVBases; + ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), + NumVBases) + << SecondNumVBases; + Diagnosed = true; + break; + } + + auto FirstBases = FirstDD->bases(); + auto SecondBases = SecondDD->bases(); + unsigned i = 0; + for (i = 0; i < FirstNumBases; ++i) { + auto FirstBase = FirstBases[i]; + auto SecondBase = SecondBases[i]; + if (ComputeQualTypeODRHash(FirstBase.getType()) != + ComputeQualTypeODRHash(SecondBase.getType())) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseType) + << (i + 1) << FirstBase.getType(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseType) + << (i + 1) << SecondBase.getType(); + break; + } + + if (FirstBase.isVirtual() != SecondBase.isVirtual()) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseVirtual) + << (i + 1) << FirstBase.isVirtual() << FirstBase.getType(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseVirtual) + << (i + 1) << SecondBase.isVirtual() << SecondBase.getType(); + break; + } + + if (FirstBase.getAccessSpecifierAsWritten() != + SecondBase.getAccessSpecifierAsWritten()) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseAccess) + << (i + 1) << FirstBase.getType() + << (int)FirstBase.getAccessSpecifierAsWritten(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseAccess) + << (i + 1) << SecondBase.getType() + << (int)SecondBase.getAccessSpecifierAsWritten(); + break; + } + } + + if (i != FirstNumBases) { + Diagnosed = true; + break; + } + } + using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>; + + const ClassTemplateDecl *FirstTemplate = + FirstRecord->getDescribedClassTemplate(); + const ClassTemplateDecl *SecondTemplate = + SecondRecord->getDescribedClassTemplate(); + + assert(!FirstTemplate == !SecondTemplate && + "Both pointers should be null or non-null"); + + enum ODRTemplateDifference { + ParamEmptyName, + ParamName, + ParamSingleDefaultArgument, + ParamDifferentDefaultArgument, + }; + + if (FirstTemplate && SecondTemplate) { + DeclHashes FirstTemplateHashes; + DeclHashes SecondTemplateHashes; + ODRHash Hash; + + auto PopulateTemplateParameterHashs = + [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) { + for (auto *D : TD->getTemplateParameters()->asArray()) { + Hash.clear(); + Hash.AddSubDecl(D); + Hashes.emplace_back(D, Hash.CalculateHash()); + } + }; + + PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate); + PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate); + + assert(FirstTemplateHashes.size() == SecondTemplateHashes.size() && + "Number of template parameters should be equal."); + + auto FirstIt = FirstTemplateHashes.begin(); + auto FirstEnd = FirstTemplateHashes.end(); + auto SecondIt = SecondTemplateHashes.begin(); + for (; FirstIt != FirstEnd; ++FirstIt, ++SecondIt) { + if (FirstIt->second == SecondIt->second) + continue; + + auto ODRDiagError = [FirstRecord, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRTemplateDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_template_parameter) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, + this](SourceLocation Loc, SourceRange Range, + ODRTemplateDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_template_parameter) + << SecondModule << Range << DiffType; + }; + + const NamedDecl* FirstDecl = cast<NamedDecl>(FirstIt->first); + const NamedDecl* SecondDecl = cast<NamedDecl>(SecondIt->first); + + assert(FirstDecl->getKind() == SecondDecl->getKind() && + "Parameter Decl's should be the same kind."); + + DeclarationName FirstName = FirstDecl->getDeclName(); + DeclarationName SecondName = SecondDecl->getDeclName(); + + if (FirstName != SecondName) { + const bool FirstNameEmpty = + FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo(); + const bool SecondNameEmpty = + SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo(); + assert((!FirstNameEmpty || !SecondNameEmpty) && + "Both template parameters cannot be unnamed."); + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + FirstNameEmpty ? ParamEmptyName : ParamName) + << FirstName; + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + SecondNameEmpty ? ParamEmptyName : ParamName) + << SecondName; + break; + } + + switch (FirstDecl->getKind()) { + default: + llvm_unreachable("Invalid template parameter type."); + case Decl::TemplateTypeParm: { + const auto *FirstParam = cast<TemplateTypeParmDecl>(FirstDecl); + const auto *SecondParam = cast<TemplateTypeParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + case Decl::NonTypeTemplateParm: { + const auto *FirstParam = cast<NonTypeTemplateParmDecl>(FirstDecl); + const auto *SecondParam = cast<NonTypeTemplateParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + case Decl::TemplateTemplateParm: { + const auto *FirstParam = cast<TemplateTemplateParmDecl>(FirstDecl); + const auto *SecondParam = + cast<TemplateTemplateParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + } + + break; + } + + if (FirstIt != FirstEnd) { + Diagnosed = true; + break; + } + } + DeclHashes FirstHashes; DeclHashes SecondHashes; ODRHash Hash; @@ -10050,7 +10463,7 @@ void ASTReader::diagnoseOdrViolations() { } } - if (Diagnosed == true) + if (Diagnosed) continue; Diag(FirstDecl->getLocation(), @@ -10160,7 +10573,8 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context, SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), ContextObj(Context), - ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr), + ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr, + PP.getHeaderSearchInfo()), PCMCache(PP.getPCMCache()), DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index 085341571ced4..a3bf0d9712673 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -453,7 +453,7 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { if (Record.readInt()) - Reader.BodySource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; + Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { CD->NumCtorInitializers = Record.readInt(); if (CD->NumCtorInitializers) @@ -1219,16 +1219,17 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->Mutable = Record.readInt(); - if (int BitWidthOrInitializer = Record.readInt()) { - FD->InitStorage.setInt( - static_cast<FieldDecl::InitStorageKind>(BitWidthOrInitializer - 1)); - if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { - // Read captured variable length array. - FD->InitStorage.setPointer(Record.readType().getAsOpaquePtr()); - } else { - FD->InitStorage.setPointer(Record.readExpr()); - } + + if (auto ISK = static_cast<FieldDecl::InitStorageKind>(Record.readInt())) { + FD->InitStorage.setInt(ISK); + FD->InitStorage.setPointer(ISK == FieldDecl::ISK_CapturedVLAType + ? Record.readType().getAsOpaquePtr() + : Record.readExpr()); } + + if (auto *BW = Record.readExpr()) + FD->setBitWidth(BW); + if (!FD->getDeclName()) { if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>()) Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); @@ -1293,6 +1294,9 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { } } + if (VD->getStorageDuration() == SD_Static && Record.readInt()) + Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile; + enum VarKind { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization }; @@ -1587,11 +1591,8 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.ODRHash = Record.readInt(); Data.HasODRHash = true; - if (Record.readInt()) { - Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile - ? ExternalASTSource::EK_Never - : ExternalASTSource::EK_Always; - } + if (Record.readInt()) + Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile; Data.NumBases = Record.readInt(); if (Data.NumBases) @@ -1754,7 +1755,8 @@ void ASTDeclReader::MergeDefinitionData( } if (DetectedOdrViolation) - Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition); + Reader.PendingOdrMergeFailures[DD.Definition].push_back( + {MergeDD.Definition, &MergeDD}); } void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) { @@ -1861,6 +1863,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { VisitFunctionDecl(D); + D->IsCopyDeductionCandidate = Record.readInt(); } void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { @@ -1899,9 +1902,12 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>()) { auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl()); + auto *ThisArg = Record.readExpr(); // FIXME: Check consistency if we have an old and new operator delete. - if (!Canon->OperatorDelete) + if (!Canon->OperatorDelete) { Canon->OperatorDelete = OperatorDelete; + Canon->OperatorDeleteThisArg = ThisArg; + } } } @@ -2192,6 +2198,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); D->PointOfInstantiation = ReadSourceLocation(); D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); + D->IsCompleteDefinition = Record.readInt(); bool writtenAsCanonicalDecl = Record.readInt(); if (writtenAsCanonicalDecl) { @@ -2514,7 +2521,9 @@ void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { VisitValueDecl(D); D->setLocation(ReadSourceLocation()); D->setCombiner(Record.readExpr()); - D->setInitializer(Record.readExpr()); + D->setInitializer( + Record.readExpr(), + static_cast<OMPDeclareReductionDecl::InitKind>(Record.readInt())); D->PrevDeclInScope = ReadDeclID(); } @@ -2567,11 +2576,14 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) { // An ObjCMethodDecl is never considered as "interesting" because its // implementation container always is. - // An ImportDecl or VarDecl imported from a module will get emitted when - // we import the relevant module. - if ((isa<ImportDecl>(D) || isa<VarDecl>(D)) && D->getImportedOwningModule() && - Ctx.DeclMustBeEmitted(D)) - return false; + // An ImportDecl or VarDecl imported from a module map module will get + // emitted when we import the relevant module. + if (isa<ImportDecl>(D) || isa<VarDecl>(D)) { + auto *M = D->getImportedOwningModule(); + if (M && M->Kind == Module::ModuleMapModule && + Ctx.DeclMustBeEmitted(D)) + return false; + } if (isa<FileScopeAsmDecl>(D) || isa<ObjCProtocolDecl>(D) || @@ -2810,7 +2822,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { // FIXME: Do we need to check for C++14 deduced return types here too? auto *XFPT = FuncX->getType()->getAs<FunctionProtoType>(); auto *YFPT = FuncY->getType()->getAs<FunctionProtoType>(); - if (C.getLangOpts().CPlusPlus1z && XFPT && YFPT && + if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT && (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) || isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) && C.hasSameFunctionTypeIgnoringExceptionSpec(FuncX->getType(), @@ -3972,10 +3984,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { + case UPD_CXX_ADDED_VAR_DEFINITION: { VarDecl *VD = cast<VarDecl>(D); - VD->getMemberSpecializationInfo()->setPointOfInstantiation( - ReadSourceLocation()); + VD->NonParmVarDeclBits.IsInline = Record.readInt(); + VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt(); uint64_t Val = Record.readInt(); if (Val && !VD->getInit()) { VD->setInit(Record.readExpr()); @@ -3988,6 +4000,25 @@ void ASTDeclReader::UpdateDecl(Decl *D, break; } + case UPD_CXX_POINT_OF_INSTANTIATION: { + SourceLocation POI = Record.readSourceLocation(); + if (VarTemplateSpecializationDecl *VTSD = + dyn_cast<VarTemplateSpecializationDecl>(D)) { + VTSD->setPointOfInstantiation(POI); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + VD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + } else { + auto *FD = cast<FunctionDecl>(D); + if (auto *FTSInfo = FD->TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + FTSInfo->setPointOfInstantiation(POI); + else + FD->TemplateOrSpecialization.get<MemberSpecializationInfo *>() + ->setPointOfInstantiation(POI); + } + break; + } + case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: { auto Param = cast<ParmVarDecl>(D); @@ -4106,9 +4137,12 @@ void ASTDeclReader::UpdateDecl(Decl *D, // record. auto *Del = ReadDeclAs<FunctionDecl>(); auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl()); + auto *ThisArg = Record.readExpr(); // FIXME: Check consistency if we have an old and new operator delete. - if (!First->OperatorDelete) + if (!First->OperatorDelete) { First->OperatorDelete = Del; + First->OperatorDeleteThisArg = ThisArg; + } break; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h index 6cb4d662e3389..2b92ae65ea84c 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h @@ -1,4 +1,4 @@ -//===--- ASTReaderInternals.h - AST Reader Internals ------------*- C++ -*-===// +//===- ASTReaderInternals.h - AST Reader Internals --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,23 +10,29 @@ // This file provides internal definitions used in the AST reader. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H #define LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H #include "MultiOnDiskHashTable.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/LLVM.h" #include "clang/Serialization/ASTBitCodes.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/Support/Endian.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/OnDiskHashTable.h" +#include <ctime> #include <utility> namespace clang { class ASTReader; -class HeaderSearch; -struct HeaderFileInfo; class FileEntry; +struct HeaderFileInfo; +class HeaderSearch; +class IdentifierTable; +class ObjCMethodDecl; namespace serialization { @@ -45,12 +51,14 @@ public: static const int MaxTables = 4; /// The lookup result is a list of global declaration IDs. - typedef llvm::SmallVector<DeclID, 4> data_type; + using data_type = SmallVector<DeclID, 4>; + struct data_type_builder { data_type &Data; llvm::DenseSet<DeclID> Found; data_type_builder(data_type &D) : Data(D) {} + void insert(DeclID ID) { // Just use a linear scan unless we have more than a few IDs. if (Found.empty() && !Data.empty()) { @@ -70,15 +78,15 @@ public: Data.push_back(ID); } }; - typedef unsigned hash_value_type; - typedef unsigned offset_type; - typedef ModuleFile *file_type; + using hash_value_type = unsigned; + using offset_type = unsigned; + using file_type = ModuleFile *; - typedef DeclarationName external_key_type; - typedef DeclarationNameKey internal_key_type; + using external_key_type = DeclarationName; + using internal_key_type = DeclarationNameKey; explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) - : Reader(Reader), F(F) { } + : Reader(Reader), F(F) {} static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { return a == b; @@ -87,6 +95,7 @@ public: static hash_value_type ComputeHash(const internal_key_type &Key) { return Key.getHash(); } + static internal_key_type GetInternalKey(const external_key_type &Name) { return Name; } @@ -119,14 +128,13 @@ struct DeclContextLookupTable { /// functionality for accessing the on-disk hash table of identifiers /// in an AST file. Different subclasses customize that functionality /// based on what information they are interested in. Those subclasses -/// must provide the \c data_type typedef and the ReadData operation, -/// only. +/// must provide the \c data_type type and the ReadData operation, only. class ASTIdentifierLookupTraitBase { public: - typedef StringRef external_key_type; - typedef StringRef internal_key_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using external_key_type = StringRef; + using internal_key_type = StringRef; + using hash_value_type = unsigned; + using offset_type = unsigned; static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { return a == b; @@ -159,11 +167,11 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { IdentifierInfo *KnownII; public: - typedef IdentifierInfo * data_type; + using data_type = IdentifierInfo *; ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F, IdentifierInfo *II = nullptr) - : Reader(Reader), F(F), KnownII(II) { } + : Reader(Reader), F(F), KnownII(II) {} data_type ReadData(const internal_key_type& k, const unsigned char* d, @@ -176,8 +184,8 @@ public: /// \brief The on-disk hash table used to contain information about /// all of the identifiers in the program. -typedef llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait> - ASTIdentifierLookupTable; +using ASTIdentifierLookupTable = + llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>; /// \brief Class that performs lookup for a selector's entries in the global /// method pool stored in an AST file. @@ -196,13 +204,13 @@ public: SmallVector<ObjCMethodDecl *, 2> Factory; }; - typedef Selector external_key_type; - typedef external_key_type internal_key_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using external_key_type = Selector; + using internal_key_type = external_key_type; + using hash_value_type = unsigned; + using offset_type = unsigned; - ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F) - : Reader(Reader), F(F) { } + ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F) + : Reader(Reader), F(F) {} static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { @@ -222,8 +230,8 @@ public: }; /// \brief The on-disk hash table used for the global method pool. -typedef llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait> - ASTSelectorLookupTable; +using ASTSelectorLookupTable = + llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>; /// \brief Trait class used to search the on-disk hash table containing all of /// the header search information. @@ -241,7 +249,7 @@ class HeaderFileInfoTrait { const char *FrameworkStrings; public: - typedef const FileEntry *external_key_type; + using external_key_type = const FileEntry *; struct internal_key_type { off_t Size; @@ -249,15 +257,16 @@ public: StringRef Filename; bool Imported; }; - typedef const internal_key_type &internal_key_ref; + + using internal_key_ref = const internal_key_type &; - typedef HeaderFileInfo data_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using data_type = HeaderFileInfo; + using hash_value_type = unsigned; + using offset_type = unsigned; HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS, const char *FrameworkStrings) - : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { } + : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) {} static hash_value_type ComputeHash(internal_key_ref ikey); internal_key_type GetInternalKey(const FileEntry *FE); @@ -272,12 +281,13 @@ public: }; /// \brief The on-disk hash table used for known header files. -typedef llvm::OnDiskChainedHashTable<HeaderFileInfoTrait> - HeaderFileInfoLookupTable; +using HeaderFileInfoLookupTable = + llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>; -} // end namespace clang::serialization::reader -} // end namespace clang::serialization -} // end namespace clang +} // namespace reader + +} // namespace serialization +} // namespace clang -#endif +#endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp index 3f5da029947c5..8ef1491eb2da7 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1854,6 +1854,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_task_reduction: C = OMPTaskReductionClause::CreateEmpty(Context, Reader->Record.readInt()); break; + case OMPC_in_reduction: + C = OMPInReductionClause::CreateEmpty(Context, Reader->Record.readInt()); + break; case OMPC_linear: C = OMPLinearClause::CreateEmpty(Context, Reader->Record.readInt()); break; @@ -2192,6 +2195,44 @@ void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { C->setReductionOps(Vars); } +void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Reader->ReadSourceLocation()); + C->setColonLoc(Reader->ReadSourceLocation()); + NestedNameSpecifierLoc NNSL = Reader->Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DNI; + Reader->ReadDeclarationNameInfo(DNI); + C->setQualifierLoc(NNSL); + C->setNameInfo(DNI); + + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setLHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setRHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setReductionOps(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Reader->Record.readSubExpr()); + C->setTaskgroupDescriptors(Vars); +} + void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Reader->ReadSourceLocation()); @@ -2306,6 +2347,7 @@ void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { } void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { + VisitOMPClauseWithPreInit(C); C->setDevice(Reader->Record.readSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation()); } @@ -2766,6 +2808,7 @@ void ASTStmtReader::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { // The NumClauses field was read in ReadStmtFromStream. Record.skipInts(1); VisitOMPExecutableDirective(D); + D->setReductionRef(Record.readSubExpr()); } void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) { @@ -2877,6 +2920,7 @@ void ASTStmtReader::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { void ASTStmtReader::VisitOMPDistributeParallelForDirective( OMPDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); } void ASTStmtReader::VisitOMPDistributeParallelForSimdDirective( @@ -2916,6 +2960,7 @@ void ASTStmtReader::VisitOMPTeamsDistributeParallelForSimdDirective( void ASTStmtReader::VisitOMPTeamsDistributeParallelForDirective( OMPTeamsDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); } void ASTStmtReader::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *D) { @@ -2933,6 +2978,7 @@ void ASTStmtReader::VisitOMPTargetTeamsDistributeDirective( void ASTStmtReader::VisitOMPTargetTeamsDistributeParallelForDirective( OMPTargetTeamsDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); } void ASTStmtReader::VisitOMPTargetTeamsDistributeParallelForSimdDirective( diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 128e53b91b1d1..1e72ced2ee364 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -1,4 +1,4 @@ -//===--- ASTWriter.cpp - AST File Writer ------------------------*- C++ -*-===// +//===- ASTWriter.cpp - AST File Writer ------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -17,11 +17,15 @@ #include "MultiOnDiskHashTable.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/LambdaCapture.h" @@ -30,16 +34,22 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" @@ -62,24 +72,30 @@ #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Bitcode/BitCodes.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -87,11 +103,14 @@ #include <cstdint> #include <cstdlib> #include <cstring> +#include <ctime> #include <deque> #include <limits> -#include <new> +#include <memory> +#include <queue> #include <tuple> #include <utility> +#include <vector> using namespace clang; using namespace clang::serialization; @@ -120,13 +139,14 @@ namespace clang { ASTRecordWriter Record; /// \brief Type code that corresponds to the record generated. - TypeCode Code; + TypeCode Code = static_cast<TypeCode>(0); + /// \brief Abbreviation to use for the record, if any. - unsigned AbbrevToUse; + unsigned AbbrevToUse = 0; public: ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record) - : Writer(Writer), Record(Writer, Record), Code((TypeCode)0), AbbrevToUse(0) { } + : Writer(Writer), Record(Writer, Record) {} uint64_t Emit() { return Record.Emit(Code, AbbrevToUse); @@ -160,7 +180,7 @@ namespace clang { #include "clang/AST/TypeNodes.def" }; -} // end namespace clang +} // namespace clang void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { llvm_unreachable("Built-in types are never serialized"); @@ -433,6 +453,15 @@ ASTTypeWriter::VisitDependentSizedExtVectorType( Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR; } +void +ASTTypeWriter::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + Record.AddTypeRef(T->getPointeeType()); + Record.AddStmt(T->getAddrSpaceExpr()); + Record.AddSourceLocation(T->getAttributeLoc()); + Code = TYPE_DEPENDENT_ADDRESS_SPACE; +} + void ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { Record.push_back(T->getDepth()); @@ -541,8 +570,7 @@ class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { ASTRecordWriter &Record; public: - TypeLocWriter(ASTRecordWriter &Record) - : Record(Record) { } + TypeLocWriter(ASTRecordWriter &Record) : Record(Record) {} #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ @@ -553,7 +581,7 @@ public: void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); }; -} // end anonymous namespace +} // namespace void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do @@ -627,6 +655,15 @@ void TypeLocWriter::VisitDependentSizedArrayTypeLoc( VisitArrayTypeLoc(TL); } +void TypeLocWriter::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + Record.AddSourceLocation(TL.getAttrNameLoc()); + SourceRange range = TL.getAttrOperandParensRange(); + Record.AddSourceLocation(range.getBegin()); + Record.AddSourceLocation(range.getEnd()); + Record.AddStmt(TL.getAttrExprOperand()); +} + void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); @@ -649,18 +686,23 @@ void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) Record.AddDeclRef(TL.getParam(i)); } + void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } + void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } + void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } + void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } + void TypeLocWriter::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { if (TL.getNumProtocols()) { Record.AddSourceLocation(TL.getProtocolLAngleLoc()); @@ -669,6 +711,7 @@ void TypeLocWriter::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Record.AddSourceLocation(TL.getProtocolLoc(i)); } + void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { Record.AddSourceLocation(TL.getTypeofLoc()); Record.AddSourceLocation(TL.getLParenLoc()); @@ -1130,6 +1173,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(SUBMODULE_TEXTUAL_HEADER); RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); RECORD(SUBMODULE_INITIALIZERS); + RECORD(SUBMODULE_EXPORT_AS); // Comments Block. BLOCK(COMMENTS_BLOCK); @@ -1397,6 +1441,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, StringRef isysroot, const std::string &OutputFile) { using namespace llvm; + Stream.EnterSubblock(CONTROL_BLOCK_ID, 5); RecordData Record; @@ -1505,6 +1550,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, for (auto I : M.Signature) Record.push_back(I); + AddString(M.ModuleName, Record); AddPath(M.FileName, Record); } Stream.EmitRecord(IMPORTS, Record); @@ -1686,21 +1732,22 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, namespace { - /// \brief An input file. - struct InputFileEntry { - const FileEntry *File; - bool IsSystemFile; - bool IsTransient; - bool BufferOverridden; - bool IsTopLevelModuleMap; - }; +/// \brief An input file. +struct InputFileEntry { + const FileEntry *File; + bool IsSystemFile; + bool IsTransient; + bool BufferOverridden; + bool IsTopLevelModuleMap; +}; -} // end anonymous namespace +} // namespace void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts, bool Modules) { using namespace llvm; + Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); // Create input-file abbreviation. @@ -1877,7 +1924,7 @@ namespace { off_t Size; time_t ModTime; }; - typedef const key_type &key_type_ref; + using key_type_ref = const key_type &; using UnresolvedModule = llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>; @@ -1887,10 +1934,10 @@ namespace { ArrayRef<ModuleMap::KnownHeader> KnownHeaders; UnresolvedModule Unresolved; }; - typedef const data_type &data_type_ref; + using data_type_ref = const data_type &; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using hash_value_type = unsigned; + using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { // The hash is based only on size/time of the file, so that the reader can @@ -1899,9 +1946,10 @@ namespace { return llvm::hash_combine(key.Size, key.ModTime); } - std::pair<unsigned,unsigned> + std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { using namespace llvm::support; + endian::Writer<little> LE(Out); unsigned KeyLen = key.Filename.size() + 1 + 8 + 8; LE.write<uint16_t>(KeyLen); @@ -1917,6 +1965,7 @@ namespace { void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) { using namespace llvm::support; + endian::Writer<little> LE(Out); LE.write<uint64_t>(key.Size); KeyLen -= 8; @@ -1928,6 +1977,7 @@ namespace { void EmitData(raw_ostream &Out, key_type_ref key, data_type_ref Data, unsigned DataLen) { using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; @@ -1982,7 +2032,7 @@ namespace { const char *strings_end() const { return FrameworkStringData.end(); } }; -} // end anonymous namespace +} // namespace /// \brief Write the header search block for the list of files that /// @@ -2095,6 +2145,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { uint32_t BucketOffset; { using namespace llvm::support; + llvm::raw_svector_ostream Out(TableData); // Make sure that no bucket is at offset 0 endian::Writer<little>(Out).write<uint32_t>(0); @@ -2126,7 +2177,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, unsigned SLocBufferBlobCompressedAbbrv, unsigned SLocBufferBlobAbbrv) { - typedef ASTWriter::RecordData::value_type RecordDataType; + using RecordDataType = ASTWriter::RecordData::value_type; // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. @@ -2312,12 +2363,13 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Emit the needed file names. llvm::DenseMap<int, int> FilenameMap; + FilenameMap[-1] = -1; // For unspecified filenames. for (const auto &L : LineTable) { if (L.first.ID < 0) continue; for (auto &LE : L.second) { if (FilenameMap.insert(std::make_pair(LE.FilenameID, - FilenameMap.size())).second) + FilenameMap.size() - 1)).second) AddPath(LineTable.getFilename(LE.FilenameID), Record); } } @@ -2370,7 +2422,6 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, /// \brief Writes the block containing the serialized form of the /// preprocessor. -/// void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); if (PPRec) @@ -2387,6 +2438,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) { assert(!IsModule); + auto SkipInfo = PP.getPreambleSkipInfo(); + if (SkipInfo.hasValue()) { + Record.push_back(true); + AddSourceLocation(SkipInfo->HashTokenLoc, Record); + AddSourceLocation(SkipInfo->IfTokenLoc, Record); + Record.push_back(SkipInfo->FoundNonSkipPortion); + Record.push_back(SkipInfo->FoundElse); + AddSourceLocation(SkipInfo->ElseLoc, Record); + } else { + Record.push_back(false); + } for (const auto &Cond : PP.getPreambleConditionalStack()) { AddSourceLocation(Cond.IfLoc, Record); Record.push_back(Cond.WasSkipping); @@ -2715,6 +2777,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem @@ -2789,11 +2852,15 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXPORT_AS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + // Write the submodule metadata block. RecordData::value_type Record[] = { getNumberOfModules(WritingModule), - FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS, - (unsigned)WritingModule->Kind}; + FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS}; Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. @@ -2815,6 +2882,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { RecordData::value_type Record[] = {SUBMODULE_DEFINITION, ID, ParentID, + (RecordData::value_type)Mod->Kind, Mod->IsFramework, Mod->IsExplicit, Mod->IsSystem, @@ -2923,6 +2991,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { if (!Inits.empty()) Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits); + // Emit the name of the re-exported module, if any. + if (!Mod->ExportAsModule.empty()) { + RecordData::value_type Record[] = {SUBMODULE_EXPORT_AS}; + Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule); + } + // Queue up the submodules of this module. for (auto *M : Mod->submodules()) Q.push(M); @@ -3164,28 +3238,29 @@ class ASTMethodPoolTrait { ASTWriter &Writer; public: - typedef Selector key_type; - typedef key_type key_type_ref; + using key_type = Selector; + using key_type_ref = key_type; struct data_type { SelectorID ID; ObjCMethodList Instance, Factory; }; - typedef const data_type& data_type_ref; + using data_type_ref = const data_type &; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using hash_value_type = unsigned; + using offset_type = unsigned; - explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { } + explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) {} static hash_value_type ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } - std::pair<unsigned,unsigned> + std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream& Out, Selector Sel, data_type_ref Methods) { using namespace llvm::support; + endian::Writer<little> LE(Out); unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); LE.write<uint16_t>(KeyLen); @@ -3204,6 +3279,7 @@ public: void EmitKey(raw_ostream& Out, Selector Sel, unsigned) { using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); assert((Start >> 32) == 0 && "Selector key offset too large"); @@ -3220,6 +3296,7 @@ public: void EmitData(raw_ostream& Out, key_type_ref, data_type_ref Methods, unsigned DataLen) { using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; LE.write<uint32_t>(Methods.ID); @@ -3264,7 +3341,7 @@ public: } }; -} // end anonymous namespace +} // namespace /// \brief Write ObjC data: selectors and the method pool. /// @@ -3328,6 +3405,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { uint32_t BucketOffset; { using namespace llvm::support; + ASTMethodPoolTrait Trait(*this); llvm::raw_svector_ostream Out(MethodPool); // Make sure that no bucket is at offset 0 @@ -3372,6 +3450,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { /// \brief Write the selectors referenced in @selector expression into AST file. void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) { using namespace llvm; + if (SemaRef.ReferencedSelectors.empty()) return; @@ -3460,14 +3539,14 @@ class ASTIdentifierTableTrait { } public: - typedef IdentifierInfo* key_type; - typedef key_type key_type_ref; + using key_type = IdentifierInfo *; + using key_type_ref = key_type; - typedef IdentID data_type; - typedef data_type data_type_ref; + using data_type = IdentID; + using data_type_ref = data_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using hash_value_type = unsigned; + using offset_type = unsigned; ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule, @@ -3491,7 +3570,7 @@ public: return isInterestingIdentifier(II, 0); } - std::pair<unsigned,unsigned> + std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 @@ -3509,7 +3588,9 @@ public: DataLen += 4; } } + using namespace llvm::support; + endian::Writer<little> LE(Out); assert((uint16_t)DataLen == DataLen && (uint16_t)KeyLen == KeyLen); @@ -3538,6 +3619,7 @@ public: void EmitData(raw_ostream& Out, IdentifierInfo* II, IdentID ID, unsigned) { using namespace llvm::support; + endian::Writer<little> LE(Out); auto MacroOffset = Writer.getMacroDirectivesOffset(II); @@ -3581,7 +3663,7 @@ public: } }; -} // end anonymous namespace +} // namespace /// \brief Write the identifier table into the AST file. /// @@ -3639,6 +3721,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, uint32_t BucketOffset; { using namespace llvm::support; + llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 endian::Writer<little>(Out).write<uint32_t>(0); @@ -3694,17 +3777,17 @@ class ASTDeclContextNameLookupTrait { llvm::SmallVector<DeclID, 64> DeclIDs; public: - typedef DeclarationNameKey key_type; - typedef key_type key_type_ref; + using key_type = DeclarationNameKey; + using key_type_ref = key_type; /// A start and end index into DeclIDs, representing a sequence of decls. - typedef std::pair<unsigned, unsigned> data_type; - typedef const data_type& data_type_ref; + using data_type = std::pair<unsigned, unsigned>; + using data_type_ref = const data_type &; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + using hash_value_type = unsigned; + using offset_type = unsigned; - explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { } + explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) {} template<typename Coll> data_type getData(const Coll &Decls) { @@ -3736,6 +3819,7 @@ public: "have reference to loaded module file but no chain?"); using namespace llvm::support; + endian::Writer<little>(Out) .write<uint32_t>(Writer.getChain()->getModuleFileID(F)); } @@ -3744,6 +3828,7 @@ public: DeclarationNameKey Name, data_type_ref Lookup) { using namespace llvm::support; + endian::Writer<little> LE(Out); unsigned KeyLen = 1; switch (Name.getKind()) { @@ -3777,6 +3862,7 @@ public: void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { using namespace llvm::support; + endian::Writer<little> LE(Out); LE.write<uint8_t>(Name.getKind()); switch (Name.getKind()) { @@ -3808,6 +3894,7 @@ public: void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, unsigned DataLen) { using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) @@ -3816,7 +3903,7 @@ public: } }; -} // end anonymous namespace +} // namespace bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC) { @@ -4295,6 +4382,7 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) { for (const auto &StackEntry : SemaRef.PackStack.Stack) { Record.push_back(StackEntry.Value); AddSourceLocation(StackEntry.PragmaLocation, Record); + AddSourceLocation(StackEntry.PragmaPushLocation, Record); AddString(StackEntry.StackSlotLabel, Record); } Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record); @@ -4348,7 +4436,6 @@ void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) { Record.AddSourceRange(A->getRange()); #include "clang/Serialization/AttrPCHWrite.inc" - } } @@ -4778,7 +4865,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, // each of those modules were mapped into our own offset/ID space, so that // the reader can build the appropriate mapping to its own offset/ID space. // The map consists solely of a blob with the following format: - // *(module-name-len:i16 module-name:len*i8 + // *(module-kind:i8 + // module-name-len:i16 module-name:len*i8 // source-location-offset:i32 // identifier-id:i32 // preprocessed-entity-id:i32 @@ -4789,6 +4877,9 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, // c++-base-specifiers-id:i32 // type-id:i32) // + // module-kind is the ModuleKind enum value. If it is MK_PrebuiltModule or + // MK_ExplicitModule, then the module-name is the module name. Otherwise, + // it is the module file name. auto Abbrev = std::make_shared<BitCodeAbbrev>(); Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); @@ -4798,10 +4889,15 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, llvm::raw_svector_ostream Out(Buffer); for (ModuleFile &M : Chain->ModuleMgr) { using namespace llvm::support; + endian::Writer<little> LE(Out); - StringRef FileName = M.FileName; - LE.write<uint16_t>(FileName.size()); - Out.write(FileName.data(), FileName.size()); + LE.write<uint8_t>(static_cast<uint8_t>(M.Kind)); + StringRef Name = + M.Kind == MK_PrebuiltModule || M.Kind == MK_ExplicitModule + ? M.ModuleName + : M.FileName; + LE.write<uint16_t>(Name.size()); + Out.write(Name.data(), Name.size()); // Note: if a base ID was uint max, it would not be possible to load // another module after it or have more than one entity inside it. @@ -5039,9 +5135,15 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { case UPD_CXX_ADDED_FUNCTION_DEFINITION: break; - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { - const VarDecl *VD = cast<VarDecl>(D); + case UPD_CXX_POINT_OF_INSTANTIATION: + // FIXME: Do we need to also save the template specialization kind here? Record.AddSourceLocation(Update.getLoc()); + break; + + case UPD_CXX_ADDED_VAR_DEFINITION: { + const VarDecl *VD = cast<VarDecl>(D); + Record.push_back(VD->isInline()); + Record.push_back(VD->isInlineSpecified()); if (VD->getInit()) { Record.push_back(!VD->isInitKnownICE() ? 1 : (VD->isInitICE() ? 3 : 2)); @@ -5109,6 +5211,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { case UPD_CXX_RESOLVED_DTOR_DELETE: Record.AddDeclRef(Update.getDecl()); + Record.AddStmt(cast<CXXDestructorDecl>(D)->getOperatorDeleteThisArg()); break; case UPD_CXX_RESOLVED_EXCEPTION_SPEC: @@ -6136,7 +6239,8 @@ void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { } void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, - const FunctionDecl *Delete) { + const FunctionDecl *Delete, + Expr *ThisArg) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); assert(Delete && "Not given an operator delete"); @@ -6156,6 +6260,15 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } +void ASTWriter::VariableDefinitionInstantiated(const VarDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_VAR_DEFINITION)); +} + void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); @@ -6165,7 +6278,7 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } -void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { +void ASTWriter::InstantiationRequested(const ValueDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) @@ -6173,9 +6286,12 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { // Since the actual instantiation is delayed, this really means that we need // to update the instantiation location. - DeclUpdates[D].push_back( - DeclUpdate(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, - D->getMemberSpecializationInfo()->getPointOfInstantiation())); + SourceLocation POI; + if (auto *VD = dyn_cast<VarDecl>(D)) + POI = VD->getPointOfInstantiation(); + else + POI = cast<FunctionDecl>(D)->getPointOfInstantiation(); + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_POINT_OF_INSTANTIATION, POI)); } void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) { diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp index ec21ca2276c11..3dac3a48297af 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -612,6 +612,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { VisitFunctionDecl(D); + Record.push_back(D->IsCopyDeductionCandidate); Code = serialization::DECL_CXX_DEDUCTION_GUIDE; } @@ -849,17 +850,16 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing && - D->InitStorage.getPointer() == nullptr) { - Record.push_back(0); - } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { - Record.push_back(D->InitStorage.getInt() + 1); - Record.AddTypeRef( - QualType(static_cast<Type *>(D->InitStorage.getPointer()), 0)); - } else { - Record.push_back(D->InitStorage.getInt() + 1); - Record.AddStmt(static_cast<Expr *>(D->InitStorage.getPointer())); - } + + FieldDecl::InitStorageKind ISK = D->InitStorage.getInt(); + Record.push_back(ISK); + if (ISK == FieldDecl::ISK_CapturedVLAType) + Record.AddTypeRef(QualType(D->getCapturedVLAType(), 0)); + else if (ISK) + Record.AddStmt(D->getInClassInitializer()); + + Record.AddStmt(D->getBitWidth()); + if (!D->getDeclName()) Record.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D)); @@ -873,6 +873,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { !D->isModulePrivate() && !D->getBitWidth() && !D->hasInClassInitializer() && + !D->hasCapturedVLAType() && !D->hasExtInfo() && !ObjCIvarDecl::classofKind(D->getKind()) && !ObjCAtDefsFieldDecl::classofKind(D->getKind()) && @@ -928,6 +929,24 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { } else { Record.push_back(0); } + + if (D->getStorageDuration() == SD_Static) { + bool ModulesCodegen = false; + if (Writer.WritingModule && + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + !isa<VarTemplateSpecializationDecl>(D)) { + // When building a C++ Modules TS module interface unit, a strong + // definition in the module interface is provided by the compilation of + // that module interface unit, not by its users. (Inline variables are + // still emitted in module users.) + ModulesCodegen = + (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit && + Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); + } + Record.push_back(ModulesCodegen); + if (ModulesCodegen) + Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D)); + } enum { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization @@ -963,6 +982,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->isConstexpr() && !D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() && + D->getStorageDuration() != SD_Static && !D->getMemberSpecializationInfo()) AbbrevToUse = Writer.getDeclVarAbbrev(); @@ -1247,10 +1267,8 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); if (D->isCanonicalDecl()) { Record.push_back(D->size_overridden_methods()); - for (CXXMethodDecl::method_iterator - I = D->begin_overridden_methods(), E = D->end_overridden_methods(); - I != E; ++I) - Record.AddDeclRef(*I); + for (const CXXMethodDecl *MD : D->overridden_methods()) + Record.AddDeclRef(MD); } else { // We only need to record overridden methods once for the canonical decl. Record.push_back(0); @@ -1290,6 +1308,8 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); Record.AddDeclRef(D->getOperatorDelete()); + if (D->getOperatorDelete()) + Record.AddStmt(D->getOperatorDeleteThisArg()); Code = serialization::DECL_CXX_DESTRUCTOR; } @@ -1472,6 +1492,7 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl( Record.AddTemplateArgumentList(&D->getTemplateArgs()); Record.AddSourceLocation(D->getPointOfInstantiation()); Record.push_back(D->getSpecializationKind()); + Record.push_back(D->IsCompleteDefinition); Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { @@ -1697,6 +1718,7 @@ void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { Record.AddSourceLocation(D->getLocStart()); Record.AddStmt(D->getCombiner()); Record.AddStmt(D->getInitializer()); + Record.push_back(D->getInitializerKind()); Record.AddDeclRef(D->getPrevDeclInScope()); Code = serialization::DECL_OMP_DECLARE_REDUCTION; } @@ -1741,7 +1763,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable - Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth + Abv->Add(BitCodeAbbrevOp(0)); // InitStyle // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); @@ -1774,7 +1796,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable - Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth + Abv->Add(BitCodeAbbrevOp(0)); // InitStyle // ObjC Ivar Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize @@ -2235,15 +2257,24 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); bool ModulesCodegen = false; if (Writer->WritingModule && !FD->isDependentContext()) { - // Under -fmodules-codegen, codegen is performed for all defined functions. - // When building a C++ Modules TS module interface unit, a strong definition - // in the module interface is provided by the compilation of that module - // interface unit, not by its users. (Inline functions are still emitted - // in module users.) - ModulesCodegen = - Writer->Context->getLangOpts().ModulesCodegen || - (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit && - Writer->Context->GetGVALinkageForFunction(FD) == GVA_StrongExternal); + Optional<GVALinkage> Linkage; + if (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) { + // When building a C++ Modules TS module interface unit, a strong + // definition in the module interface is provided by the compilation of + // that module interface unit, not by its users. (Inline functions are + // still emitted in module users.) + Linkage = Writer->Context->GetGVALinkageForFunction(FD); + ModulesCodegen = *Linkage == GVA_StrongExternal; + } + if (Writer->Context->getLangOpts().ModulesCodegen) { + // Under -fmodules-codegen, codegen is performed for all non-internal, + // non-always_inline functions. + if (!FD->hasAttr<AlwaysInlineAttr>()) { + if (!Linkage) + Linkage = Writer->Context->GetGVALinkageForFunction(FD); + ModulesCodegen = *Linkage != GVA_Internal; + } + } } Record->push_back(ModulesCodegen); if (ModulesCodegen) diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp index 6971339663f09..c5f4495d2f013 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2001,6 +2001,27 @@ void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { Record.AddStmt(E); } +void OMPClauseWriter::VisitOMPInReductionClause(OMPInReductionClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); + Record.AddDeclarationNameInfo(C->getNameInfo()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *VE : C->privates()) + Record.AddStmt(VE); + for (auto *E : C->lhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->rhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->reduction_ops()) + Record.AddStmt(E); + for (auto *E : C->taskgroup_descriptors()) + Record.AddStmt(E); +} + void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); @@ -2081,6 +2102,7 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { } void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) { + VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getDevice()); Record.AddSourceLocation(C->getLParenLoc()); } @@ -2480,6 +2502,7 @@ void ASTStmtWriter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); + Record.AddStmt(D->getReductionRef()); Code = serialization::STMT_OMP_TASKGROUP_DIRECTIVE; } @@ -2545,6 +2568,7 @@ void ASTStmtWriter::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { void ASTStmtWriter::VisitOMPDistributeParallelForDirective( OMPDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; } @@ -2592,6 +2616,7 @@ void ASTStmtWriter::VisitOMPTeamsDistributeParallelForSimdDirective( void ASTStmtWriter::VisitOMPTeamsDistributeParallelForDirective( OMPTeamsDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; } @@ -2611,6 +2636,7 @@ void ASTStmtWriter::VisitOMPTargetTeamsDistributeDirective( void ASTStmtWriter::VisitOMPTargetTeamsDistributeParallelForDirective( OMPTargetTeamsDistributeParallelForDirective *D) { VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp index 6978e7e09774f..20c114297b999 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp @@ -619,6 +619,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++]}}}; + // Skip the module name (currently this is only used for prebuilt + // modules while here we are only dealing with cached). + Idx += Record[Idx] + 1; + // Retrieve the imported file name. unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp index 1dee4d0698616..b512fa452cc13 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp @@ -1,4 +1,4 @@ -//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +//===- ModuleManager.cpp - Module Manager ---------------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,24 +11,38 @@ // modules for the ASTReader. // //===----------------------------------------------------------------------===// + #include "clang/Serialization/ModuleManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/MemoryBufferCache.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/ModuleMap.h" #include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <memory> +#include <string> #include <system_error> -#ifndef NDEBUG -#include "llvm/Support/GraphWriter.h" -#endif - using namespace clang; using namespace serialization; -ModuleFile *ModuleManager::lookup(StringRef Name) const { +ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const { const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, /*cacheFailure=*/false); if (Entry) @@ -37,6 +51,14 @@ ModuleFile *ModuleManager::lookup(StringRef Name) const { return nullptr; } +ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const { + if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name)) + if (const FileEntry *File = Mod->getASTFile()) + return lookup(File); + + return nullptr; +} + ModuleFile *ModuleManager::lookup(const FileEntry *File) const { auto Known = Modules.find(File); if (Known == Modules.end()) @@ -200,7 +222,6 @@ void ModuleManager::removeModules( if (First == Last) return; - // Explicitly clear VisitOrder since we might not notice it is stale. VisitOrder.clear(); @@ -259,7 +280,6 @@ void ModuleManager::removeModules( void ModuleManager::addInMemoryBuffer(StringRef FileName, std::unique_ptr<llvm::MemoryBuffer> Buffer) { - const FileEntry *Entry = FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0); InMemoryBuffers[Entry] = std::move(Buffer); @@ -306,9 +326,10 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) { } ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, - const PCHContainerReader &PCHContainerRdr) + const PCHContainerReader &PCHContainerRdr, + const HeaderSearch& HeaderSearchInfo) : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr), - GlobalIndex(), FirstVisitState(nullptr) {} + HeaderSearchInfo(HeaderSearchInfo) {} ModuleManager::~ModuleManager() { delete FirstVisitState; } @@ -442,11 +463,12 @@ bool ModuleManager::lookupModuleFile(StringRef FileName, #ifndef NDEBUG namespace llvm { + template<> struct GraphTraits<ModuleManager> { - typedef ModuleFile *NodeRef; - typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; - typedef pointer_iterator<ModuleManager::ModuleConstIterator> nodes_iterator; + using NodeRef = ModuleFile *; + using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator; + using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>; static ChildIteratorType child_begin(NodeRef Node) { return Node->Imports.begin(); @@ -468,17 +490,16 @@ namespace llvm { template<> struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { explicit DOTGraphTraits(bool IsSimple = false) - : DefaultDOTGraphTraits(IsSimple) { } + : DefaultDOTGraphTraits(IsSimple) {} - static bool renderGraphFromBottomUp() { - return true; - } + static bool renderGraphFromBottomUp() { return true; } std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { return M->ModuleName; } }; -} + +} // namespace llvm void ModuleManager::viewGraph() { llvm::ViewGraph(*this, "Modules"); diff --git a/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h index fdbbb602b5371..44d1616a01104 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h +++ b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h @@ -1,4 +1,4 @@ -//===--- MultiOnDiskHashTable.h - Merged set of hash tables -----*- C++ -*-===// +//===- MultiOnDiskHashTable.h - Merged set of hash tables -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,6 +15,7 @@ // files. // //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H #define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H @@ -22,33 +23,43 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/OnDiskHashTable.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <vector> namespace clang { namespace serialization { -class ModuleFile; - /// \brief A collection of on-disk hash tables, merged when relevant for performance. template<typename Info> class MultiOnDiskHashTable { public: /// A handle to a file, used when overriding tables. - typedef typename Info::file_type file_type; + using file_type = typename Info::file_type; + /// A pointer to an on-disk representation of the hash table. - typedef const unsigned char *storage_type; + using storage_type = const unsigned char *; - typedef typename Info::external_key_type external_key_type; - typedef typename Info::internal_key_type internal_key_type; - typedef typename Info::data_type data_type; - typedef typename Info::data_type_builder data_type_builder; - typedef unsigned hash_value_type; + using external_key_type = typename Info::external_key_type; + using internal_key_type = typename Info::internal_key_type; + using data_type = typename Info::data_type; + using data_type_builder = typename Info::data_type_builder; + using hash_value_type = unsigned; private: + /// The generator is permitted to read our merged table. + template<typename ReaderInfo, typename WriterInfo> + friend class MultiOnDiskHashTableGenerator; + /// \brief A hash table stored on disk. struct OnDiskTable { - typedef llvm::OnDiskIterableChainedHashTable<Info> HashTable; + using HashTable = llvm::OnDiskIterableChainedHashTable<Info>; file_type File; HashTable Table; @@ -65,8 +76,8 @@ private: llvm::DenseMap<internal_key_type, data_type> Data; }; - typedef llvm::PointerUnion<OnDiskTable*, MergedTable*> Table; - typedef llvm::TinyPtrVector<void*> TableVector; + using Table = llvm::PointerUnion<OnDiskTable *, MergedTable *>; + using TableVector = llvm::TinyPtrVector<void *>; /// \brief The current set of on-disk and merged tables. /// We manually store the opaque value of the Table because TinyPtrVector @@ -80,14 +91,16 @@ private: llvm::TinyPtrVector<file_type> PendingOverrides; struct AsOnDiskTable { - typedef OnDiskTable *result_type; + using result_type = OnDiskTable *; + result_type operator()(void *P) const { return Table::getFromOpaqueValue(P).template get<OnDiskTable *>(); } }; - typedef llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable> - table_iterator; - typedef llvm::iterator_range<table_iterator> table_range; + + using table_iterator = + llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable>; + using table_range = llvm::iterator_range<table_iterator>; /// \brief The current set of on-disk tables. table_range tables() { @@ -160,17 +173,15 @@ private: Tables.push_back(Table(Merged).getOpaqueValue()); } - /// The generator is permitted to read our merged table. - template<typename ReaderInfo, typename WriterInfo> - friend class MultiOnDiskHashTableGenerator; - public: - MultiOnDiskHashTable() {} + MultiOnDiskHashTable() = default; + MultiOnDiskHashTable(MultiOnDiskHashTable &&O) : Tables(std::move(O.Tables)), PendingOverrides(std::move(O.PendingOverrides)) { O.Tables.clear(); } + MultiOnDiskHashTable &operator=(MultiOnDiskHashTable &&O) { if (&O == this) return *this; @@ -180,11 +191,13 @@ public: PendingOverrides = std::move(O.PendingOverrides); return *this; } + ~MultiOnDiskHashTable() { clear(); } /// \brief Add the table \p Data loaded from file \p File. void add(file_type File, storage_type Data, Info InfoObj = Info()) { using namespace llvm::support; + storage_type Ptr = Data; uint32_t BucketOffset = endian::readNext<uint32_t, little, unaligned>(Ptr); @@ -278,8 +291,8 @@ public: /// \brief Writer for the on-disk hash table. template<typename ReaderInfo, typename WriterInfo> class MultiOnDiskHashTableGenerator { - typedef MultiOnDiskHashTable<ReaderInfo> BaseTable; - typedef llvm::OnDiskChainedHashTableGenerator<WriterInfo> Generator; + using BaseTable = MultiOnDiskHashTable<ReaderInfo>; + using Generator = llvm::OnDiskChainedHashTableGenerator<WriterInfo>; Generator Gen; @@ -294,6 +307,7 @@ public: void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info, const BaseTable *Base) { using namespace llvm::support; + llvm::raw_svector_ostream OutStream(Out); // Write our header information. @@ -327,8 +341,7 @@ public: } }; -} // end namespace clang::serialization -} // end namespace clang - +} // namespace serialization +} // namespace clang -#endif +#endif // LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 848c2662019a1..b944f90539d42 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -259,6 +259,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, llvm::make_unique<BugReport>(*BT, os.str(), errorNode)); } +#ifndef NDEBUG LLVM_DUMP_METHOD void RegionRawOffsetV2::dump() const { dumpToStream(llvm::errs()); } @@ -266,7 +267,7 @@ LLVM_DUMP_METHOD void RegionRawOffsetV2::dump() const { void RegionRawOffsetV2::dumpToStream(raw_ostream &os) const { os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}'; } - +#endif // Lazily computes a value to be used by 'computeOffset'. If 'val' // is unknown or undefined, we lazily substitute '0'. Otherwise, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index d19630eeef778..c31f2794df6ab 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -26,15 +26,22 @@ using namespace ento; namespace { -class BlockInCriticalSectionChecker : public Checker<check::PostCall, - check::PreCall> { +class BlockInCriticalSectionChecker : public Checker<check::PostCall> { + + mutable IdentifierInfo *IILockGuard, *IIUniqueLock; CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn, PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn, MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock; + StringRef ClassLockGuard, ClassUniqueLock; + + mutable bool IdentifierInfoInitialized; + std::unique_ptr<BugType> BlockInCritSectionBugType; + void initIdentifierInfo(ASTContext &Ctx) const; + void reportBlockInCritSection(SymbolRef FileDescSym, const CallEvent &call, CheckerContext &C) const; @@ -46,13 +53,10 @@ public: bool isLockFunction(const CallEvent &Call) const; bool isUnlockFunction(const CallEvent &Call) const; - void checkPreCall(const CallEvent &Call, CheckerContext &C) const; - /// Process unlock. /// Process lock. /// Process blocking functions (sleep, getc, fgets, read, recv) void checkPostCall(const CallEvent &Call, CheckerContext &C) const; - }; } // end anonymous namespace @@ -60,7 +64,8 @@ public: REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned) BlockInCriticalSectionChecker::BlockInCriticalSectionChecker() - : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"), + : IILockGuard(nullptr), IIUniqueLock(nullptr), + LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"), FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"), PthreadLockFn("pthread_mutex_lock"), PthreadTryLockFn("pthread_mutex_trylock"), @@ -68,13 +73,29 @@ BlockInCriticalSectionChecker::BlockInCriticalSectionChecker() MtxLock("mtx_lock"), MtxTimedLock("mtx_timedlock"), MtxTryLock("mtx_trylock"), - MtxUnlock("mtx_unlock") { + MtxUnlock("mtx_unlock"), + ClassLockGuard("lock_guard"), + ClassUniqueLock("unique_lock"), + IdentifierInfoInitialized(false) { // Initialize the bug type. BlockInCritSectionBugType.reset( new BugType(this, "Call to blocking function in critical section", "Blocking Error")); } +void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const { + if (!IdentifierInfoInitialized) { + /* In case of checking C code, or when the corresponding headers are not + * included, we might end up query the identifier table every time when this + * function is called instead of early returning it. To avoid this, a bool + * variable (IdentifierInfoInitialized) is used and the function will be run + * only once. */ + IILockGuard = &Ctx.Idents.get(ClassLockGuard); + IIUniqueLock = &Ctx.Idents.get(ClassUniqueLock); + IdentifierInfoInitialized = true; + } +} + bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const { if (Call.isCalled(SleepFn) || Call.isCalled(GetcFn) @@ -87,6 +108,12 @@ bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) co } bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const { + if (const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { + auto IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier(); + if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock) + return true; + } + if (Call.isCalled(LockFn) || Call.isCalled(PthreadLockFn) || Call.isCalled(PthreadTryLockFn) @@ -99,6 +126,13 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const } bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const { + if (const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { + const auto *DRecordDecl = dyn_cast<CXXRecordDecl>(Dtor->getDecl()->getParent()); + auto IdentifierInfo = DRecordDecl->getIdentifier(); + if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock) + return true; + } + if (Call.isCalled(UnlockFn) || Call.isCalled(PthreadUnlockFn) || Call.isCalled(MtxUnlock)) { @@ -107,12 +141,10 @@ bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) cons return false; } -void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call, - CheckerContext &C) const { -} - void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { + initIdentifierInfo(C.getASTContext()); + if (!isBlockingFunction(Call) && !isLockFunction(Call) && !isUnlockFunction(Call)) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 77c24629d71e5..28ad7e9e5071d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -289,8 +289,8 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, if (!ER) return state; - assert(ER->getValueType() == C.getASTContext().CharTy && - "CheckLocation should only be called with char* ElementRegions"); + if (ER->getValueType() != C.getASTContext().CharTy) + return state; // Get the size of the array. const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); @@ -874,6 +874,8 @@ bool CStringChecker::IsFirstBufInBound(CheckerContext &C, if (!ER) return true; // cf top comment. + // FIXME: Does this crash when a non-standard definition + // of a library function is encountered? assert(ER->getValueType() == C.getASTContext().CharTy && "IsFirstBufInBound should only be called with char* ElementRegions"); @@ -1050,31 +1052,22 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, // If this is mempcpy, get the byte after the last byte copied and // bind the expr. if (IsMempcpy) { - loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>(); - - // Get the length to copy. - if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) { - // Get the byte after the last byte copied. - SValBuilder &SvalBuilder = C.getSValBuilder(); - ASTContext &Ctx = SvalBuilder.getContext(); - QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); - loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal, - CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>(); - SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, - DestRegCharVal, - *lenValNonLoc, - Dest->getType()); - - // The byte after the last byte copied is the return value. - state = state->BindExpr(CE, LCtx, lastElement); - } else { - // If we don't know how much we copied, we can at least - // conjure a return value for later. - SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, + // Get the byte after the last byte copied. + SValBuilder &SvalBuilder = C.getSValBuilder(); + ASTContext &Ctx = SvalBuilder.getContext(); + QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); + SVal DestRegCharVal = + SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType()); + SVal lastElement = C.getSValBuilder().evalBinOp( + state, BO_Add, DestRegCharVal, sizeVal, Dest->getType()); + // If we don't know how much we copied, we can at least + // conjure a return value for later. + if (lastElement.isUnknown()) + lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); - state = state->BindExpr(CE, LCtx, result); - } + // The byte after the last byte copied is the return value. + state = state->BindExpr(CE, LCtx, lastElement); } else { // All other copies return the destination buffer. // (Well, bcopy() has a void return type, but this won't hurt.) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 391b843ff3dbe..4b5e97b69295a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -16,7 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TypeTraits.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 07285d27ed9e1..20a46843e23e2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -179,7 +179,7 @@ bool CallAndMessageChecker::uninitRefOrPointer( if (const MemRegion *SValMemRegion = V.getAsRegion()) { const ProgramStateRef State = C.getState(); - const SVal PSV = State->getSVal(SValMemRegion); + const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy); if (PSV.isUndef()) { if (ExplodedNode *N = C.generateErrorNode()) { LazyInit_BT(BD, BT); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 60f16188bcf89..6dbacad7f2eab 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -13,7 +13,7 @@ #include "ClangSACheckers.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -32,7 +32,6 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) { T.getOS() == llvm::Triple::FreeBSD || T.getOS() == llvm::Triple::NetBSD || T.getOS() == llvm::Triple::OpenBSD || - T.getOS() == llvm::Triple::Bitrig || T.getOS() == llvm::Triple::DragonFly; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp index 83955c586b688..ee517ed977700 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp @@ -64,7 +64,7 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU, // the CloneDetector. The only thing left to do is to report the found clones. int MinComplexity = Mgr.getAnalyzerOptions().getOptionAsInteger( - "MinimumCloneComplexity", 10, this); + "MinimumCloneComplexity", 50, this); assert(MinComplexity >= 0); bool ReportSuspiciousClones = Mgr.getAnalyzerOptions().getBooleanOption( @@ -81,11 +81,11 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU, // because reportSuspiciousClones() wants to search them for errors. std::vector<CloneDetector::CloneGroup> AllCloneGroups; - Detector.findClones(AllCloneGroups, - FilenamePatternConstraint(IgnoredFilesPattern), - RecursiveCloneTypeIIConstraint(), - MinComplexityConstraint(MinComplexity), - MinGroupSizeConstraint(2), OnlyLargestCloneConstraint()); + Detector.findClones( + AllCloneGroups, FilenamePatternConstraint(IgnoredFilesPattern), + RecursiveCloneTypeIIHashConstraint(), MinGroupSizeConstraint(2), + MinComplexityConstraint(MinComplexity), + RecursiveCloneTypeIIVerifyConstraint(), OnlyLargestCloneConstraint()); if (ReportSuspiciousClones) reportSuspiciousClones(BR, Mgr, AllCloneGroups); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp index ea894c81011c9..17ec2c288777b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp @@ -123,57 +123,6 @@ void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C, C.emitReport(std::move(R)); } -// Is E value greater or equal than Val? -static bool isGreaterEqual(CheckerContext &C, const Expr *E, - unsigned long long Val) { - ProgramStateRef State = C.getState(); - SVal EVal = C.getSVal(E); - if (EVal.isUnknownOrUndef()) - return false; - if (!EVal.getAs<NonLoc>() && EVal.getAs<Loc>()) { - ProgramStateManager &Mgr = C.getStateManager(); - EVal = - Mgr.getStoreManager().getBinding(State->getStore(), EVal.castAs<Loc>()); - } - if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>()) - return false; - - SValBuilder &Bldr = C.getSValBuilder(); - DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy); - - // Is DefinedEVal greater or equal with V? - SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType()); - if (GE.isUnknownOrUndef()) - return false; - ConstraintManager &CM = C.getConstraintManager(); - ProgramStateRef StGE, StLT; - std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>()); - return StGE && !StLT; -} - -// Is E value negative? -static bool isNegative(CheckerContext &C, const Expr *E) { - ProgramStateRef State = C.getState(); - SVal EVal = State->getSVal(E, C.getLocationContext()); - if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>()) - return false; - DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>(); - - SValBuilder &Bldr = C.getSValBuilder(); - DefinedSVal V = Bldr.makeIntVal(0, false); - - SVal LT = - Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType()); - - // Is E value greater than MaxVal? - ConstraintManager &CM = C.getConstraintManager(); - ProgramStateRef StNegative, StPositive; - std::tie(StNegative, StPositive) = - CM.assumeDual(State, LT.castAs<DefinedSVal>()); - - return StNegative && !StPositive; -} - bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType, CheckerContext &C) const { @@ -195,18 +144,18 @@ bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast, return false; unsigned long long MaxVal = 1ULL << W; - return isGreaterEqual(C, Cast->getSubExpr(), MaxVal); + return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal); } bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast, - CheckerContext &C) const { + CheckerContext &C) const { QualType CastType = Cast->getType(); QualType SubType = Cast->IgnoreParenImpCasts()->getType(); if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType()) return false; - return isNegative(C, Cast->getSubExpr()); + return C.isNegative(Cast->getSubExpr()); } void ento::registerConversionChecker(CheckerManager &mgr) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 2eef1688d4c4b..810a33ed404db 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -16,7 +16,6 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CallGraph.h" #include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -213,35 +212,3 @@ void ento::registerExplodedGraphViewer(CheckerManager &mgr) { mgr.registerChecker<ExplodedGraphViewer>(); } -//===----------------------------------------------------------------------===// -// DumpBugHash -//===----------------------------------------------------------------------===// - -namespace { -class BugHashDumper : public Checker<check::PostStmt<Stmt>> { -public: - mutable std::unique_ptr<BugType> BT; - - void checkPostStmt(const Stmt *S, CheckerContext &C) const { - if (!BT) - BT.reset(new BugType(this, "Dump hash components", "debug")); - - ExplodedNode *N = C.generateNonFatalErrorNode(); - if (!N) - return; - - const LangOptions &Opts = C.getLangOpts(); - const SourceManager &SM = C.getSourceManager(); - FullSourceLoc FL(S->getLocStart(), SM); - std::string HashContent = - GetIssueString(SM, FL, getCheckName().getName(), BT->getCategory(), - C.getLocationContext()->getDecl(), Opts); - - C.emitReport(llvm::make_unique<BugReport>(*BT, HashContent, N)); - } -}; -} - -void ento::registerBugHashDumper(CheckerManager &mgr) { - mgr.registerChecker<BugHashDumper>(); -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp new file mode 100644 index 0000000000000..e04e2ab2c3202 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp @@ -0,0 +1,153 @@ +//===-- DeleteWithNonVirtualDtorChecker.cpp -----------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for the OOP52-CPP CERT rule: Do not delete a polymorphic +// object without a virtual destructor. +// +// Diagnostic flags -Wnon-virtual-dtor and -Wdelete-non-virtual-dtor report if +// an object with a virtual function but a non-virtual destructor exists or is +// deleted, respectively. +// +// This check exceeds them by comparing the dynamic and static types of the +// object at the point of destruction and only warns if it happens through a +// pointer to a base type without a virtual destructor. The check places a note +// at the last point where the conversion from derived to base happened. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" + +using namespace clang; +using namespace ento; + +namespace { +class DeleteWithNonVirtualDtorChecker + : public Checker<check::PreStmt<CXXDeleteExpr>> { + mutable std::unique_ptr<BugType> BT; + + class DeleteBugVisitor : public BugReporterVisitorImpl<DeleteBugVisitor> { + public: + DeleteBugVisitor() : Satisfied(false) {} + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int X = 0; + ID.AddPointer(&X); + } + std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; + + private: + bool Satisfied; + }; + +public: + void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; +}; +} // end anonymous namespace + +void DeleteWithNonVirtualDtorChecker::checkPreStmt(const CXXDeleteExpr *DE, + CheckerContext &C) const { + const Expr *DeletedObj = DE->getArgument(); + const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion(); + if (!MR) + return; + + const auto *BaseClassRegion = MR->getAs<TypedValueRegion>(); + const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>(); + if (!BaseClassRegion || !DerivedClassRegion) + return; + + const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl(); + const auto *DerivedClass = + DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl(); + if (!BaseClass || !DerivedClass) + return; + + if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition()) + return; + + if (BaseClass->getDestructor()->isVirtual()) + return; + + if (!DerivedClass->isDerivedFrom(BaseClass)) + return; + + if (!BT) + BT.reset(new BugType(this, + "Destruction of a polymorphic object with no " + "virtual destructor", + "Logic error")); + + ExplodedNode *N = C.generateNonFatalErrorNode(); + auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N); + + // Mark region of problematic base class for later use in the BugVisitor. + R->markInteresting(BaseClassRegion); + R->addVisitor(llvm::make_unique<DeleteBugVisitor>()); + C.emitReport(std::move(R)); +} + +std::shared_ptr<PathDiagnosticPiece> +DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode( + const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, + BugReport &BR) { + // Stop traversal after the first conversion was found on a path. + if (Satisfied) + return nullptr; + + ProgramStateRef State = N->getState(); + const LocationContext *LC = N->getLocationContext(); + const Stmt *S = PathDiagnosticLocation::getStmt(N); + if (!S) + return nullptr; + + const auto *CastE = dyn_cast<CastExpr>(S); + if (!CastE) + return nullptr; + + // Only interested in DerivedToBase implicit casts. + // Explicit casts can have different CastKinds. + if (const auto *ImplCastE = dyn_cast<ImplicitCastExpr>(CastE)) { + if (ImplCastE->getCastKind() != CK_DerivedToBase) + return nullptr; + } + + // Region associated with the current cast expression. + const MemRegion *M = State->getSVal(CastE, LC).getAsRegion(); + if (!M) + return nullptr; + + // Check if target region was marked as problematic previously. + if (!BR.isInteresting(M)) + return nullptr; + + // Stop traversal on this path. + Satisfied = true; + + SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + OS << "Conversion from derived to base happened here"; + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), + N->getLocationContext()); + return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true, + nullptr); +} + +void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) { + mgr.registerChecker<DeleteWithNonVirtualDtorChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 0891ea85a7148..23b43759a34ba 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -546,8 +546,6 @@ void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); - // TODO: erase tracked information when there is a cast to unrelated type - // and everything is unspecialized statically. if (OrigObjectPtrType->isUnspecialized() && DestObjectPtrType->isUnspecialized()) return; @@ -556,29 +554,31 @@ void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, if (!Sym) return; - // Check which assignments are legal. - bool OrigToDest = - ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); - bool DestToOrig = - ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); const ObjCObjectPointerType *const *TrackedType = State->get<MostSpecializedTypeArgsMap>(Sym); - // Downcasts and upcasts handled in an uniform way regardless of being - // explicit. Explicit casts however can happen between mismatched types. - if (isa<ExplicitCastExpr>(CE) && !OrigToDest && !DestToOrig) { - // Mismatched types. If the DestType specialized, store it. Forget the - // tracked type otherwise. - if (DestObjectPtrType->isSpecialized()) { - State = State->set<MostSpecializedTypeArgsMap>(Sym, DestObjectPtrType); - C.addTransition(State, AfterTypeProp); - } else if (TrackedType) { + if (isa<ExplicitCastExpr>(CE)) { + // Treat explicit casts as an indication from the programmer that the + // Objective-C type system is not rich enough to express the needed + // invariant. In such cases, forget any existing information inferred + // about the type arguments. We don't assume the casted-to specialized + // type here because the invariant the programmer specifies in the cast + // may only hold at this particular program point and not later ones. + // We don't want a suppressing cast to require a cascade of casts down the + // line. + if (TrackedType) { State = State->remove<MostSpecializedTypeArgsMap>(Sym); C.addTransition(State, AfterTypeProp); } return; } + // Check which assignments are legal. + bool OrigToDest = + ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); + bool DestToOrig = + ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); + // The tracked type should be the sub or super class of the static destination // type. When an (implicit) upcast or a downcast happens according to static // types, and there is no subtyping relationship between the tracked and the diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 32040e71163dd..0005ec470d203 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -8,10 +8,11 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Checkers/SValExplainer.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Checkers/SValExplainer.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ScopedPrinter.h" @@ -41,6 +42,7 @@ class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols, void analyzerExplain(const CallExpr *CE, CheckerContext &C) const; void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const; void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const; + void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const; typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, CheckerContext &C) const; @@ -79,6 +81,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, &ExprInspectionChecker::analyzerPrintState) .Case("clang_analyzer_numTimesReached", &ExprInspectionChecker::analyzerNumTimesReached) + .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump) .Default(nullptr); if (!Handler) @@ -272,6 +275,7 @@ void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, reportBug(llvm::to_string(NumTimesReached), BR, N); } + ReachedStats.clear(); } void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, @@ -279,7 +283,18 @@ void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, LLVM_BUILTIN_TRAP; } +void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE, + CheckerContext &C) const { + const LangOptions &Opts = C.getLangOpts(); + const SourceManager &SM = C.getSourceManager(); + FullSourceLoc FL(CE->getArg(0)->getLocStart(), SM); + std::string HashContent = + GetIssueString(SM, FL, getCheckName().getName(), "Category", + C.getLocationContext()->getDecl(), Opts); + + reportBug(HashContent, C); +} + void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker<ExprInspectionChecker>(); } - diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 883c6a663291d..43966656cd8d0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -466,7 +466,7 @@ bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{ } Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, - const Expr* Arg) { + const Expr *Arg) { ProgramStateRef State = C.getState(); SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext()); if (AddrVal.isUnknownOrUndef()) @@ -476,9 +476,18 @@ Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, if (!AddrLoc) return None; - const PointerType *ArgTy = - dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr()); - return State->getSVal(*AddrLoc, ArgTy ? ArgTy->getPointeeType(): QualType()); + QualType ArgTy = Arg->getType().getCanonicalType(); + if (!ArgTy->isPointerType()) + return None; + + QualType ValTy = ArgTy->getPointeeType(); + + // Do not dereference void pointers. Treat them as byte pointers instead. + // FIXME: we might want to consider more than just the first byte. + if (ValTy->isVoidType()) + ValTy = C.getASTContext().CharTy; + + return State->getSVal(*AddrLoc, ValTy); } ProgramStateRef diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index 0c3bff5b63b8f..cf57b8dca0638 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -255,7 +255,10 @@ void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) { PathDiagnosticLocation ELoc = PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); StringRef Message; - if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) + if (Op == BO_Cmp) + Message = "comparison of identical expressions always evaluates to " + "'equal'"; + else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) Message = "comparison of identical expressions always evaluates to true"; else Message = "comparison of identical expressions always evaluates to false"; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp index decc552e1213e..497978f078155 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp @@ -56,8 +56,11 @@ public: ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, const CallEvent *Call) const; + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const override; private: + enum MisuseKind {MK_FunCall, MK_Copy, MK_Move}; class MovedBugVisitor : public BugReporterVisitorImpl<MovedBugVisitor> { public: MovedBugVisitor(const MemRegion *R) : Region(R), Found(false) {} @@ -81,7 +84,7 @@ private: mutable std::unique_ptr<BugType> BT; ExplodedNode *reportBug(const MemRegion *Region, const CallEvent &Call, - CheckerContext &C, bool isCopy) const; + CheckerContext &C, MisuseKind MK) const; bool isInMoveSafeContext(const LocationContext *LC) const; bool isStateResetMethod(const CXXMethodDecl *MethodDec) const; bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const; @@ -177,7 +180,7 @@ const ExplodedNode *MisusedMovedObjectChecker::getMoveLocation( ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region, const CallEvent &Call, CheckerContext &C, - bool isCopy = false) const { + MisuseKind MK) const { if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset(new BugType(this, "Usage of a 'moved-from' object", @@ -193,10 +196,17 @@ ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region, // Creating the error message. std::string ErrorMessage; - if (isCopy) - ErrorMessage = "Copying a 'moved-from' object"; - else - ErrorMessage = "Method call on a 'moved-from' object"; + switch(MK) { + case MK_FunCall: + ErrorMessage = "Method call on a 'moved-from' object"; + break; + case MK_Copy: + ErrorMessage = "Copying a 'moved-from' object"; + break; + case MK_Move: + ErrorMessage = "Moving a 'moved-from' object"; + break; + } if (const auto DecReg = Region->getAs<DeclRegion>()) { const auto *RegionDecl = dyn_cast<NamedDecl>(DecReg->getDecl()); ErrorMessage += " '" + RegionDecl->getNameAsString() + "'"; @@ -350,7 +360,7 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); ExplodedNode *N = nullptr; - // Remove the MemRegions from the map on which a ctor/dtor call or assignement + // Remove the MemRegions from the map on which a ctor/dtor call or assignment // happened. // Checking constructor calls. @@ -363,7 +373,10 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call, const RegionState *ArgState = State->get<TrackedRegionMap>(ArgRegion); if (ArgState && ArgState->isMoved()) { if (!isInMoveSafeContext(LC)) { - N = reportBug(ArgRegion, Call, C, /*isCopy=*/true); + if(CtorDec->isMoveConstructor()) + N = reportBug(ArgRegion, Call, C, MK_Move); + else + N = reportBug(ArgRegion, Call, C, MK_Copy); State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getReported()); } @@ -378,8 +391,11 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call, return; // In case of destructor call we do not track the object anymore. const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) + return; + if (dyn_cast_or_null<CXXDestructorDecl>(Call.getDecl())) { - State = removeFromState(State, IC->getCXXThisVal().getAsRegion()); + State = removeFromState(State, ThisRegion); C.addTransition(State); return; } @@ -400,7 +416,10 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call, State->get<TrackedRegionMap>(IC->getArgSVal(0).getAsRegion()); if (ArgState && ArgState->isMoved() && !isInMoveSafeContext(LC)) { const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion(); - N = reportBug(ArgRegion, Call, C, /*isCopy=*/true); + if(MethodDecl->isMoveAssignmentOperator()) + N = reportBug(ArgRegion, Call, C, MK_Move); + else + N = reportBug(ArgRegion, Call, C, MK_Copy); State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getReported()); } @@ -410,28 +429,35 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call, } // The remaining part is check only for method call on a moved-from object. + + // We want to investigate the whole object, not only sub-object of a parent + // class in which the encountered method defined. + while (const CXXBaseObjectRegion *BR = + dyn_cast<CXXBaseObjectRegion>(ThisRegion)) + ThisRegion = BR->getSuperRegion(); + if (isMoveSafeMethod(MethodDecl)) return; if (isStateResetMethod(MethodDecl)) { - State = State->remove<TrackedRegionMap>(ThisRegion); + State = removeFromState(State, ThisRegion); C.addTransition(State); return; } - // If it is already reported then we dont report the bug again. + // If it is already reported then we don't report the bug again. const RegionState *ThisState = State->get<TrackedRegionMap>(ThisRegion); if (!(ThisState && ThisState->isMoved())) return; - // Dont report it in case if any base region is already reported + // Don't report it in case if any base region is already reported if (isAnyBaseRegionReported(State, ThisRegion)) return; if (isInMoveSafeContext(LC)) return; - N = reportBug(ThisRegion, Call, C); + N = reportBug(ThisRegion, Call, C, MK_FunCall); State = State->set<TrackedRegionMap>(ThisRegion, RegionState::getReported()); C.addTransition(State, N); } @@ -476,6 +502,25 @@ ProgramStateRef MisusedMovedObjectChecker::checkRegionChanges( return State; } +void MisusedMovedObjectChecker::printState(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep) const { + + TrackedRegionMapTy RS = State->get<TrackedRegionMap>(); + + if (!RS.isEmpty()) { + Out << Sep << "Moved-from objects :" << NL; + for (auto I: RS) { + I.first->dumpToStream(Out); + if (I.second.isMoved()) + Out << ": moved"; + else + Out << ": moved and reported"; + Out << NL; + } + } +} void ento::registerMisusedMovedObjectChecker(CheckerManager &mgr) { mgr.registerChecker<MisusedMovedObjectChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp new file mode 100644 index 0000000000000..0b4ecb41d20f3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp @@ -0,0 +1,140 @@ +//==- NonnullGlobalConstantsChecker.cpp ---------------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker adds an assumption that constant globals of certain types* are +// non-null, as otherwise they generally do not convey any useful information. +// The assumption is useful, as many framework use e. g. global const strings, +// and the analyzer might not be able to infer the global value if the +// definition is in a separate translation unit. +// The following types (and their typedef aliases) are considered to be +// non-null: +// - `char* const` +// - `const CFStringRef` from CoreFoundation +// - `NSString* const` from Foundation +// - `CFBooleanRef` from Foundation +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" + +using namespace clang; +using namespace ento; + +namespace { + +class NonnullGlobalConstantsChecker : public Checker<check::Location> { + mutable IdentifierInfo *NSStringII = nullptr; + mutable IdentifierInfo *CFStringRefII = nullptr; + mutable IdentifierInfo *CFBooleanRefII = nullptr; + +public: + NonnullGlobalConstantsChecker() {} + + void checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const; + +private: + void initIdentifierInfo(ASTContext &Ctx) const; + + bool isGlobalConstString(SVal V) const; + + bool isNonnullType(QualType Ty) const; +}; + +} // namespace + +/// Lazily initialize cache for required identifier informations. +void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const { + if (NSStringII) + return; + + NSStringII = &Ctx.Idents.get("NSString"); + CFStringRefII = &Ctx.Idents.get("CFStringRef"); + CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef"); +} + +/// Add an assumption that const string-like globals are non-null. +void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad, + const Stmt *S, + CheckerContext &C) const { + initIdentifierInfo(C.getASTContext()); + if (!isLoad || !location.isValid()) + return; + + ProgramStateRef State = C.getState(); + SVal V = State->getSVal(location.castAs<Loc>()); + + if (isGlobalConstString(location)) { + Optional<DefinedOrUnknownSVal> Constr = V.getAs<DefinedOrUnknownSVal>(); + + if (Constr) { + + // Assume that the variable is non-null. + ProgramStateRef OutputState = State->assume(*Constr, true); + C.addTransition(OutputState); + } + } +} + +/// \param V loaded lvalue. +/// \return whether {@code val} is a string-like const global. +bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const { + Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>(); + if (!RegionVal) + return false; + auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion()); + if (!Region) + return false; + const VarDecl *Decl = Region->getDecl(); + + if (!Decl->hasGlobalStorage()) + return false; + + QualType Ty = Decl->getType(); + bool HasConst = Ty.isConstQualified(); + if (isNonnullType(Ty) && HasConst) + return true; + + // Look through the typedefs. + while (auto *T = dyn_cast<TypedefType>(Ty)) { + Ty = T->getDecl()->getUnderlyingType(); + + // It is sufficient for any intermediate typedef + // to be classified const. + HasConst = HasConst || Ty.isConstQualified(); + if (isNonnullType(Ty) && HasConst) + return true; + } + return false; +} + +/// \return whether {@code type} is extremely unlikely to be null +bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const { + + if (Ty->isPointerType() && Ty->getPointeeType()->isCharType()) + return true; + + if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) { + return T->getInterfaceDecl() && + T->getInterfaceDecl()->getIdentifier() == NSStringII; + } else if (auto *T = dyn_cast<TypedefType>(Ty)) { + IdentifierInfo* II = T->getDecl()->getIdentifier(); + return II == CFStringRefII || II == CFBooleanRefII; + } + return false; +} + +void ento::registerNonnullGlobalConstantsChecker(CheckerManager &Mgr) { + Mgr.registerChecker<NonnullGlobalConstantsChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index b10ec848ee461..e4737fcee7fb5 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/Checker.h" diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp index 075ff09dcbfac..69b19a7859381 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp @@ -107,8 +107,6 @@ void ObjCSuperDeallocChecker::checkPreObjCMessage(const ObjCMethodCall &M, } reportUseAfterDealloc(ReceiverSymbol, Desc, M.getOriginExpr(), C); - - return; } void ObjCSuperDeallocChecker::checkPreCall(const CallEvent &Call, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 0e3a649e88f78..dab29be1c8fb1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -81,6 +81,8 @@ class PthreadLockChecker public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const override; void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const; @@ -184,6 +186,39 @@ ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex( return state; } +void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + LockMapTy LM = State->get<LockMap>(); + if (!LM.isEmpty()) { + Out << Sep << "Mutex states:" << NL; + for (auto I : LM) { + I.first->dumpToStream(Out); + if (I.second.isLocked()) + Out << ": locked"; + else if (I.second.isUnlocked()) + Out << ": unlocked"; + else if (I.second.isDestroyed()) + Out << ": destroyed"; + else if (I.second.isUntouchedAndPossiblyDestroyed()) + Out << ": not tracked, possibly destroyed"; + else if (I.second.isUnlockedAndPossiblyDestroyed()) + Out << ": unlocked, possibly destroyed"; + Out << NL; + } + } + + LockSetTy LS = State->get<LockSet>(); + if (!LS.isEmpty()) { + Out << Sep << "Mutex lock order:" << NL; + for (auto I: LS) { + I->dumpToStream(Out); + Out << NL; + } + } + + // TODO: Dump destroyed mutex symbols? +} + void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 21ccf21515b3a..e47494a3e90b3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -462,6 +462,7 @@ private: ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; } friend class RetainSummaryManager; + friend class RetainCountChecker; }; } // end anonymous namespace @@ -1061,6 +1062,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // Inspect the result type. QualType RetTy = FT->getReturnType(); + std::string RetTyName = RetTy.getAsString(); // FIXME: This should all be refactored into a chain of "summary lookup" // filters. @@ -1080,12 +1082,14 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { AllowAnnotations = false; } else if (FName == "CFPlugInInstanceCreate") { S = getPersistentSummary(RetEffect::MakeNoRet()); - } else if (FName == "IOBSDNameMatching" || + } else if (FName == "IORegistryEntrySearchCFProperty" + || (RetTyName == "CFMutableDictionaryRef" && ( + FName == "IOBSDNameMatching" || FName == "IOServiceMatching" || FName == "IOServiceNameMatching" || - FName == "IORegistryEntrySearchCFProperty" || FName == "IORegistryEntryIDMatching" || - FName == "IOOpenFirmwarePathMatching") { + FName == "IOOpenFirmwarePathMatching" + ))) { // Part of <rdar://problem/6961230>. (IOKit) // This should be addressed using a API table. S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF), @@ -1166,6 +1170,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { if (cocoa::isRefType(RetTy, "CF", FName)) { if (isRetain(FD, FName)) { S = getUnarySummary(FT, cfretain); + // CFRetain isn't supposed to be annotated. However, this may as well + // be a user-made "safe" CFRetain function that is incorrectly + // annotated as cf_returns_retained due to lack of better options. + // We want to ignore such annotation. + AllowAnnotations = false; } else if (isAutorelease(FD, FName)) { S = getUnarySummary(FT, cfautorelease); // The headers use cf_consumed, but we can fully model CFAutorelease @@ -1192,10 +1201,10 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { break; } - // For the Disk Arbitration API (DiskArbitration/DADisk.h) - if (cocoa::isRefType(RetTy, "DADisk") || - cocoa::isRefType(RetTy, "DADissenter") || - cocoa::isRefType(RetTy, "DASessionRef")) { + // For all other CF-style types, use the Create/Get + // rule for summaries but don't support Retain functions + // with framework-specific prefixes. + if (coreFoundation::isCFObjectRef(RetTy)) { S = getCFCreateGetRuleSummary(FD); break; } @@ -1210,7 +1219,8 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // Check for release functions, the only kind of functions that we care // about that don't return a pointer type. - if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) { + if (FName.size() >= 2 && + FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) { // Test for 'CGCF'. FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); @@ -1319,6 +1329,13 @@ static bool isTrustedReferenceCountImplementation(const FunctionDecl *FD) { return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); } +static bool isGeneralizedObjectRef(QualType Ty) { + if (Ty.getAsString().substr(0, 4) == "isl_") + return true; + else + return false; +} + //===----------------------------------------------------------------------===// // Summary creation for Selectors. //===----------------------------------------------------------------------===// @@ -1340,6 +1357,8 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy, if (D->hasAttr<CFReturnsRetainedAttr>()) return RetEffect::MakeOwned(RetEffect::CF); + else if (hasRCAnnotation(D, "rc_ownership_returns_retained")) + return RetEffect::MakeOwned(RetEffect::Generalized); if (D->hasAttr<CFReturnsNotRetainedAttr>()) return RetEffect::MakeNotOwned(RetEffect::CF); @@ -1363,9 +1382,11 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, const ParmVarDecl *pd = *pi; if (pd->hasAttr<NSConsumedAttr>()) Template->addArg(AF, parm_idx, DecRefMsg); - else if (pd->hasAttr<CFConsumedAttr>()) + else if (pd->hasAttr<CFConsumedAttr>() || + hasRCAnnotation(pd, "rc_ownership_consumed")) Template->addArg(AF, parm_idx, DecRef); - else if (pd->hasAttr<CFReturnsRetainedAttr>()) { + else if (pd->hasAttr<CFReturnsRetainedAttr>() || + hasRCAnnotation(pd, "rc_ownership_returns_retained")) { QualType PointeeTy = pd->getType()->getPointeeType(); if (!PointeeTy.isNull()) if (coreFoundation::isCFObjectRef(PointeeTy)) @@ -1844,6 +1865,15 @@ namespace { class CFRefLeakReport : public CFRefReport { const MemRegion* AllocBinding; + const Stmt *AllocStmt; + + // Finds the function declaration where a leak warning for the parameter 'sym' should be raised. + void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym); + // Finds the location where a leak warning for 'sym' should be raised. + void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym); + // Produces description of a leak warning which is printed on the console. + void createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine); + public: CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, @@ -1999,17 +2029,15 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, } if (CurrV.getObjKind() == RetEffect::CF) { - if (Sym->getType().isNull()) { - os << " returns a Core Foundation object with a "; - } else { - os << " returns a Core Foundation object of type " - << Sym->getType().getAsString() << " with a "; - } - } - else { + os << " returns a Core Foundation object of type " + << Sym->getType().getAsString() << " with a "; + } else if (CurrV.getObjKind() == RetEffect::Generalized) { + os << " returns an object of type " << Sym->getType().getAsString() + << " with a "; + } else { assert (CurrV.getObjKind() == RetEffect::ObjC); QualType T = Sym->getType(); - if (T.isNull() || !isa<ObjCObjectPointerType>(T)) { + if (!isa<ObjCObjectPointerType>(T)) { os << " returns an Objective-C object with a "; } else { const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T); @@ -2425,13 +2453,25 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, return llvm::make_unique<PathDiagnosticEventPiece>(L, os.str()); } -CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, - bool GCEnabled, const SummaryLogTy &Log, - ExplodedNode *n, SymbolRef sym, - CheckerContext &Ctx, - bool IncludeAllocationLine) - : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { +void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) { + const SourceManager& SMgr = Ctx.getSourceManager(); + if (!sym->getOriginRegion()) + return; + + auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion()); + if (Region) { + const Decl *PDecl = Region->getDecl(); + if (PDecl && isa<ParmVarDecl>(PDecl)) { + PathDiagnosticLocation ParamLocation = PathDiagnosticLocation::create(PDecl, SMgr); + Location = ParamLocation; + UniqueingLocation = ParamLocation; + UniqueingDecl = Ctx.getLocationContext()->getDecl(); + } + } +} + +void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,SymbolRef sym) { // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. To do this, we need to find @@ -2455,8 +2495,12 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, // FIXME: This will crash the analyzer if an allocation comes from an // implicit call (ex: a destructor call). // (Currently there are no such allocations in Cocoa, though.) - const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); - assert(AllocStmt && "Cannot find allocation statement"); + AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); + + if (!AllocStmt) { + AllocBinding = nullptr; + return; + } PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, @@ -2467,8 +2511,10 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, // leaks should be uniqued on the allocation site. UniqueingLocation = AllocLocation; UniqueingDecl = AllocNode->getLocationContext()->getDecl(); +} - // Fill in the description of the bug. +void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine) { + assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid()); Description.clear(); llvm::raw_string_ostream os(Description); os << "Potential leak "; @@ -2483,6 +2529,20 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, os << " (allocated on line " << SL.getSpellingLineNumber() << ")"; } } +} + +CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, + bool GCEnabled, const SummaryLogTy &Log, + ExplodedNode *n, SymbolRef sym, + CheckerContext &Ctx, + bool IncludeAllocationLine) + : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { + + deriveAllocLocation(Ctx, sym); + if (!AllocBinding) + deriveParamLocation(Ctx, sym); + + createDescription(Ctx, GCEnabled, IncludeAllocationLine); addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, GCEnabled, Log)); } @@ -2496,6 +2556,7 @@ class RetainCountChecker : public Checker< check::Bind, check::DeadSymbols, check::EndAnalysis, + check::BeginFunction, check::EndFunction, check::PostStmt<BlockExpr>, check::PostStmt<CastExpr>, @@ -2680,6 +2741,7 @@ public: SymbolRef Sym, ProgramStateRef state) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void checkBeginFunction(CheckerContext &C) const; void checkEndFunction(CheckerContext &C) const; ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, @@ -3901,6 +3963,36 @@ RetainCountChecker::processLeaks(ProgramStateRef state, return N; } +void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { + if (!Ctx.inTopFrame()) + return; + + const LocationContext *LCtx = Ctx.getLocationContext(); + const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl()); + + if (!FD || isTrustedReferenceCountImplementation(FD)) + return; + + ProgramStateRef state = Ctx.getState(); + + const RetainSummary *FunctionSummary = getSummaryManager(Ctx).getFunctionSummary(FD); + ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects(); + + for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) { + const ParmVarDecl *Param = FD->getParamDecl(idx); + SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol(); + + QualType Ty = Param->getType(); + const ArgEffect *AE = CalleeSideArgEffects.lookup(idx); + if (AE && *AE == DecRef && isGeneralizedObjectRef(Ty)) + state = setRefBinding(state, Sym, RefVal::makeOwned(RetEffect::ObjKind::Generalized, Ty)); + else if (isGeneralizedObjectRef(Ty)) + state = setRefBinding(state, Sym, RefVal::makeNotOwned(RetEffect::ObjKind::Generalized, Ty)); + } + + Ctx.addTransition(state); +} + void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); RefBindingsTy B = state->get<RefBindings>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 556274d0edb65..25975628c553d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -18,6 +18,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/SmallString.h" @@ -26,85 +27,139 @@ using namespace clang; using namespace ento; namespace { -class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>, - check::EndFunction > { +class StackAddrEscapeChecker + : public Checker<check::PreCall, check::PreStmt<ReturnStmt>, + check::EndFunction> { + mutable IdentifierInfo *dispatch_semaphore_tII; mutable std::unique_ptr<BuiltinBug> BT_stackleak; mutable std::unique_ptr<BuiltinBug> BT_returnstack; + mutable std::unique_ptr<BuiltinBug> BT_capturedstackasync; + mutable std::unique_ptr<BuiltinBug> BT_capturedstackret; public: + enum CheckKind { + CK_StackAddrEscapeChecker, + CK_StackAddrAsyncEscapeChecker, + CK_NumCheckKinds + }; + + DefaultBool ChecksEnabled[CK_NumCheckKinds]; + + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; void checkEndFunction(CheckerContext &Ctx) const; + private: + void checkReturnedBlockCaptures(const BlockDataRegion &B, + CheckerContext &C) const; + void checkAsyncExecutedBlockCaptures(const BlockDataRegion &B, + CheckerContext &C) const; void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const; + bool isSemaphoreCaptured(const BlockDecl &B) const; static SourceRange genName(raw_ostream &os, const MemRegion *R, ASTContext &Ctx); + static SmallVector<const MemRegion *, 4> + getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C); + static bool isArcManagedBlock(const MemRegion *R, CheckerContext &C); + static bool isNotInCurrentFrame(const MemRegion *R, CheckerContext &C); }; -} +} // namespace SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R, ASTContext &Ctx) { - // Get the base region, stripping away fields and elements. + // Get the base region, stripping away fields and elements. R = R->getBaseRegion(); SourceManager &SM = Ctx.getSourceManager(); SourceRange range; os << "Address of "; // Check if the region is a compound literal. - if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { + if (const auto *CR = dyn_cast<CompoundLiteralRegion>(R)) { const CompoundLiteralExpr *CL = CR->getLiteralExpr(); os << "stack memory associated with a compound literal " "declared on line " - << SM.getExpansionLineNumber(CL->getLocStart()) - << " returned to caller"; + << SM.getExpansionLineNumber(CL->getLocStart()) << " returned to caller"; range = CL->getSourceRange(); - } - else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { + } else if (const auto *AR = dyn_cast<AllocaRegion>(R)) { const Expr *ARE = AR->getExpr(); SourceLocation L = ARE->getLocStart(); range = ARE->getSourceRange(); os << "stack memory allocated by call to alloca() on line " << SM.getExpansionLineNumber(L); - } - else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { + } else if (const auto *BR = dyn_cast<BlockDataRegion>(R)) { const BlockDecl *BD = BR->getCodeRegion()->getDecl(); SourceLocation L = BD->getLocStart(); range = BD->getSourceRange(); os << "stack-allocated block declared on line " << SM.getExpansionLineNumber(L); - } - else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << "stack memory associated with local variable '" - << VR->getString() << '\''; + } else if (const auto *VR = dyn_cast<VarRegion>(R)) { + os << "stack memory associated with local variable '" << VR->getString() + << '\''; range = VR->getDecl()->getSourceRange(); - } - else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) { + } else if (const auto *TOR = dyn_cast<CXXTempObjectRegion>(R)) { QualType Ty = TOR->getValueType().getLocalUnqualifiedType(); os << "stack memory associated with temporary object of type '"; Ty.print(os, Ctx.getPrintingPolicy()); os << "'"; range = TOR->getExpr()->getSourceRange(); - } - else { + } else { llvm_unreachable("Invalid region in ReturnStackAddressChecker."); } return range; } -void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, - const Expr *RetE) const { - ExplodedNode *N = C.generateErrorNode(); +bool StackAddrEscapeChecker::isArcManagedBlock(const MemRegion *R, + CheckerContext &C) { + assert(R && "MemRegion should not be null"); + return C.getASTContext().getLangOpts().ObjCAutoRefCount && + isa<BlockDataRegion>(R); +} +bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemRegion *R, + CheckerContext &C) { + const StackSpaceRegion *S = cast<StackSpaceRegion>(R->getMemorySpace()); + return S->getStackFrame() != C.getLocationContext()->getCurrentStackFrame(); +} + +bool StackAddrEscapeChecker::isSemaphoreCaptured(const BlockDecl &B) const { + if (!dispatch_semaphore_tII) + dispatch_semaphore_tII = &B.getASTContext().Idents.get("dispatch_semaphore_t"); + for (const auto &C : B.captures()) { + const auto *T = C.getVariable()->getType()->getAs<TypedefType>(); + if (T && T->getDecl()->getIdentifier() == dispatch_semaphore_tII) + return true; + } + return false; +} + +SmallVector<const MemRegion *, 4> +StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B, + CheckerContext &C) { + SmallVector<const MemRegion *, 4> Regions; + BlockDataRegion::referenced_vars_iterator I = B.referenced_vars_begin(); + BlockDataRegion::referenced_vars_iterator E = B.referenced_vars_end(); + for (; I != E; ++I) { + SVal Val = C.getState()->getSVal(I.getCapturedRegion()); + const MemRegion *Region = Val.getAsRegion(); + if (Region && isa<StackSpaceRegion>(Region->getMemorySpace())) + Regions.push_back(Region); + } + return Regions; +} + +void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, + const MemRegion *R, + const Expr *RetE) const { + ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) return; - if (!BT_returnstack) - BT_returnstack.reset( - new BuiltinBug(this, "Return of address to stack-allocated memory")); - + BT_returnstack = llvm::make_unique<BuiltinBug>( + this, "Return of address to stack-allocated memory"); // Generate a report for this bug. - SmallString<512> buf; + SmallString<128> buf; llvm::raw_svector_ostream os(buf); SourceRange range = genName(os, R, C.getASTContext()); os << " returned to caller"; @@ -112,12 +167,88 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion * report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); - C.emitReport(std::move(report)); } +void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures( + const BlockDataRegion &B, CheckerContext &C) const { + // There is a not-too-uncommon idiom + // where a block passed to dispatch_async captures a semaphore + // and then the thread (which called dispatch_async) is blocked on waiting + // for the completion of the execution of the block + // via dispatch_semaphore_wait. To avoid false-positives (for now) + // we ignore all the blocks which have captured + // a variable of the type "dispatch_semaphore_t". + if (isSemaphoreCaptured(*B.getDecl())) + return; + for (const MemRegion *Region : getCapturedStackRegions(B, C)) { + // The block passed to dispatch_async may capture another block + // created on the stack. However, there is no leak in this situaton, + // no matter if ARC or no ARC is enabled: + // dispatch_async copies the passed "outer" block (via Block_copy) + // and if the block has captured another "inner" block, + // the "inner" block will be copied as well. + if (isa<BlockDataRegion>(Region)) + continue; + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + continue; + if (!BT_capturedstackasync) + BT_capturedstackasync = llvm::make_unique<BuiltinBug>( + this, "Address of stack-allocated memory is captured"); + SmallString<128> Buf; + llvm::raw_svector_ostream Out(Buf); + SourceRange Range = genName(Out, Region, C.getASTContext()); + Out << " is captured by an asynchronously-executed block"; + auto Report = + llvm::make_unique<BugReport>(*BT_capturedstackasync, Out.str(), N); + if (Range.isValid()) + Report->addRange(Range); + C.emitReport(std::move(Report)); + } +} + +void StackAddrEscapeChecker::checkReturnedBlockCaptures( + const BlockDataRegion &B, CheckerContext &C) const { + for (const MemRegion *Region : getCapturedStackRegions(B, C)) { + if (isArcManagedBlock(Region, C) || isNotInCurrentFrame(Region, C)) + continue; + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + continue; + if (!BT_capturedstackret) + BT_capturedstackret = llvm::make_unique<BuiltinBug>( + this, "Address of stack-allocated memory is captured"); + SmallString<128> Buf; + llvm::raw_svector_ostream Out(Buf); + SourceRange Range = genName(Out, Region, C.getASTContext()); + Out << " is captured by a returned block"; + auto Report = + llvm::make_unique<BugReport>(*BT_capturedstackret, Out.str(), N); + if (Range.isValid()) + Report->addRange(Range); + C.emitReport(std::move(Report)); + } +} + +void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker]) + return; + if (!Call.isGlobalCFunction("dispatch_after") && + !Call.isGlobalCFunction("dispatch_async")) + return; + for (unsigned Idx = 0, NumArgs = Call.getNumArgs(); Idx < NumArgs; ++Idx) { + if (const BlockDataRegion *B = dyn_cast_or_null<BlockDataRegion>( + Call.getArgSVal(Idx).getAsRegion())) + checkAsyncExecutedBlockCaptures(*B, C); + } +} + void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { + if (!ChecksEnabled[CK_StackAddrEscapeChecker]) + return; const Expr *RetE = RS->getRetValue(); if (!RetE) @@ -127,25 +258,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, const LocationContext *LCtx = C.getLocationContext(); SVal V = C.getState()->getSVal(RetE, LCtx); const MemRegion *R = V.getAsRegion(); - if (!R) return; - const StackSpaceRegion *SS = - dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace()); - - if (!SS) - return; - - // Return stack memory in an ancestor stack frame is fine. - const StackFrameContext *CurFrame = LCtx->getCurrentStackFrame(); - const StackFrameContext *MemFrame = SS->getStackFrame(); - if (MemFrame != CurFrame) - return; + if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R)) + checkReturnedBlockCaptures(*B, C); - // Automatic reference counting automatically copies blocks. - if (C.getASTContext().getLangOpts().ObjCAutoRefCount && - isa<BlockDataRegion>(R)) + if (!isa<StackSpaceRegion>(R->getMemorySpace()) || + isNotInCurrentFrame(R, C) || isArcManagedBlock(R, C)) return; // Returning a record by value is fine. (In this case, the returned @@ -169,7 +289,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, } void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { - ProgramStateRef state = Ctx.getState(); + if (!ChecksEnabled[CK_StackAddrEscapeChecker]) + return; + + ProgramStateRef State = Ctx.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. @@ -177,82 +300,73 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { private: CheckerContext &Ctx; const StackFrameContext *CurSFC; - public: - SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; - CallBack(CheckerContext &CC) : - Ctx(CC), - CurSFC(CC.getLocationContext()->getCurrentStackFrame()) - {} + public: + SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V; - bool HandleBinding(StoreManager &SMgr, Store store, - const MemRegion *region, SVal val) override { + CallBack(CheckerContext &CC) + : Ctx(CC), CurSFC(CC.getLocationContext()->getCurrentStackFrame()) {} - if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) - return true; + bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region, + SVal Val) override { - const MemRegion *vR = val.getAsRegion(); - if (!vR) + if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace())) return true; - - // Under automated retain release, it is okay to assign a block - // directly to a global variable. - if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount && - isa<BlockDataRegion>(vR)) - return true; - - if (const StackSpaceRegion *SSR = - dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { - // If the global variable holds a location in the current stack frame, - // record the binding to emit a warning. - if (SSR->getStackFrame() == CurSFC) - V.push_back(std::make_pair(region, vR)); - } - + const MemRegion *VR = Val.getAsRegion(); + if (VR && isa<StackSpaceRegion>(VR->getMemorySpace()) && + !isArcManagedBlock(VR, Ctx) && !isNotInCurrentFrame(VR, Ctx)) + V.emplace_back(Region, VR); return true; } }; - CallBack cb(Ctx); - state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); + CallBack Cb(Ctx); + State->getStateManager().getStoreManager().iterBindings(State->getStore(), + Cb); - if (cb.V.empty()) + if (Cb.V.empty()) return; // Generate an error node. - ExplodedNode *N = Ctx.generateNonFatalErrorNode(state); + ExplodedNode *N = Ctx.generateNonFatalErrorNode(State); if (!N) return; if (!BT_stackleak) - BT_stackleak.reset( - new BuiltinBug(this, "Stack address stored into global variable", - "Stack address was saved into a global variable. " - "This is dangerous because the address will become " - "invalid after returning from the function")); + BT_stackleak = llvm::make_unique<BuiltinBug>( + this, "Stack address stored into global variable", + "Stack address was saved into a global variable. " + "This is dangerous because the address will become " + "invalid after returning from the function"); - for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { + for (const auto &P : Cb.V) { // Generate a report for this bug. - SmallString<512> buf; - llvm::raw_svector_ostream os(buf); - SourceRange range = genName(os, cb.V[i].second, Ctx.getASTContext()); - os << " is still referred to by the "; - if (isa<StaticGlobalSpaceRegion>(cb.V[i].first->getMemorySpace())) - os << "static"; + SmallString<128> Buf; + llvm::raw_svector_ostream Out(Buf); + SourceRange Range = genName(Out, P.second, Ctx.getASTContext()); + Out << " is still referred to by the "; + if (isa<StaticGlobalSpaceRegion>(P.first->getMemorySpace())) + Out << "static"; else - os << "global"; - os << " variable '"; - const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); - os << *VR->getDecl() - << "' upon returning to the caller. This will be a dangling reference"; - auto report = llvm::make_unique<BugReport>(*BT_stackleak, os.str(), N); - if (range.isValid()) - report->addRange(range); + Out << "global"; + Out << " variable '"; + const VarRegion *VR = cast<VarRegion>(P.first->getBaseRegion()); + Out << *VR->getDecl() + << "' upon returning to the caller. This will be a dangling reference"; + auto Report = llvm::make_unique<BugReport>(*BT_stackleak, Out.str(), N); + if (Range.isValid()) + Report->addRange(Range); - Ctx.emitReport(std::move(report)); + Ctx.emitReport(std::move(Report)); } } -void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) { - mgr.registerChecker<StackAddrEscapeChecker>(); -} +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &Mgr) { \ + StackAddrEscapeChecker *Chk = \ + Mgr.registerChecker<StackAddrEscapeChecker>(); \ + Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ + } + +REGISTER_CHECKER(StackAddrEscapeChecker) +REGISTER_CHECKER(StackAddrAsyncEscapeChecker) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index f3c2ffc58662e..172ce346f1ba7 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -59,6 +59,11 @@ static bool isArrayIndexOutOfBounds(CheckerContext &C, const Expr *Ex) { return StOutBound && !StInBound; } +static bool isShiftOverflow(const BinaryOperator *B, CheckerContext &C) { + return C.isGreaterOrEqual( + B->getRHS(), C.getASTContext().getIntWidth(B->getLHS()->getType())); +} + void UndefResultChecker::checkPostStmt(const BinaryOperator *B, CheckerContext &C) const { ProgramStateRef state = C.getState(); @@ -97,18 +102,50 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, } if (Ex) { - OS << "The " << (isLeft ? "left" : "right") - << " operand of '" + OS << "The " << (isLeft ? "left" : "right") << " operand of '" << BinaryOperator::getOpcodeStr(B->getOpcode()) << "' is a garbage value"; if (isArrayIndexOutOfBounds(C, Ex)) OS << " due to array index out of bounds"; - } - else { + } else { // Neither operand was undefined, but the result is undefined. - OS << "The result of the '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' expression is undefined"; + if ((B->getOpcode() == BinaryOperatorKind::BO_Shl || + B->getOpcode() == BinaryOperatorKind::BO_Shr) && + C.isNegative(B->getRHS())) { + OS << "The result of the " + << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left" + : "right") + << " shift is undefined because the right operand is negative"; + } else if ((B->getOpcode() == BinaryOperatorKind::BO_Shl || + B->getOpcode() == BinaryOperatorKind::BO_Shr) && + isShiftOverflow(B, C)) { + + OS << "The result of the " + << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left" + : "right") + << " shift is undefined due to shifting by "; + + SValBuilder &SB = C.getSValBuilder(); + const llvm::APSInt *I = + SB.getKnownValue(C.getState(), C.getSVal(B->getRHS())); + if (!I) + OS << "a value that is"; + else if (I->isUnsigned()) + OS << '\'' << I->getZExtValue() << "\', which is"; + else + OS << '\'' << I->getSExtValue() << "\', which is"; + + OS << " greater or equal to the width of type '" + << B->getLHS()->getType().getAsString() << "'."; + } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl && + C.isNegative(B->getLHS())) { + OS << "The result of the left shift is undefined because the left " + "operand is negative"; + } else { + OS << "The result of the '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' expression is undefined"; + } } auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N); if (Ex) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 7a31efc8cef88..c3dcf1fac197b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -60,6 +60,14 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, const Expr *ex = nullptr; while (StoreE) { + if (const UnaryOperator *U = dyn_cast<UnaryOperator>(StoreE)) { + str = "The expression is an uninitialized value. " + "The computed value will also be garbage"; + + ex = U->getSubExpr(); + break; + } + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { ProgramStateRef state = C.getState(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index ccd8e9a18b00f..6f21e868b1742 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -112,7 +112,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, continue; // Check for false positives - if (CB->size() > 0 && isInvalidPath(CB, *PM)) + if (isInvalidPath(CB, *PM)) continue; // It is good practice to always have a "default" label in a "switch", even diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index b47762b915ce9..c5010f53785a8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -14,279 +14,272 @@ #include "ClangSACheckers.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/StmtVisitor.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/SaveAndRestore.h" -#include "llvm/Support/raw_ostream.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" using namespace clang; using namespace ento; namespace { +enum class ObjectState : bool { CtorCalled, DtorCalled }; +} // end namespace + // FIXME: Ascending over StackFrameContext maybe another method. -class WalkAST : public StmtVisitor<WalkAST> { - const CheckerBase *Checker; - BugReporter &BR; - AnalysisDeclContext *AC; - - /// The root constructor or destructor whose callees are being analyzed. - const CXXMethodDecl *RootMethod = nullptr; - - /// Whether the checker should walk into bodies of called functions. - /// Controlled by the "Interprocedural" analyzer-config option. - bool IsInterprocedural = false; - - /// Whether the checker should only warn for calls to pure virtual functions - /// (which is undefined behavior) or for all virtual functions (which may - /// may result in unexpected behavior). - bool ReportPureOnly = false; - - typedef const CallExpr * WorkListUnit; - typedef SmallVector<WorkListUnit, 20> DFSWorkList; - - /// A vector representing the worklist which has a chain of CallExprs. - DFSWorkList WList; - - // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the - // body has not been visited yet. - // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the - // body has been visited. - enum Kind { NotVisited, - PreVisited, /**< A CallExpr to this FunctionDecl is in the - worklist, but the body has not yet been - visited. */ - PostVisited /**< A CallExpr to this FunctionDecl is in the - worklist, and the body has been visited. */ - }; - - /// A DenseMap that records visited states of FunctionDecls. - llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions; +namespace llvm { +template <> struct FoldingSetTrait<ObjectState> { + static inline void Profile(ObjectState X, FoldingSetNodeID &ID) { + ID.AddInteger(static_cast<int>(X)); + } +}; +} // end namespace llvm - /// The CallExpr whose body is currently being visited. This is used for - /// generating bug reports. This is null while visiting the body of a - /// constructor or destructor. - const CallExpr *visitingCallExpr; +namespace { +class VirtualCallChecker + : public Checker<check::BeginFunction, check::EndFunction, check::PreCall> { + mutable std::unique_ptr<BugType> BT; public: - WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac, - const CXXMethodDecl *rootMethod, bool isInterprocedural, - bool reportPureOnly) - : Checker(checker), BR(br), AC(ac), RootMethod(rootMethod), - IsInterprocedural(isInterprocedural), ReportPureOnly(reportPureOnly), - visitingCallExpr(nullptr) { - // Walking should always start from either a constructor or a destructor. - assert(isa<CXXConstructorDecl>(rootMethod) || - isa<CXXDestructorDecl>(rootMethod)); - } + // The flag to determine if pure virtual functions should be issued only. + DefaultBool IsPureOnly; - bool hasWork() const { return !WList.empty(); } + void checkBeginFunction(CheckerContext &C) const; + void checkEndFunction(CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; - /// This method adds a CallExpr to the worklist and marks the callee as - /// being PreVisited. - void Enqueue(WorkListUnit WLUnit) { - const FunctionDecl *FD = WLUnit->getDirectCallee(); - if (!FD || !FD->getBody()) - return; - Kind &K = VisitedFunctions[FD]; - if (K != NotVisited) - return; - K = PreVisited; - WList.push_back(WLUnit); - } +private: + void registerCtorDtorCallInState(bool IsBeginFunction, + CheckerContext &C) const; + void reportBug(StringRef Msg, bool PureError, const MemRegion *Reg, + CheckerContext &C) const; - /// This method returns an item from the worklist without removing it. - WorkListUnit Dequeue() { - assert(!WList.empty()); - return WList.back(); - } + class VirtualBugVisitor : public BugReporterVisitorImpl<VirtualBugVisitor> { + private: + const MemRegion *ObjectRegion; + bool Found; - void Execute() { - while (hasWork()) { - WorkListUnit WLUnit = Dequeue(); - const FunctionDecl *FD = WLUnit->getDirectCallee(); - assert(FD && FD->getBody()); + public: + VirtualBugVisitor(const MemRegion *R) : ObjectRegion(R), Found(false) {} - if (VisitedFunctions[FD] == PreVisited) { - // If the callee is PreVisited, walk its body. - // Visit the body. - SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit); - Visit(FD->getBody()); + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int X = 0; + ID.AddPointer(&X); + ID.AddPointer(ObjectRegion); + } - // Mark the function as being PostVisited to indicate we have - // scanned the body. - VisitedFunctions[FD] = PostVisited; - continue; - } + std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; + }; +}; +} // end namespace - // Otherwise, the callee is PostVisited. - // Remove it from the worklist. - assert(VisitedFunctions[FD] == PostVisited); - WList.pop_back(); - } - } +// GDM (generic data map) to the memregion of this for the ctor and dtor. +REGISTER_MAP_WITH_PROGRAMSTATE(CtorDtorMap, const MemRegion *, ObjectState) - // Stmt visitor methods. - void VisitCallExpr(CallExpr *CE); - void VisitCXXMemberCallExpr(CallExpr *CE); - void VisitStmt(Stmt *S) { VisitChildren(S); } - void VisitChildren(Stmt *S); +std::shared_ptr<PathDiagnosticPiece> +VirtualCallChecker::VirtualBugVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + // We need the last ctor/dtor which call the virtual function. + // The visitor walks the ExplodedGraph backwards. + if (Found) + return nullptr; - void ReportVirtualCall(const CallExpr *CE, bool isPure); + ProgramStateRef State = N->getState(); + const LocationContext *LCtx = N->getLocationContext(); + const CXXConstructorDecl *CD = + dyn_cast_or_null<CXXConstructorDecl>(LCtx->getDecl()); + const CXXDestructorDecl *DD = + dyn_cast_or_null<CXXDestructorDecl>(LCtx->getDecl()); -}; -} // end anonymous namespace + if (!CD && !DD) + return nullptr; -//===----------------------------------------------------------------------===// -// AST walking. -//===----------------------------------------------------------------------===// + ProgramStateManager &PSM = State->getStateManager(); + auto &SVB = PSM.getSValBuilder(); + const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl()); + if (!MD) + return nullptr; + auto ThiSVal = + State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame())); + const MemRegion *Reg = ThiSVal.castAs<loc::MemRegionVal>().getRegion(); + if (!Reg) + return nullptr; + if (Reg != ObjectRegion) + return nullptr; -void WalkAST::VisitChildren(Stmt *S) { - for (Stmt *Child : S->children()) - if (Child) - Visit(Child); -} + const Stmt *S = PathDiagnosticLocation::getStmt(N); + if (!S) + return nullptr; + Found = true; + + std::string InfoText; + if (CD) + InfoText = "This constructor of an object of type '" + + CD->getNameAsString() + + "' has not returned when the virtual method was called"; + else + InfoText = "This destructor of an object of type '" + + DD->getNameAsString() + + "' has not returned when the virtual method was called"; -void WalkAST::VisitCallExpr(CallExpr *CE) { - VisitChildren(CE); - if (IsInterprocedural) - Enqueue(CE); + // Generate the extra diagnostic. + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), + N->getLocationContext()); + return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true); } -void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) { - VisitChildren(CE); - bool callIsNonVirtual = false; +// The function to check if a callexpr is a virtual function. +static bool isVirtualCall(const CallExpr *CE) { + bool CallIsNonVirtual = false; - // Several situations to elide for checking. - if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) { - // If the member access is fully qualified (i.e., X::F), then treat - // this as a non-virtual call and do not warn. + if (const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) { + // The member access is fully qualified (i.e., X::F). + // Treat this as a non-virtual call and do not warn. if (CME->getQualifier()) - callIsNonVirtual = true; - - if (Expr *base = CME->getBase()->IgnoreImpCasts()) { - // Elide analyzing the call entirely if the base pointer is not 'this'. - if (!isa<CXXThisExpr>(base)) - return; + CallIsNonVirtual = true; - // If the most derived class is marked final, we know that now subclass - // can override this member. - if (base->getBestDynamicClassType()->hasAttr<FinalAttr>()) - callIsNonVirtual = true; + if (const Expr *Base = CME->getBase()) { + // The most derived class is marked final. + if (Base->getBestDynamicClassType()->hasAttr<FinalAttr>()) + CallIsNonVirtual = true; } } - // Get the callee. const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee()); - if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() && + if (MD && MD->isVirtual() && !CallIsNonVirtual && !MD->hasAttr<FinalAttr>() && !MD->getParent()->hasAttr<FinalAttr>()) - ReportVirtualCall(CE, MD->isPure()); + return true; + return false; +} - if (IsInterprocedural) - Enqueue(CE); +// The BeginFunction callback when enter a constructor or a destructor. +void VirtualCallChecker::checkBeginFunction(CheckerContext &C) const { + registerCtorDtorCallInState(true, C); } -void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { - if (ReportPureOnly && !isPure) +// The EndFunction callback when leave a constructor or a destructor. +void VirtualCallChecker::checkEndFunction(CheckerContext &C) const { + registerCtorDtorCallInState(false, C); +} + +void VirtualCallChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + const auto MC = dyn_cast<CXXMemberCall>(&Call); + if (!MC) return; - SmallString<100> buf; - llvm::raw_svector_ostream os(buf); + const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl()); + if (!MD) + return; + ProgramStateRef State = C.getState(); + const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); - // FIXME: The interprocedural diagnostic experience here is not good. - // Ultimately this checker should be re-written to be path sensitive. - // For now, only diagnose intraprocedurally, by default. - if (IsInterprocedural) { - os << "Call Path : "; - // Name of current visiting CallExpr. - os << *CE->getDirectCallee(); + if (IsPureOnly && !MD->isPure()) + return; + if (!isVirtualCall(CE)) + return; - // Name of the CallExpr whose body is current being walked. - if (visitingCallExpr) - os << " <-- " << *visitingCallExpr->getDirectCallee(); - // Names of FunctionDecls in worklist with state PostVisited. - for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(), - E = WList.begin(); I != E; --I) { - const FunctionDecl *FD = (*(I-1))->getDirectCallee(); - assert(FD); - if (VisitedFunctions[FD] == PostVisited) - os << " <-- " << *FD; - } + const MemRegion *Reg = MC->getCXXThisVal().getAsRegion(); + const ObjectState *ObState = State->get<CtorDtorMap>(Reg); + if (!ObState) + return; + // Check if a virtual method is called. + // The GDM of constructor and destructor should be true. + if (*ObState == ObjectState::CtorCalled) { + if (IsPureOnly && MD->isPure()) + reportBug("Call to pure virtual function during construction", true, Reg, + C); + else if (!MD->isPure()) + reportBug("Call to virtual function during construction", false, Reg, C); + else + reportBug("Call to pure virtual function during construction", false, Reg, + C); + } - os << "\n"; + if (*ObState == ObjectState::DtorCalled) { + if (IsPureOnly && MD->isPure()) + reportBug("Call to pure virtual function during destruction", true, Reg, + C); + else if (!MD->isPure()) + reportBug("Call to virtual function during destruction", false, Reg, C); + else + reportBug("Call to pure virtual function during construction", false, Reg, + C); } +} - PathDiagnosticLocation CELoc = - PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - SourceRange R = CE->getCallee()->getSourceRange(); +void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction, + CheckerContext &C) const { + const auto *LCtx = C.getLocationContext(); + const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl()); + if (!MD) + return; - os << "Call to "; - if (isPure) - os << "pure "; + ProgramStateRef State = C.getState(); + auto &SVB = C.getSValBuilder(); - os << "virtual function during "; + // Enter a constructor, set the corresponding memregion be true. + if (isa<CXXConstructorDecl>(MD)) { + auto ThiSVal = + State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame())); + const MemRegion *Reg = ThiSVal.getAsRegion(); + if (IsBeginFunction) + State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled); + else + State = State->remove<CtorDtorMap>(Reg); - if (isa<CXXConstructorDecl>(RootMethod)) - os << "construction "; - else - os << "destruction "; + C.addTransition(State); + return; + } - if (isPure) - os << "has undefined behavior"; - else - os << "will not dispatch to derived class"; + // Enter a Destructor, set the corresponding memregion be true. + if (isa<CXXDestructorDecl>(MD)) { + auto ThiSVal = + State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame())); + const MemRegion *Reg = ThiSVal.getAsRegion(); + if (IsBeginFunction) + State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled); + else + State = State->remove<CtorDtorMap>(Reg); - BR.EmitBasicReport(AC->getDecl(), Checker, - "Call to virtual function during construction or " - "destruction", - "C++ Object Lifecycle", os.str(), CELoc, R); + C.addTransition(State); + return; + } } -//===----------------------------------------------------------------------===// -// VirtualCallChecker -//===----------------------------------------------------------------------===// - -namespace { -class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > { -public: - DefaultBool isInterprocedural; - DefaultBool isPureOnly; - - void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr, - BugReporter &BR) const { - AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(RD); +void VirtualCallChecker::reportBug(StringRef Msg, bool IsSink, + const MemRegion *Reg, + CheckerContext &C) const { + ExplodedNode *N; + if (IsSink) + N = C.generateErrorNode(); + else + N = C.generateNonFatalErrorNode(); - // Check the constructors. - for (const auto *I : RD->ctors()) { - if (!I->isCopyOrMoveConstructor()) - if (Stmt *Body = I->getBody()) { - WalkAST walker(this, BR, ADC, I, isInterprocedural, isPureOnly); - walker.Visit(Body); - walker.Execute(); - } - } + if (!N) + return; + if (!BT) + BT.reset(new BugType( + this, "Call to virtual function during construction or destruction", + "C++ Object Lifecycle")); - // Check the destructor. - if (CXXDestructorDecl *DD = RD->getDestructor()) - if (Stmt *Body = DD->getBody()) { - WalkAST walker(this, BR, ADC, DD, isInterprocedural, isPureOnly); - walker.Visit(Body); - walker.Execute(); - } - } -}; + auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N); + Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg)); + C.emitReport(std::move(Reporter)); } void ento::registerVirtualCallChecker(CheckerManager &mgr) { VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>(); - checker->isInterprocedural = - mgr.getAnalyzerOptions().getBooleanOption("Interprocedural", false, - checker); - checker->isPureOnly = - mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false, - checker); + checker->IsPureOnly = + mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false, checker); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 83e67662e614c..1cc08f0d9fe75 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -14,30 +14,25 @@ using namespace ento; void AnalysisManager::anchor() { } -AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - const LangOptions &lang, - const PathDiagnosticConsumers &PDC, - StoreManagerCreator storemgr, - ConstraintManagerCreator constraintmgr, - CheckerManager *checkerMgr, - AnalyzerOptions &Options, - CodeInjector *injector) - : AnaCtxMgr(Options.UnoptimizedCFG, - Options.includeImplicitDtorsInCFG(), - /*AddInitializers=*/true, - Options.includeTemporaryDtorsInCFG(), - Options.includeLifetimeInCFG(), - Options.shouldSynthesizeBodies(), - Options.shouldConditionalizeStaticInitializers(), - /*addCXXNewAllocator=*/true, - injector), - Ctx(ctx), - Diags(diags), - LangOpts(lang), - PathConsumers(PDC), - CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - CheckerMgr(checkerMgr), - options(Options) { +AnalysisManager::AnalysisManager( + ASTContext &ASTCtx, DiagnosticsEngine &diags, const LangOptions &lang, + const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, + AnalyzerOptions &Options, CodeInjector *injector) + : AnaCtxMgr(ASTCtx, Options.UnoptimizedCFG, + Options.includeImplicitDtorsInCFG(), + /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), + Options.includeLifetimeInCFG(), + // Adding LoopExit elements to the CFG is a requirement for loop + // unrolling. + Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(), + Options.shouldSynthesizeBodies(), + Options.shouldConditionalizeStaticInitializers(), + /*addCXXNewAllocator=*/true, + injector), + Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 6f48fcb9e20ce..48e3e22af04ab 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -183,6 +183,11 @@ bool AnalyzerOptions::includeLifetimeInCFG() { /* Default = */ false); } +bool AnalyzerOptions::includeLoopExitInCFG() { + return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit", + /* Default = */ false); +} + bool AnalyzerOptions::mayInlineCXXStandardLibrary() { return getBooleanOption(InlineCXXStandardLibrary, "c++-stdlib-inlining", @@ -375,6 +380,12 @@ bool AnalyzerOptions::shouldWidenLoops() { return WidenLoops.getValue(); } +bool AnalyzerOptions::shouldUnrollLoops() { + if (!UnrollLoops.hasValue()) + UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); + return UnrollLoops.getValue(); +} + bool AnalyzerOptions::shouldDisplayNotesAsEvents() { if (!DisplayNotesAsEvents.hasValue()) DisplayNotesAsEvents = diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index ebbace4e33b38..ec7a7e9e4b1c8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -225,6 +225,8 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // test these conditions symbolically. // FIXME: Expand these checks to include all undefined behavior. + if (V1.isSigned() && V1.isNegative()) + return nullptr; if (V2.isSigned() && V2.isNegative()) return nullptr; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index d8fca00681b4d..4a5d25fc56345 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3310,6 +3310,78 @@ static const CFGBlock *findBlockForNode(const ExplodedNode *N) { return nullptr; } +// Returns true if by simply looking at the block, we can be sure that it +// results in a sink during analysis. This is useful to know when the analysis +// was interrupted, and we try to figure out if it would sink eventually. +// There may be many more reasons why a sink would appear during analysis +// (eg. checkers may generate sinks arbitrarily), but here we only consider +// sinks that would be obvious by looking at the CFG. +static bool isImmediateSinkBlock(const CFGBlock *Blk) { + if (Blk->hasNoReturnElement()) + return true; + + // FIXME: Throw-expressions are currently generating sinks during analysis: + // they're not supported yet, and also often used for actually terminating + // the program. So we should treat them as sinks in this analysis as well, + // at least for now, but once we have better support for exceptions, + // we'd need to carefully handle the case when the throw is being + // immediately caught. + if (std::any_of(Blk->begin(), Blk->end(), [](const CFGElement &Elm) { + if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>()) + if (isa<CXXThrowExpr>(StmtElm->getStmt())) + return true; + return false; + })) + return true; + + return false; +} + +// Returns true if by looking at the CFG surrounding the node's program +// point, we can be sure that any analysis starting from this point would +// eventually end with a sink. We scan the child CFG blocks in a depth-first +// manner and see if all paths eventually end up in an immediate sink block. +static bool isInevitablySinking(const ExplodedNode *N) { + const CFG &Cfg = N->getCFG(); + + const CFGBlock *StartBlk = findBlockForNode(N); + if (!StartBlk) + return false; + if (isImmediateSinkBlock(StartBlk)) + return true; + + llvm::SmallVector<const CFGBlock *, 32> DFSWorkList; + llvm::SmallPtrSet<const CFGBlock *, 32> Visited; + + DFSWorkList.push_back(StartBlk); + while (!DFSWorkList.empty()) { + const CFGBlock *Blk = DFSWorkList.back(); + DFSWorkList.pop_back(); + Visited.insert(Blk); + + for (const auto &Succ : Blk->succs()) { + if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) { + if (SuccBlk == &Cfg.getExit()) { + // If at least one path reaches the CFG exit, it means that control is + // returned to the caller. For now, say that we are not sure what + // happens next. If necessary, this can be improved to analyze + // the parent StackFrameContext's call site in a similar manner. + return false; + } + + if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) { + // If the block has reachable child blocks that aren't no-return, + // add them to the worklist. + DFSWorkList.push_back(SuccBlk); + } + } + } + } + + // Nothing reached the exit. It can only mean one thing: there's no return. + return true; +} + static BugReport * FindReportInEquivalenceClass(BugReportEquivClass& EQ, SmallVectorImpl<BugReport*> &bugReports) { @@ -3360,15 +3432,10 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // See if we are in a no-return CFG block. If so, treat this similarly // to being post-dominated by a sink. This works better when the analysis - // is incomplete and we have never reached a no-return function - // we're post-dominated by. - // This is not quite enough to handle the incomplete analysis case. - // We may be post-dominated in subsequent blocks, or even - // inter-procedurally. However, it is not clear if more complicated - // cases are generally worth suppressing. - if (const CFGBlock *B = findBlockForNode(errorNode)) - if (B->hasNoReturnElement()) - continue; + // is incomplete and we have never reached the no-return function call(s) + // that we'd inevitably bump into on this path. + if (isInevitablySinking(errorNode)) + continue; // At this point we know that 'N' is not a sink and it has at least one // successor. Use a DFS worklist to find a non-sink end-of-path node. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index d00182a871c1e..7304d789431ee 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -11,7 +11,7 @@ // enhance the diagnostics reported for a bug. // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Analysis/CFGStmtMap.h" @@ -42,48 +42,80 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { return false; } +/// Given that expression S represents a pointer that would be dereferenced, +/// try to find a sub-expression from which the pointer came from. +/// This is used for tracking down origins of a null or undefined value: +/// "this is null because that is null because that is null" etc. +/// We wipe away field and element offsets because they merely add offsets. +/// We also wipe away all casts except lvalue-to-rvalue casts, because the +/// latter represent an actual pointer dereference; however, we remove +/// the final lvalue-to-rvalue cast before returning from this function +/// because it demonstrates more clearly from where the pointer rvalue was +/// loaded. Examples: +/// x->y.z ==> x (lvalue) +/// foo()->y.z ==> foo() (rvalue) const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases: - // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) return nullptr; - E = E->IgnoreParenCasts(); while (true) { - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) { - assert(B->isAssignmentOp()); - E = B->getLHS()->IgnoreParenCasts(); - continue; - } - else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { - if (U->getOpcode() == UO_Deref) - return U->getSubExpr()->IgnoreParenCasts(); - } - else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (ME->isImplicitAccess()) { - return ME; - } else if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { - return ME->getBase()->IgnoreParenCasts(); + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_LValueToRValue) { + // This cast represents the load we're looking for. + break; + } + E = CE->getSubExpr(); + } else if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) { + // Pointer arithmetic: '*(x + 2)' -> 'x') etc. + if (B->getType()->isPointerType()) { + if (B->getLHS()->getType()->isPointerType()) { + E = B->getLHS(); + } else if (B->getRHS()->getType()->isPointerType()) { + E = B->getRHS(); + } else { + break; + } } else { - // If we have a member expr with a dot, the base must have been - // dereferenced. - return getDerefExpr(ME->getBase()); + // Probably more arithmetic can be pattern-matched here, + // but for now give up. + break; + } + } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { + if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf || + (U->isIncrementDecrementOp() && U->getType()->isPointerType())) { + // Operators '*' and '&' don't actually mean anything. + // We look at casts instead. + E = U->getSubExpr(); + } else { + // Probably more arithmetic can be pattern-matched here, + // but for now give up. + break; } } - else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { - return IvarRef->getBase()->IgnoreParenCasts(); - } - else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { - return getDerefExpr(AE->getBase()); - } - else if (isa<DeclRefExpr>(E)) { - return E; + // Pattern match for a few useful cases: a[0], p->f, *p etc. + else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + E = ME->getBase(); + } else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { + E = IvarRef->getBase(); + } else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { + E = AE->getBase(); + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + } else { + // Other arbitrary stuff. + break; } - break; } - return nullptr; + // Special case: remove the final lvalue-to-rvalue cast, but do not recurse + // deeper into the sub-expression. This way we return the lvalue from which + // our pointer rvalue was loaded. + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + if (CE->getCastKind() == CK_LValueToRValue) + E = CE->getSubExpr(); + + return E; } const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) { @@ -1509,7 +1541,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, // For non-assignment operations, we require that we can understand // both the LHS and RHS. if (LhsString.empty() || RhsString.empty() || - !BinaryOperator::isComparisonOp(Op)) + !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp) return nullptr; // Should we invert the strings if the LHS is not a variable name? diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 1858bfd89637e..776369be9dbaa 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -21,6 +21,9 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "static-analyzer-call-event" using namespace clang; using namespace ento; @@ -97,9 +100,6 @@ bool CallEvent::hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const { for (CallEvent::param_type_iterator I = param_type_begin(), E = param_type_end(); I != E && Idx < NumOfArgs; ++I, ++Idx) { - if (NumOfArgs <= Idx) - break; - // If the parameter is 0, it's harmless. if (getArgSVal(Idx).isZeroConstant()) continue; @@ -211,7 +211,9 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, } bool CallEvent::isCalled(const CallDescription &CD) const { - assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported"); + // FIXME: Add ObjC Message support. + if (getKind() == CE_ObjCMessage) + return false; if (!CD.IsLookupDone) { CD.IsLookupDone = true; CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); @@ -346,6 +348,30 @@ ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const { return D->parameters(); } +RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const { + const FunctionDecl *FD = getDecl(); + // Note that the AnalysisDeclContext will have the FunctionDecl with + // the definition (if one exists). + if (FD) { + AnalysisDeclContext *AD = + getLocationContext()->getAnalysisDeclContext()-> + getManager()->getContext(FD); + bool IsAutosynthesized; + Stmt* Body = AD->getBody(IsAutosynthesized); + DEBUG({ + if (IsAutosynthesized) + llvm::dbgs() << "Using autosynthesized body for " << FD->getName() + << "\n"; + }); + if (Body) { + const Decl* Decl = AD->getDecl(); + return RuntimeDefinition(Decl); + } + } + + return RuntimeDefinition(); +} + void AnyFunctionCall::getInitialStackFrameContents( const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index 548b06ef91fce..61cbf3854bb21 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -99,3 +99,35 @@ StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); } +/// Evaluate comparison and return true if it's known that condition is true +static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, + SVal RHSVal, ProgramStateRef State) { + if (LHSVal.isUnknownOrUndef()) + return false; + ProgramStateManager &Mgr = State->getStateManager(); + if (!LHSVal.getAs<NonLoc>()) { + LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), + LHSVal.castAs<Loc>()); + if (LHSVal.isUnknownOrUndef() || !LHSVal.getAs<NonLoc>()) + return false; + } + + SValBuilder &Bldr = Mgr.getSValBuilder(); + SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, + Bldr.getConditionType()); + if (Eval.isUnknownOrUndef()) + return false; + ProgramStateRef StTrue, StFalse; + std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); + return StTrue && !StFalse; +} + +bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { + DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); + return evalComparison(getSVal(E), BO_GE, V, getState()); +} + +bool CheckerContext::isNegative(const Expr *E) { + DefinedSVal V = getSValBuilder().makeIntVal(0, false); + return evalComparison(getSVal(E), BO_LT, V, getState()); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 4e2866c56f0ee..e2e9ddf5048eb 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -274,7 +274,8 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, assert(Loc.getAs<PostStmt>() || Loc.getAs<PostInitializer>() || Loc.getAs<PostImplicitCall>() || - Loc.getAs<CallExitEnd>()); + Loc.getAs<CallExitEnd>() || + Loc.getAs<LoopExit>()); HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred); break; } @@ -566,7 +567,8 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, // Do not create extra nodes. Move to the next CFG element. if (N->getLocation().getAs<PostInitializer>() || - N->getLocation().getAs<PostImplicitCall>()) { + N->getLocation().getAs<PostImplicitCall>()|| + N->getLocation().getAs<LoopExit>()) { WList->enqueue(N, Block, Idx+1); return; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp index e2cb52cb417e2..c6acb9d1851ce 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -13,7 +13,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/Support/raw_ostream.h" diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index eee5400fe1771..3be37e7ae301c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -17,6 +17,7 @@ #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" +#include "clang/Analysis/CFGStmtMap.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -27,6 +28,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" @@ -362,6 +364,9 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::TemporaryDtor: ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred); return; + case CFGElement::LoopExit: + ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred); + return; case CFGElement::LifetimeEnds: return; } @@ -507,6 +512,24 @@ void ExprEngine::ProcessStmt(const CFGStmt S, Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } +void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) { + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + S->getLocStart(), + "Error evaluating end of the loop"); + ExplodedNodeSet Dst; + Dst.Add(Pred); + NodeBuilder Bldr(Pred, Dst, *currBldrCtx); + ProgramStateRef NewState = Pred->getState(); + + if(AMgr.options.shouldUnrollLoops()) + NewState = processLoopEnd(S, NewState); + + LoopExit PP(S, Pred->getLocationContext()); + Bldr.generateNode(PP, NewState, Pred); + // Enqueue the new nodes onto the work list. + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); +} + void ExprEngine::ProcessInitializer(const CFGInitializer Init, ExplodedNode *Pred) { const CXXCtorInitializer *BMI = Init.getInitializer(); @@ -804,6 +827,21 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, } } +namespace { +class CollectReachableSymbolsCallback final : public SymbolVisitor { + InvalidatedSymbols Symbols; + +public: + explicit CollectReachableSymbolsCallback(ProgramStateRef State) {} + const InvalidatedSymbols &getSymbols() const { return Symbols; } + + bool VisitSymbol(SymbolRef Sym) override { + Symbols.insert(Sym); + return true; + } +}; +} // end anonymous namespace + void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &DstTop) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -1080,8 +1118,29 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, resultType, currBldrCtx->blockCount()); - ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); - Bldr2.generateNode(S, N, state); + ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); + + // Escape pointers passed into the list, unless it's an ObjC boxed + // expression which is not a boxable C structure. + if (!(isa<ObjCBoxedExpr>(Ex) && + !cast<ObjCBoxedExpr>(Ex)->getSubExpr() + ->getType()->isRecordType())) + for (auto Child : Ex->children()) { + assert(Child); + + SVal Val = State->getSVal(Child, LCtx); + + CollectReachableSymbolsCallback Scanner = + State->scanReachableSymbols<CollectReachableSymbolsCallback>( + Val); + const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); + + State = getCheckerManager().runCheckersForPointerEscape( + State, EscapedSymbols, + /*CallEvent*/ nullptr, PSK_EscapeOther, nullptr); + } + + Bldr2.generateNode(S, N, State); } getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); @@ -1091,7 +1150,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ArraySubscriptExprClass: Bldr.takeNodes(Pred); - VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst); + VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst); Bldr.addNodes(Dst); break; @@ -1497,6 +1556,25 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, NodeBuilderWithSinks &nodeBuilder, ExplodedNode *Pred) { PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); + // If we reach a loop which has a known bound (and meets + // other constraints) then consider completely unrolling it. + if(AMgr.options.shouldUnrollLoops()) { + unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath; + const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator(); + if (Term) { + ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(), + Pred, maxBlockVisitOnPath); + if (NewState != Pred->getState()) { + ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred); + if (!UpdatedNode) + return; + Pred = UpdatedNode; + } + } + // Is we are inside an unrolled loop then no need the check the counters. + if(isUnrolledState(Pred->getState())) + return; + } // If this block is terminated by a loop and it has already been visited the // maximum number of times, widen the loop. @@ -2030,10 +2108,12 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ProgramPoint::PostLValueKind); return; } - if (isa<FieldDecl>(D)) { + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) { // FIXME: Compute lvalue of field pointers-to-member. // Right now we just use a non-null void pointer, so that it gives proper // results in boolean contexts. + // FIXME: Maybe delegate this to the surrounding operator&. + // Note how this expression is lvalue, however pointer-to-member is NonLoc. SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, currBldrCtx->blockCount()); state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); @@ -2046,10 +2126,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } /// VisitArraySubscriptExpr - Transfer function for array accesses -void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, +void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNode *Pred, ExplodedNodeSet &Dst){ - const Expr *Base = A->getBase()->IgnoreParens(); const Expr *Idx = A->getIdx()->IgnoreParens(); @@ -2058,18 +2137,32 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNodeSet EvalSet; StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); - assert(A->isGLValue() || - (!AMgr.getLangOpts().CPlusPlus && - A->getType().isCForbiddenLValueType())); + + bool IsVectorType = A->getBase()->getType()->isVectorType(); + + // The "like" case is for situations where C standard prohibits the type to + // be an lvalue, e.g. taking the address of a subscript of an expression of + // type "void *". + bool IsGLValueLike = A->isGLValue() || + (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus); for (auto *Node : CheckerPreStmt) { const LocationContext *LCtx = Node->getLocationContext(); ProgramStateRef state = Node->getState(); - SVal V = state->getLValue(A->getType(), - state->getSVal(Idx, LCtx), - state->getSVal(Base, LCtx)); - Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + + if (IsGLValueLike) { + SVal V = state->getLValue(A->getType(), + state->getSVal(Idx, LCtx), + state->getSVal(Base, LCtx)); + Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, + ProgramPoint::PostLValueKind); + } else if (IsVectorType) { + // FIXME: non-glvalue vector reads are not modelled. + Bldr.generateNode(A, Node, state, nullptr); + } else { + llvm_unreachable("Array subscript should be an lValue when not \ +a vector and not a forbidden lvalue type"); + } } getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this); @@ -2195,21 +2288,6 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this); } -namespace { -class CollectReachableSymbolsCallback final : public SymbolVisitor { - InvalidatedSymbols Symbols; - -public: - CollectReachableSymbolsCallback(ProgramStateRef State) {} - const InvalidatedSymbols &getSymbols() const { return Symbols; } - - bool VisitSymbol(SymbolRef Sym) override { - Symbols.insert(Sym); - return true; - } -}; -} // end anonymous namespace - // A value escapes in three possible cases: // (1) We are binding to something that is not a memory region. // (2) We are binding to a MemrRegion that does not have stack storage. @@ -2666,6 +2744,12 @@ struct DOTGraphTraits<ExplodedNode*> : Out << "Epsilon Point"; break; + case ProgramPoint::LoopExitKind: { + LoopExit LE = Loc.castAs<LoopExit>(); + Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName(); + break; + } + case ProgramPoint::PreImplicitCallKind: { ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>(); Out << "PreCall: "; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 6f1e8391e67cf..3e7a50365f50c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -20,6 +20,24 @@ using namespace clang; using namespace ento; using llvm::APSInt; +/// \brief Optionally conjure and return a symbol for offset when processing +/// an expression \p Expression. +/// If \p Other is a location, conjure a symbol for \p Symbol +/// (offset) if it is unknown so that memory arithmetic always +/// results in an ElementRegion. +/// \p Count The number of times the current basic block was visited. +static SVal conjureOffsetSymbolOnLocation( + SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder, + unsigned Count, const LocationContext *LCtx) { + QualType Ty = Expression->getType(); + if (Other.getAs<Loc>() && + Ty->isIntegralOrEnumerationType() && + Symbol.isUnknown()) { + return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count); + } + return Symbol; +} + void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -63,24 +81,13 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx); if (B->isAdditiveOp()) { - // If one of the operands is a location, conjure a symbol for the other - // one (offset) if it's unknown so that memory arithmetic always - // results in an ElementRegion. // TODO: This can be removed after we enable history tracking with // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); - if (LeftV.getAs<Loc>() && - RHS->getType()->isIntegralOrEnumerationType() && - RightV.isUnknown()) { - RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(), - Count); - } - if (RightV.getAs<Loc>() && - LHS->getType()->isIntegralOrEnumerationType() && - LeftV.isUnknown()) { - LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(), - Count); - } + RightV = conjureOffsetSymbolOnLocation( + RightV, LeftV, RHS, svalBuilder, Count, LCtx); + LeftV = conjureOffsetSymbolOnLocation( + LeftV, RightV, LHS, svalBuilder, Count, LCtx); } // Although we don't yet model pointers-to-members, we do need to make @@ -92,12 +99,10 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); - if (Result.isUnknown()) { - Bldr.generateNode(B, *it, state); - continue; + if (!Result.isUnknown()) { + state = state->BindExpr(B, LCtx, Result); } - state = state->BindExpr(B, LCtx, Result); Bldr.generateNode(B, *it, state); continue; } @@ -530,7 +535,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, const Expr *Init = CL->getInitializer(); SVal V = State->getSVal(CL->getInitializer(), LCtx); - if (isa<CXXConstructExpr>(Init)) { + if (isa<CXXConstructExpr>(Init) || isa<CXXStdInitializerListExpr>(Init)) { // No work needed. Just pass the value up to this expression. } else { assert(isa<InitListExpr>(Init)); @@ -628,6 +633,16 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); + if (B->getType()->isVectorType()) { + // FIXME: We do not model vector arithmetic yet. When adding support for + // that, note that the CFG-based reasoning below does not apply, because + // logical operators on vectors are not short-circuit. Currently they are + // modeled as short-circuit in Clang CFG but this is incorrect. + // Do not set the value for the expression. It'd be UnknownVal by default. + Bldr.generateNode(B, Pred, state); + return; + } + ExplodedNode *N = Pred; while (!N->getLocation().getAs<BlockEntrance>()) { ProgramPoint P = N->getLocation(); @@ -1028,7 +1043,14 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Propagate unknown and undefined values. if (V2_untested.isUnknownOrUndef()) { - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested)); + state = state->BindExpr(U, LCtx, V2_untested); + + // Perform the store, so that the uninitialized value detection happens. + Bldr.takeNodes(*I); + ExplodedNodeSet Dst3; + evalStore(Dst3, U, U, *I, state, loc, V2_untested); + Bldr.addNodes(Dst3); + continue; } DefinedSVal V2 = V2_untested.castAs<DefinedSVal>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index f0f6dd2e43e78..9b820e81e374f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -44,8 +44,12 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { bool createdDir, noDir; const Preprocessor &PP; AnalyzerOptions &AnalyzerOpts; + const bool SupportsCrossFileDiagnostics; public: - HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& prefix, + const Preprocessor &pp, + bool supportsMultipleFiles); ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } @@ -56,6 +60,10 @@ public: return "HTMLDiagnostics"; } + bool supportsCrossFileDiagnostics() const override { + return SupportsCrossFileDiagnostics; + } + unsigned ProcessMacroPiece(raw_ostream &os, const PathDiagnosticMacroPiece& P, unsigned num); @@ -69,21 +77,47 @@ public: void ReportDiag(const PathDiagnostic& D, FilesMade *filesMade); + + // Generate the full HTML report + std::string GenerateHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, + const char *declName); + + // Add HTML header/footers to file specified by FID + void FinalizeHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, + FileID FID, const FileEntry *Entry, const char *declName); + + // Rewrite the file specified by FID with HTML formatting. + void RewriteFile(Rewriter &R, const SourceManager& SMgr, + const PathPieces& path, FileID FID); }; } // end anonymous namespace HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, - const Preprocessor &pp) - : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { -} + const Preprocessor &pp, + bool supportsMultipleFiles) + : Directory(prefix), + createdDir(false), + noDir(false), + PP(pp), + AnalyzerOpts(AnalyzerOpts), + SupportsCrossFileDiagnostics(supportsMultipleFiles) {} void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string& prefix, const Preprocessor &PP) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true)); +} + +void ento::createHTMLSingleFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP) { + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false)); } //===----------------------------------------------------------------------===// @@ -121,24 +155,24 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // First flatten out the entire path to make it easier to use. PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false); - // The path as already been prechecked that all parts of the path are - // from the same file and that it is non-empty. - const SourceManager &SMgr = path.front()->getLocation().getManager(); + // The path as already been prechecked that the path is non-empty. assert(!path.empty()); - FileID FID = - path.front()->getLocation().asLocation().getExpansionLoc().getFileID(); - assert(FID.isValid()); + const SourceManager &SMgr = path.front()->getLocation().getManager(); // Create a new rewriter to generate HTML. Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts()); + // The file for the first path element is considered the main report file, it + // will usually be equivalent to SMgr.getMainFileID(); however, it might be a + // header when -analyzer-opt-analyze-headers is used. + FileID ReportFile = path.front()->getLocation().asLocation().getExpansionLoc().getFileID(); + // Get the function/method name SmallString<128> declName("unknown"); int offsetDecl = 0; if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { - if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) declName = ND->getDeclName().getAsString(); - } if (const Stmt *Body = DeclWithIssue->getBody()) { // Retrieve the relative position of the declaration which will be used @@ -151,49 +185,144 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, } } - // Process the path. - // Maintain the counts of extra note pieces separately. - unsigned TotalPieces = path.size(); - unsigned TotalNotePieces = - std::count_if(path.begin(), path.end(), - [](const std::shared_ptr<PathDiagnosticPiece> &p) { - return isa<PathDiagnosticNotePiece>(*p); - }); + std::string report = GenerateHTML(D, R, SMgr, path, declName.c_str()); + if (report.empty()) { + llvm::errs() << "warning: no diagnostics generated for main file.\n"; + return; + } - unsigned TotalRegularPieces = TotalPieces - TotalNotePieces; - unsigned NumRegularPieces = TotalRegularPieces; - unsigned NumNotePieces = TotalNotePieces; + // Create a path for the target HTML file. + int FD; + SmallString<128> Model, ResultPath; - for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { - if (isa<PathDiagnosticNotePiece>(I->get())) { - // This adds diagnostic bubbles, but not navigation. - // Navigation through note pieces would be added later, - // as a separate pass through the piece list. - HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces); - --NumNotePieces; - } else { - HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces); - --NumRegularPieces; - } + if (!AnalyzerOpts.shouldWriteStableReportFilename()) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + if (std::error_code EC = + llvm::sys::fs::make_absolute(Model)) { + llvm::errs() << "warning: could not make '" << Model + << "' absolute: " << EC.message() << '\n'; + return; + } + if (std::error_code EC = + llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) { + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + return; + } + + } else { + int i = 1; + std::error_code EC; + do { + // Find a filename which is not already used + const FileEntry* Entry = SMgr.getFileEntryForID(ReportFile); + std::stringstream filename; + Model = ""; + filename << "report-" + << llvm::sys::path::filename(Entry->getName()).str() + << "-" << declName.c_str() + << "-" << offsetDecl + << "-" << i << ".html"; + llvm::sys::path::append(Model, Directory, + filename.str()); + EC = llvm::sys::fs::openFileForWrite(Model, + FD, + llvm::sys::fs::F_RW | + llvm::sys::fs::F_Excl); + if (EC && EC != llvm::errc::file_exists) { + llvm::errs() << "warning: could not create file '" << Model + << "': " << EC.message() << '\n'; + return; + } + i++; + } while (EC); } - // Add line numbers, header, footer, etc. + llvm::raw_fd_ostream os(FD, true); - // unsigned FID = R.getSourceMgr().getMainFileID(); - html::EscapeText(R, FID); - html::AddLineNumbers(R, FID); + if (filesMade) + filesMade->addDiagnostic(D, getName(), + llvm::sys::path::filename(ResultPath)); - // If we have a preprocessor, relex the file and syntax highlight. - // We might not have a preprocessor if we come from a deserialized AST file, - // for example. + // Emit the HTML to disk. + os << report; +} - html::SyntaxHighlight(R, FID, PP); - html::HighlightMacros(R, FID, PP); +std::string HTMLDiagnostics::GenerateHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, const char *declName) { + + // Rewrite source files as HTML for every new file the path crosses + std::vector<FileID> FileIDs; + for (auto I : path) { + FileID FID = I->getLocation().asLocation().getExpansionLoc().getFileID(); + if (std::find(FileIDs.begin(), FileIDs.end(), FID) != FileIDs.end()) + continue; + + FileIDs.push_back(FID); + RewriteFile(R, SMgr, path, FID); + } + + if (SupportsCrossFileDiagnostics && FileIDs.size() > 1) { + // Prefix file names, anchor tags, and nav cursors to every file + for (auto I = FileIDs.begin(), E = FileIDs.end(); I != E; I++) { + std::string s; + llvm::raw_string_ostream os(s); + + if (I != FileIDs.begin()) + os << "<hr class=divider>\n"; + + os << "<div id=File" << I->getHashValue() << ">\n"; - // Get the full directory name of the analyzed file. + // Left nav arrow + if (I != FileIDs.begin()) + os << "<div class=FileNav><a href=\"#File" << (I - 1)->getHashValue() + << "\">←</a></div>"; - const FileEntry* Entry = SMgr.getFileEntryForID(FID); + os << "<h4 class=FileName>" << SMgr.getFileEntryForID(*I)->getName() + << "</h4>\n"; + // Right nav arrow + if (I + 1 != E) + os << "<div class=FileNav><a href=\"#File" << (I + 1)->getHashValue() + << "\">→</a></div>"; + + os << "</div>\n"; + + R.InsertTextBefore(SMgr.getLocForStartOfFile(*I), os.str()); + } + + // Append files to the main report file in the order they appear in the path + for (auto I : llvm::make_range(FileIDs.begin() + 1, FileIDs.end())) { + std::string s; + llvm::raw_string_ostream os(s); + + const RewriteBuffer *Buf = R.getRewriteBufferFor(I); + for (auto BI : *Buf) + os << BI; + + R.InsertTextAfter(SMgr.getLocForEndOfFile(FileIDs[0]), os.str()); + } + } + + const RewriteBuffer *Buf = R.getRewriteBufferFor(FileIDs[0]); + if (!Buf) + return ""; + + // Add CSS, header, and footer. + const FileEntry* Entry = SMgr.getFileEntryForID(FileIDs[0]); + FinalizeHTML(D, R, SMgr, path, FileIDs[0], Entry, declName); + + std::string file; + llvm::raw_string_ostream os(file); + for (auto BI : *Buf) + os << BI; + + return os.str(); +} + +void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, FileID FID, + const FileEntry *Entry, const char *declName) { // This is a cludge; basically we want to append either the full // working directory if we have no directory information. This is // a work in progress. @@ -306,73 +435,48 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); } - // Add CSS, header, and footer. - html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName()); +} - // Get the rewrite buffer. - const RewriteBuffer *Buf = R.getRewriteBufferFor(FID); - - if (!Buf) { - llvm::errs() << "warning: no diagnostics generated for main file.\n"; - return; - } - - // Create a path for the target HTML file. - int FD; - SmallString<128> Model, ResultPath; +void HTMLDiagnostics::RewriteFile(Rewriter &R, const SourceManager& SMgr, + const PathPieces& path, FileID FID) { + // Process the path. + // Maintain the counts of extra note pieces separately. + unsigned TotalPieces = path.size(); + unsigned TotalNotePieces = + std::count_if(path.begin(), path.end(), + [](const std::shared_ptr<PathDiagnosticPiece> &p) { + return isa<PathDiagnosticNotePiece>(*p); + }); - if (!AnalyzerOpts.shouldWriteStableReportFilename()) { - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (std::error_code EC = - llvm::sys::fs::make_absolute(Model)) { - llvm::errs() << "warning: could not make '" << Model - << "' absolute: " << EC.message() << '\n'; - return; - } - if (std::error_code EC = - llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; - } + unsigned TotalRegularPieces = TotalPieces - TotalNotePieces; + unsigned NumRegularPieces = TotalRegularPieces; + unsigned NumNotePieces = TotalNotePieces; - } else { - int i = 1; - std::error_code EC; - do { - // Find a filename which is not already used - std::stringstream filename; - Model = ""; - filename << "report-" - << llvm::sys::path::filename(Entry->getName()).str() - << "-" << declName.c_str() - << "-" << offsetDecl - << "-" << i << ".html"; - llvm::sys::path::append(Model, Directory, - filename.str()); - EC = llvm::sys::fs::openFileForWrite(Model, - FD, - llvm::sys::fs::F_RW | - llvm::sys::fs::F_Excl); - if (EC && EC != llvm::errc::file_exists) { - llvm::errs() << "warning: could not create file '" << Model - << "': " << EC.message() << '\n'; - return; - } - i++; - } while (EC); + for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { + if (isa<PathDiagnosticNotePiece>(I->get())) { + // This adds diagnostic bubbles, but not navigation. + // Navigation through note pieces would be added later, + // as a separate pass through the piece list. + HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces); + --NumNotePieces; + } else { + HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces); + --NumRegularPieces; + } } - llvm::raw_fd_ostream os(FD, true); + // Add line numbers, header, footer, etc. - if (filesMade) - filesMade->addDiagnostic(D, getName(), - llvm::sys::path::filename(ResultPath)); + html::EscapeText(R, FID); + html::AddLineNumbers(R, FID); - // Emit the HTML to disk. - for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) - os << *I; + // If we have a preprocessor, relex the file and syntax highlight. + // We might not have a preprocessor if we come from a deserialized AST file, + // for example. + + html::SyntaxHighlight(R, FID, PP); + html::HighlightMacros(R, FID, PP); } void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/IssueHash.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/IssueHash.cpp index abdea88b1db6f..274ebe7a941bc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/IssueHash.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/IssueHash.cpp @@ -33,6 +33,13 @@ static std::string GetSignature(const FunctionDecl *Target) { return ""; std::string Signature; + // When a flow sensitive bug happens in templated code we should not generate + // distinct hash value for every instantiation. Use the signature from the + // primary template. + if (const FunctionDecl *InstantiatedFrom = + Target->getTemplateInstantiationPattern()) + Target = InstantiatedFrom; + if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) && !isa<CXXConversionDecl>(Target)) Signature.append(Target->getReturnType().getAsString()).append(" "); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp new file mode 100644 index 0000000000000..a8c4b05cea131 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -0,0 +1,294 @@ +//===--- LoopUnrolling.cpp - Unroll loops -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This file contains functions which are used to decide if a loop worth to be +/// unrolled. Moreover, these functions manages the stack of loop which is +/// tracked by the ProgramState. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h" + +using namespace clang; +using namespace ento; +using namespace clang::ast_matchers; + +static const int MAXIMUM_STEP_UNROLLED = 128; + +struct LoopState { +private: + enum Kind { Normal, Unrolled } K; + const Stmt *LoopStmt; + const LocationContext *LCtx; + unsigned maxStep; + LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N) + : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {} + +public: + static LoopState getNormal(const Stmt *S, const LocationContext *L, + unsigned N) { + return LoopState(Normal, S, L, N); + } + static LoopState getUnrolled(const Stmt *S, const LocationContext *L, + unsigned N) { + return LoopState(Unrolled, S, L, N); + } + bool isUnrolled() const { return K == Unrolled; } + unsigned getMaxStep() const { return maxStep; } + const Stmt *getLoopStmt() const { return LoopStmt; } + const LocationContext *getLocationContext() const { return LCtx; } + bool operator==(const LoopState &X) const { + return K == X.K && LoopStmt == X.LoopStmt; + } + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + ID.AddPointer(LoopStmt); + ID.AddPointer(LCtx); + ID.AddInteger(maxStep); + } +}; + +// The tracked stack of loops. The stack indicates that which loops the +// simulated element contained by. The loops are marked depending if we decided +// to unroll them. +// TODO: The loop stack should not need to be in the program state since it is +// lexical in nature. Instead, the stack of loops should be tracked in the +// LocationContext. +REGISTER_LIST_WITH_PROGRAMSTATE(LoopStack, LoopState) + +namespace clang { +namespace ento { + +static bool isLoopStmt(const Stmt *S) { + return S && (isa<ForStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S)); +} + +ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) { + auto LS = State->get<LoopStack>(); + if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt) + State = State->set<LoopStack>(LS.getTail()); + return State; +} + +static internal::Matcher<Stmt> simpleCondition(StringRef BindName) { + return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"), + hasOperatorName("<="), hasOperatorName(">="), + hasOperatorName("!=")), + hasEitherOperand(ignoringParenImpCasts(declRefExpr( + to(varDecl(hasType(isInteger())).bind(BindName))))), + hasEitherOperand(ignoringParenImpCasts( + integerLiteral().bind("boundNum")))) + .bind("conditionOperator"); +} + +static internal::Matcher<Stmt> +changeIntBoundNode(internal::Matcher<Decl> VarNodeMatcher) { + return anyOf( + unaryOperator(anyOf(hasOperatorName("--"), hasOperatorName("++")), + hasUnaryOperand(ignoringParenImpCasts( + declRefExpr(to(varDecl(VarNodeMatcher)))))), + binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="), + hasOperatorName("/="), hasOperatorName("*="), + hasOperatorName("-=")), + hasLHS(ignoringParenImpCasts( + declRefExpr(to(varDecl(VarNodeMatcher))))))); +} + +static internal::Matcher<Stmt> +callByRef(internal::Matcher<Decl> VarNodeMatcher) { + return callExpr(forEachArgumentWithParam( + declRefExpr(to(varDecl(VarNodeMatcher))), + parmVarDecl(hasType(references(qualType(unless(isConstQualified()))))))); +} + +static internal::Matcher<Stmt> +assignedToRef(internal::Matcher<Decl> VarNodeMatcher) { + return declStmt(hasDescendant(varDecl( + allOf(hasType(referenceType()), + hasInitializer(anyOf( + initListExpr(has(declRefExpr(to(varDecl(VarNodeMatcher))))), + declRefExpr(to(varDecl(VarNodeMatcher))))))))); +} + +static internal::Matcher<Stmt> +getAddrTo(internal::Matcher<Decl> VarNodeMatcher) { + return unaryOperator( + hasOperatorName("&"), + hasUnaryOperand(declRefExpr(hasDeclaration(VarNodeMatcher)))); +} + +static internal::Matcher<Stmt> hasSuspiciousStmt(StringRef NodeName) { + return hasDescendant(stmt( + anyOf(gotoStmt(), switchStmt(), returnStmt(), + // Escaping and not known mutation of the loop counter is handled + // by exclusion of assigning and address-of operators and + // pass-by-ref function calls on the loop counter from the body. + changeIntBoundNode(equalsBoundNode(NodeName)), + callByRef(equalsBoundNode(NodeName)), + getAddrTo(equalsBoundNode(NodeName)), + assignedToRef(equalsBoundNode(NodeName))))); +} + +static internal::Matcher<Stmt> forLoopMatcher() { + return forStmt( + hasCondition(simpleCondition("initVarName")), + // Initialization should match the form: 'int i = 6' or 'i = 42'. + hasLoopInit(anyOf( + declStmt(hasSingleDecl(varDecl( + allOf(hasInitializer(integerLiteral().bind("initNum")), + equalsBoundNode("initVarName"))))), + binaryOperator(hasLHS(declRefExpr(to( + varDecl(equalsBoundNode("initVarName"))))), + hasRHS(integerLiteral().bind("initNum"))))), + // Incrementation should be a simple increment or decrement + // operator call. + hasIncrement(unaryOperator( + anyOf(hasOperatorName("++"), hasOperatorName("--")), + hasUnaryOperand(declRefExpr( + to(varDecl(allOf(equalsBoundNode("initVarName"), + hasType(isInteger())))))))), + unless(hasBody(hasSuspiciousStmt("initVarName")))).bind("forLoop"); +} + +static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) { + // Global variables assumed as escaped variables. + if (VD->hasGlobalStorage()) + return true; + + while (!N->pred_empty()) { + const Stmt *S = PathDiagnosticLocation::getStmt(N); + if (!S) { + N = N->getFirstPred(); + continue; + } + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + for (const Decl *D : DS->decls()) { + // Once we reach the declaration of the VD we can return. + if (D->getCanonicalDecl() == VD) + return false; + } + } + // Check the usage of the pass-by-ref function calls and adress-of operator + // on VD and reference initialized by VD. + ASTContext &ASTCtx = + N->getLocationContext()->getAnalysisDeclContext()->getASTContext(); + auto Match = + match(stmt(anyOf(callByRef(equalsNode(VD)), getAddrTo(equalsNode(VD)), + assignedToRef(equalsNode(VD)))), + *S, ASTCtx); + if (!Match.empty()) + return true; + + N = N->getFirstPred(); + } + llvm_unreachable("Reached root without finding the declaration of VD"); +} + +bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx, + ExplodedNode *Pred, unsigned &maxStep) { + + if (!isLoopStmt(LoopStmt)) + return false; + + // TODO: Match the cases where the bound is not a concrete literal but an + // integer with known value + auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx); + if (Matches.empty()) + return false; + + auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName"); + llvm::APInt BoundNum = + Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue(); + llvm::APInt InitNum = + Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue(); + auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator"); + if (InitNum.getBitWidth() != BoundNum.getBitWidth()) { + InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth()); + BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth()); + } + + if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE) + maxStep = (BoundNum - InitNum + 1).abs().getZExtValue(); + else + maxStep = (BoundNum - InitNum).abs().getZExtValue(); + + // Check if the counter of the loop is not escaped before. + return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred); +} + +bool madeNewBranch(ExplodedNode *N, const Stmt *LoopStmt) { + const Stmt *S = nullptr; + while (!N->pred_empty()) { + if (N->succ_size() > 1) + return true; + + ProgramPoint P = N->getLocation(); + if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) + S = BE->getBlock()->getTerminator(); + + if (S == LoopStmt) + return false; + + N = N->getFirstPred(); + } + + llvm_unreachable("Reached root without encountering the previous step"); +} + +// updateLoopStack is called on every basic block, therefore it needs to be fast +ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx, + ExplodedNode *Pred, unsigned maxVisitOnPath) { + auto State = Pred->getState(); + auto LCtx = Pred->getLocationContext(); + + if (!isLoopStmt(LoopStmt)) + return State; + + auto LS = State->get<LoopStack>(); + if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() && + LCtx == LS.getHead().getLocationContext()) { + if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) { + State = State->set<LoopStack>(LS.getTail()); + State = State->add<LoopStack>( + LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath)); + } + return State; + } + unsigned maxStep; + if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, maxStep)) { + State = State->add<LoopStack>( + LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath)); + return State; + } + + unsigned outerStep = (LS.isEmpty() ? 1 : LS.getHead().getMaxStep()); + + unsigned innerMaxStep = maxStep * outerStep; + if (innerMaxStep > MAXIMUM_STEP_UNROLLED) + State = State->add<LoopStack>( + LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath)); + else + State = State->add<LoopStack>( + LoopState::getUnrolled(LoopStmt, LCtx, innerMaxStep)); + return State; +} + +bool isUnrolledState(ProgramStateRef State) { + auto LS = State->get<LoopStack>(); + if (LS.isEmpty() || !LS.getHead().isUnrolled()) + return false; + return true; +} +} +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 7bc186d5b9941..cb8ba6de36265 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -18,7 +18,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" @@ -472,6 +472,8 @@ void ObjCStringRegion::dumpToStream(raw_ostream &os) const { } void SymbolicRegion::dumpToStream(raw_ostream &os) const { + if (isa<HeapSpaceRegion>(getSuperRegion())) + os << "Heap"; os << "SymRegion{" << sym << '}'; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index d91786f749198..669748c0127ab 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -578,8 +578,10 @@ getLocationForCaller(const StackFrameContext *SFC, } case CFGElement::TemporaryDtor: case CFGElement::NewAllocator: - case CFGElement::LifetimeEnds: llvm_unreachable("not yet implemented!"); + case CFGElement::LifetimeEnds: + case CFGElement::LoopExit: + llvm_unreachable("CFGElement kind should not be on callsite!"); } llvm_unreachable("Unknown CFGElement kind"); @@ -688,6 +690,15 @@ PathDiagnosticLocation::create(const ProgramPoint& P, return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); + } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { + CFGElement BlockFront = BE->getBlock()->front(); + if (auto StmtElt = BlockFront.getAs<CFGStmt>()) { + return PathDiagnosticLocation(StmtElt->getStmt()->getLocStart(), SMng); + } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) { + return PathDiagnosticLocation( + NewAllocElt->getAllocatorExpr()->getLocStart(), SMng); + } + llvm_unreachable("Unexpected CFG element at front of block"); } else { llvm_unreachable("Unexpected ProgramPoint"); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h index e7cc23ca82345..4bb694819c2ab 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h @@ -10,7 +10,7 @@ #ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H #define LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" namespace clang { namespace ento { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 3215c3ccd21e9..5b6b7339697f1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -260,7 +260,9 @@ SVal ProgramState::getSVal(Loc location, QualType T) const { // be a constant value, use that value instead to lessen the burden // on later analysis stages (so we have less symbolic values to reason // about). - if (!T.isNull()) { + // We only go into this branch if we can convert the APSInt value we have + // to the type of T, which is not always the case (e.g. for void). + if (!T.isNull() && (T->isIntegralOrEnumerationType() || Loc::isLocType(T))) { if (SymbolRef sym = V.getAsSymbol()) { if (const llvm::APSInt *Int = getStateManager() .getConstraintManager() diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index e0ad2d8ad45c2..5a4031c0b4a5f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -354,7 +354,8 @@ private: RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Int, const llvm::APSInt &Adjustment); - RangeSet getSymLERange(const RangeSet &RS, const llvm::APSInt &Int, + RangeSet getSymLERange(llvm::function_ref<RangeSet()> RS, + const llvm::APSInt &Int, const llvm::APSInt &Adjustment); RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Int, @@ -395,7 +396,9 @@ bool RangeConstraintManager::canReasonAbout(SVal X) const { } if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) { - if (BinaryOperator::isComparisonOp(SSE->getOpcode())) { + // FIXME: Handle <=> here. + if (BinaryOperator::isEqualityOp(SSE->getOpcode()) || + BinaryOperator::isRelationalOp(SSE->getOpcode())) { // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc. if (Loc::isLocType(SSE->getLHS()->getType())) { assert(Loc::isLocType(SSE->getRHS()->getType())); @@ -460,6 +463,53 @@ RangeConstraintManager::removeDeadBindings(ProgramStateRef State, return Changed ? State->set<ConstraintRange>(CR) : State; } +/// Return a range set subtracting zero from \p Domain. +static RangeSet assumeNonZero( + BasicValueFactory &BV, + RangeSet::Factory &F, + SymbolRef Sym, + RangeSet Domain) { + APSIntType IntType = BV.getAPSIntType(Sym->getType()); + return Domain.Intersect(BV, F, ++IntType.getZeroValue(), + --IntType.getZeroValue()); +} + +/// \brief Apply implicit constraints for bitwise OR- and AND-. +/// For unsigned types, bitwise OR with a constant always returns +/// a value greater-or-equal than the constant, and bitwise AND +/// returns a value less-or-equal then the constant. +/// +/// Pattern matches the expression \p Sym against those rule, +/// and applies the required constraints. +/// \p Input Previously established expression range set +static RangeSet applyBitwiseConstraints( + BasicValueFactory &BV, + RangeSet::Factory &F, + RangeSet Input, + const SymIntExpr* SIE) { + QualType T = SIE->getType(); + bool IsUnsigned = T->isUnsignedIntegerType(); + const llvm::APSInt &RHS = SIE->getRHS(); + const llvm::APSInt &Zero = BV.getAPSIntType(T).getZeroValue(); + BinaryOperator::Opcode Operator = SIE->getOpcode(); + + // For unsigned types, the output of bitwise-or is bigger-or-equal than RHS. + if (Operator == BO_Or && IsUnsigned) + return Input.Intersect(BV, F, RHS, BV.getMaxValue(T)); + + // Bitwise-or with a non-zero constant is always non-zero. + if (Operator == BO_Or && RHS != Zero) + return assumeNonZero(BV, F, SIE, Input); + + // For unsigned types, or positive RHS, + // bitwise-and output is always smaller-or-equal than RHS (assuming two's + // complement representation of signed types). + if (Operator == BO_And && (IsUnsigned || RHS >= Zero)) + return Input.Intersect(BV, F, BV.getMinValue(T), RHS); + + return Input; +} + RangeSet RangeConstraintManager::getRange(ProgramStateRef State, SymbolRef Sym) { if (ConstraintRangeTy::data_type *V = State->get<ConstraintRange>(Sym)) @@ -472,12 +522,13 @@ RangeSet RangeConstraintManager::getRange(ProgramStateRef State, RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T)); - // Special case: references are known to be non-zero. - if (T->isReferenceType()) { - APSIntType IntType = BV.getAPSIntType(T); - Result = Result.Intersect(BV, F, ++IntType.getZeroValue(), - --IntType.getZeroValue()); - } + // References are known to be non-zero. + if (T->isReferenceType()) + return assumeNonZero(BV, F, Sym, Result); + + // Known constraints on ranges of bitwise expressions. + if (const SymIntExpr* SIE = dyn_cast<SymIntExpr>(Sym)) + return applyBitwiseConstraints(BV, F, Result, SIE); return Result; } @@ -637,9 +688,10 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); } -RangeSet RangeConstraintManager::getSymLERange(const RangeSet &RS, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment) { +RangeSet RangeConstraintManager::getSymLERange( + llvm::function_ref<RangeSet()> RS, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment) { // Before we do any real work, see if the value can even show up. APSIntType AdjustmentType(Adjustment); switch (AdjustmentType.testInRange(Int, true)) { @@ -648,48 +700,27 @@ RangeSet RangeConstraintManager::getSymLERange(const RangeSet &RS, case APSIntType::RTR_Within: break; case APSIntType::RTR_Above: - return RS; + return RS(); } // Special case for Int == Max. This is always feasible. llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); llvm::APSInt Max = AdjustmentType.getMaxValue(); if (ComparisonVal == Max) - return RS; + return RS(); llvm::APSInt Min = AdjustmentType.getMinValue(); llvm::APSInt Lower = Min - Adjustment; llvm::APSInt Upper = ComparisonVal - Adjustment; - return RS.Intersect(getBasicVals(), F, Lower, Upper); + return RS().Intersect(getBasicVals(), F, Lower, Upper); } RangeSet RangeConstraintManager::getSymLERange(ProgramStateRef St, SymbolRef Sym, const llvm::APSInt &Int, const llvm::APSInt &Adjustment) { - // Before we do any real work, see if the value can even show up. - APSIntType AdjustmentType(Adjustment); - switch (AdjustmentType.testInRange(Int, true)) { - case APSIntType::RTR_Below: - return F.getEmptySet(); - case APSIntType::RTR_Within: - break; - case APSIntType::RTR_Above: - return getRange(St, Sym); - } - - // Special case for Int == Max. This is always feasible. - llvm::APSInt ComparisonVal = AdjustmentType.convert(Int); - llvm::APSInt Max = AdjustmentType.getMaxValue(); - if (ComparisonVal == Max) - return getRange(St, Sym); - - llvm::APSInt Min = AdjustmentType.getMinValue(); - llvm::APSInt Lower = Min - Adjustment; - llvm::APSInt Upper = ComparisonVal - Adjustment; - - return getRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); + return getSymLERange([&] { return getRange(St, Sym); }, Int, Adjustment); } ProgramStateRef @@ -706,8 +737,8 @@ ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange( RangeSet New = getSymGERange(State, Sym, From, Adjustment); if (New.isEmpty()) return nullptr; - New = getSymLERange(New, To, Adjustment); - return New.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, New); + RangeSet Out = getSymLERange([&] { return New; }, To, Adjustment); + return Out.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, Out); } ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange( diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp index 1304116f4974b..55ff15806efe6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp @@ -33,7 +33,7 @@ ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State, // We can only simplify expressions whose RHS is an integer. BinaryOperator::Opcode op = SIE->getOpcode(); - if (BinaryOperator::isComparisonOp(op)) { + if (BinaryOperator::isComparisonOp(op) && op != BO_Cmp) { if (!Assumption) op = BinaryOperator::negateComparisonOp(op); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 11902f66df914..7f2a481c6b0d3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -18,7 +18,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -134,7 +134,9 @@ namespace llvm { }; } // end llvm namespace +#ifndef NDEBUG LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; } +#endif //===----------------------------------------------------------------------===// // Actual Store type. @@ -1393,17 +1395,17 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T) return UnknownVal(); } - if (isa<AllocaRegion>(MR) || - isa<SymbolicRegion>(MR) || - isa<CodeTextRegion>(MR)) { + if (!isa<TypedValueRegion>(MR)) { if (T.isNull()) { if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR)) - T = TR->getLocationType(); - else { - const SymbolicRegion *SR = cast<SymbolicRegion>(MR); - T = SR->getSymbol()->getType(); - } + T = TR->getLocationType()->getPointeeType(); + else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) + T = SR->getSymbol()->getType()->getPointeeType(); + else if (isa<AllocaRegion>(MR)) + T = Ctx.VoidTy; } + assert(!T.isNull() && "Unable to auto-detect binding type!"); + assert(!T->isVoidType() && "Attempting to dereference a void pointer!"); MR = GetElementZeroRegion(cast<SubRegion>(MR), T); } @@ -1859,11 +1861,18 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, return svalBuilder.getRegionValueSymbolVal(R); // Is 'VD' declared constant? If so, retrieve the constant value. - if (VD->getType().isConstQualified()) - if (const Expr *Init = VD->getInit()) + if (VD->getType().isConstQualified()) { + if (const Expr *Init = VD->getInit()) { if (Optional<SVal> V = svalBuilder.getConstantVal(Init)) return *V; + // If the variable is const qualified and has an initializer but + // we couldn't evaluate initializer to a value, treat the value as + // unknown. + return UnknownVal(); + } + } + // This must come after the check for constants because closure-captured // constant variables may appear in UnknownSpaceRegion. if (isa<UnknownSpaceRegion>(MS)) @@ -2085,15 +2094,12 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B, if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT)) Size = CAT->getSize().getZExtValue(); - // Check if the init expr is a string literal. + // Check if the init expr is a literal. If so, bind the rvalue instead. + // FIXME: It's not responsibility of the Store to transform this lvalue + // to rvalue. ExprEngine or maybe even CFG should do this before binding. if (Optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) { - const StringRegion *S = cast<StringRegion>(MRV->getRegion()); - - // Treat the string as a lazy compound value. - StoreRef store(B.asStore(), *this); - nonloc::LazyCompoundVal LCV = svalBuilder.makeLazyCompoundVal(store, S) - .castAs<nonloc::LazyCompoundVal>(); - return bindAggregate(B, R, LCV); + SVal V = getBinding(B.asStore(), *MRV, R->getValueType()); + return bindAggregate(B, R, V); } // Handle lazy compound values. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp index 9f2af3ffa7097..a83421426a131 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -113,12 +113,12 @@ SymbolRef SVal::getLocSymbolInBase() const { /// Casts are ignored during lookup. /// \param IncludeBaseRegions The boolean that controls whether the search /// should continue to the base regions if the region is not symbolic. -SymbolRef SVal::getAsSymbol(bool IncludeBaseRegion) const { +SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) return X->getSymbol(); - return getAsLocSymbol(IncludeBaseRegion); + return getAsLocSymbol(IncludeBaseRegions); } /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index f09f9696f5add..94d29d5a6ba32 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -360,10 +360,18 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: + // FIXME: at the moment the implementation + // of modeling "pointers as integers" is not complete. + if (!BinaryOperator::isComparisonOp(op)) + return UnknownVal(); return evalBinOpLL(state, op, lhsL, rhs.castAs<nonloc::LocAsInteger>().getLoc(), resultTy); case nonloc::ConcreteIntKind: { + // FIXME: at the moment the implementation + // of modeling "pointers as integers" is not complete. + if (!BinaryOperator::isComparisonOp(op)) + return UnknownVal(); // Transform the integer into a location and compare. // FIXME: This only makes sense for comparisons. If we want to, say, // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it, @@ -671,7 +679,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, if (SymbolRef rSym = rhs.getAsLocSymbol()) { // We can only build expressions with symbols on the left, // so we need a reversible operator. - if (!BinaryOperator::isComparisonOp(op)) + if (!BinaryOperator::isComparisonOp(op) || op == BO_Cmp) return UnknownVal(); const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); @@ -718,9 +726,11 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) { // If one of the operands is a symbol and the other is a constant, // build an expression for use by the constraint manager. - if (SymbolRef lSym = lhs.getAsLocSymbol(true)) - return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy); - + if (SymbolRef lSym = lhs.getAsLocSymbol(true)) { + if (BinaryOperator::isComparisonOp(op)) + return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy); + return UnknownVal(); + } // Special case comparisons to NULL. // This must come after the test if the LHS is a symbol, which is used to // build constraints. The address of any non-symbolic region is guaranteed @@ -912,6 +922,10 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, if (rhs.isZeroConstant()) return lhs; + // Perserve the null pointer so that it can be found by the DerefChecker. + if (lhs.isZeroConstant()) + return lhs; + // We are dealing with pointer arithmetic. // Handle pointer arithmetic on constant values. @@ -927,6 +941,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, // Offset the increment by the pointer size. llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true); + QualType pointeeType = resultTy->getPointeeType(); + Multiplicand = getContext().getTypeSizeInChars(pointeeType).getQuantity(); rightI *= Multiplicand; // Compute the adjusted pointer. @@ -1016,7 +1032,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { SVB.getKnownValue(State, nonloc::SymbolVal(S))) return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I) : (SVal)SVB.makeIntVal(*I); - return nonloc::SymbolVal(S); + return Loc::isLocType(S->getType()) ? (SVal)SVB.makeLoc(S) + : nonloc::SymbolVal(S); } // TODO: Support SymbolCast. Support IntSymExpr when/if we actually diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp index 1af49f68cc055..173fdd8d0056b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -440,7 +440,10 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, // value. See also the similar FIXME in getLValueFieldOrIvar(). if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>()) return Base; - + + if (Base.getAs<loc::GotoLabel>()) + return UnknownVal(); + const SubRegion *BaseRegion = Base.castAs<loc::MemRegionVal>().getRegionAs<SubRegion>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index 4be85661b645f..f2d5ee83f3cc7 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -31,14 +31,20 @@ void SymIntExpr::dumpToStream(raw_ostream &os) const { os << '('; getLHS()->dumpToStream(os); os << ") " - << BinaryOperator::getOpcodeStr(getOpcode()) << ' ' - << getRHS().getZExtValue(); + << BinaryOperator::getOpcodeStr(getOpcode()) << ' '; + if (getRHS().isUnsigned()) + os << getRHS().getZExtValue(); + else + os << getRHS().getSExtValue(); if (getRHS().isUnsigned()) os << 'U'; } void IntSymExpr::dumpToStream(raw_ostream &os) const { - os << getLHS().getZExtValue(); + if (getLHS().isUnsigned()) + os << getLHS().getZExtValue(); + else + os << getLHS().getSExtValue(); if (getLHS().isUnsigned()) os << 'U'; os << ' ' diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index c47edc7d21256..fccea9ee53bf5 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -854,8 +854,7 @@ UbigraphViz::~UbigraphViz() { Ubiviz = *Path; const char *args[] = {Ubiviz.c_str(), Filename.c_str(), nullptr}; - if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, nullptr, 0, 0, - &ErrMsg)) { + if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, {}, 0, 0, &ErrMsg)) { llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; } diff --git a/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp new file mode 100644 index 0000000000000..6da0de7edf9a2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/ASTDiff/ASTDiff.cpp @@ -0,0 +1,1021 @@ +//===- ASTDiff.cpp - AST differencing implementation-----------*- C++ -*- -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains definitons for the AST differencing interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/ASTDiff/ASTDiff.h" + +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/PriorityQueue.h" + +#include <limits> +#include <memory> +#include <unordered_set> + +using namespace llvm; +using namespace clang; + +namespace clang { +namespace diff { + +namespace { +/// Maps nodes of the left tree to ones on the right, and vice versa. +class Mapping { +public: + Mapping() = default; + Mapping(Mapping &&Other) = default; + Mapping &operator=(Mapping &&Other) = default; + + Mapping(size_t Size) { + SrcToDst = llvm::make_unique<NodeId[]>(Size); + DstToSrc = llvm::make_unique<NodeId[]>(Size); + } + + void link(NodeId Src, NodeId Dst) { + SrcToDst[Src] = Dst, DstToSrc[Dst] = Src; + } + + NodeId getDst(NodeId Src) const { return SrcToDst[Src]; } + NodeId getSrc(NodeId Dst) const { return DstToSrc[Dst]; } + bool hasSrc(NodeId Src) const { return getDst(Src).isValid(); } + bool hasDst(NodeId Dst) const { return getSrc(Dst).isValid(); } + +private: + std::unique_ptr<NodeId[]> SrcToDst, DstToSrc; +}; +} // end anonymous namespace + +class ASTDiff::Impl { +public: + SyntaxTree::Impl &T1, &T2; + Mapping TheMapping; + + Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2, + const ComparisonOptions &Options); + + /// Matches nodes one-by-one based on their similarity. + void computeMapping(); + + // Compute Change for each node based on similarity. + void computeChangeKinds(Mapping &M); + + NodeId getMapped(const std::unique_ptr<SyntaxTree::Impl> &Tree, + NodeId Id) const { + if (&*Tree == &T1) + return TheMapping.getDst(Id); + assert(&*Tree == &T2 && "Invalid tree."); + return TheMapping.getSrc(Id); + } + +private: + // Returns true if the two subtrees are identical. + bool identical(NodeId Id1, NodeId Id2) const; + + // Returns false if the nodes must not be mached. + bool isMatchingPossible(NodeId Id1, NodeId Id2) const; + + // Returns true if the nodes' parents are matched. + bool haveSameParents(const Mapping &M, NodeId Id1, NodeId Id2) const; + + // Uses an optimal albeit slow algorithm to compute a mapping between two + // subtrees, but only if both have fewer nodes than MaxSize. + void addOptimalMapping(Mapping &M, NodeId Id1, NodeId Id2) const; + + // Computes the ratio of common descendants between the two nodes. + // Descendants are only considered to be equal when they are mapped in M. + double getJaccardSimilarity(const Mapping &M, NodeId Id1, NodeId Id2) const; + + // Returns the node that has the highest degree of similarity. + NodeId findCandidate(const Mapping &M, NodeId Id1) const; + + // Returns a mapping of identical subtrees. + Mapping matchTopDown() const; + + // Tries to match any yet unmapped nodes, in a bottom-up fashion. + void matchBottomUp(Mapping &M) const; + + const ComparisonOptions &Options; + + friend class ZhangShashaMatcher; +}; + +/// Represents the AST of a TranslationUnit. +class SyntaxTree::Impl { +public: + Impl(SyntaxTree *Parent, ASTContext &AST); + /// Constructs a tree from an AST node. + Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST); + Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST); + template <class T> + Impl(SyntaxTree *Parent, + typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type *Node, + ASTContext &AST) + : Impl(Parent, dyn_cast<Stmt>(Node), AST) {} + template <class T> + Impl(SyntaxTree *Parent, + typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type *Node, + ASTContext &AST) + : Impl(Parent, dyn_cast<Decl>(Node), AST) {} + + SyntaxTree *Parent; + ASTContext &AST; + PrintingPolicy TypePP; + /// Nodes in preorder. + std::vector<Node> Nodes; + std::vector<NodeId> Leaves; + // Maps preorder indices to postorder ones. + std::vector<int> PostorderIds; + std::vector<NodeId> NodesBfs; + + int getSize() const { return Nodes.size(); } + NodeId getRootId() const { return 0; } + PreorderIterator begin() const { return getRootId(); } + PreorderIterator end() const { return getSize(); } + + const Node &getNode(NodeId Id) const { return Nodes[Id]; } + Node &getMutableNode(NodeId Id) { return Nodes[Id]; } + bool isValidNodeId(NodeId Id) const { return Id >= 0 && Id < getSize(); } + void addNode(Node &N) { Nodes.push_back(N); } + int getNumberOfDescendants(NodeId Id) const; + bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const; + int findPositionInParent(NodeId Id, bool Shifted = false) const; + + std::string getRelativeName(const NamedDecl *ND, + const DeclContext *Context) const; + std::string getRelativeName(const NamedDecl *ND) const; + + std::string getNodeValue(NodeId Id) const; + std::string getNodeValue(const Node &Node) const; + std::string getDeclValue(const Decl *D) const; + std::string getStmtValue(const Stmt *S) const; + +private: + void initTree(); + void setLeftMostDescendants(); +}; + +static bool isSpecializedNodeExcluded(const Decl *D) { return D->isImplicit(); } +static bool isSpecializedNodeExcluded(const Stmt *S) { return false; } +static bool isSpecializedNodeExcluded(CXXCtorInitializer *I) { + return !I->isWritten(); +} + +template <class T> +static bool isNodeExcluded(const SourceManager &SrcMgr, T *N) { + if (!N) + return true; + SourceLocation SLoc = N->getSourceRange().getBegin(); + if (SLoc.isValid()) { + // Ignore everything from other files. + if (!SrcMgr.isInMainFile(SLoc)) + return true; + // Ignore macros. + if (SLoc != SrcMgr.getSpellingLoc(SLoc)) + return true; + } + return isSpecializedNodeExcluded(N); +} + +namespace { +// Sets Height, Parent and Children for each node. +struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> { + int Id = 0, Depth = 0; + NodeId Parent; + SyntaxTree::Impl &Tree; + + PreorderVisitor(SyntaxTree::Impl &Tree) : Tree(Tree) {} + + template <class T> std::tuple<NodeId, NodeId> PreTraverse(T *ASTNode) { + NodeId MyId = Id; + Tree.Nodes.emplace_back(); + Node &N = Tree.getMutableNode(MyId); + N.Parent = Parent; + N.Depth = Depth; + N.ASTNode = DynTypedNode::create(*ASTNode); + assert(!N.ASTNode.getNodeKind().isNone() && + "Expected nodes to have a valid kind."); + if (Parent.isValid()) { + Node &P = Tree.getMutableNode(Parent); + P.Children.push_back(MyId); + } + Parent = MyId; + ++Id; + ++Depth; + return std::make_tuple(MyId, Tree.getNode(MyId).Parent); + } + void PostTraverse(std::tuple<NodeId, NodeId> State) { + NodeId MyId, PreviousParent; + std::tie(MyId, PreviousParent) = State; + assert(MyId.isValid() && "Expecting to only traverse valid nodes."); + Parent = PreviousParent; + --Depth; + Node &N = Tree.getMutableNode(MyId); + N.RightMostDescendant = Id - 1; + assert(N.RightMostDescendant >= 0 && + N.RightMostDescendant < Tree.getSize() && + "Rightmost descendant must be a valid tree node."); + if (N.isLeaf()) + Tree.Leaves.push_back(MyId); + N.Height = 1; + for (NodeId Child : N.Children) + N.Height = std::max(N.Height, 1 + Tree.getNode(Child).Height); + } + bool TraverseDecl(Decl *D) { + if (isNodeExcluded(Tree.AST.getSourceManager(), D)) + return true; + auto SavedState = PreTraverse(D); + RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D); + PostTraverse(SavedState); + return true; + } + bool TraverseStmt(Stmt *S) { + if (S) + S = S->IgnoreImplicit(); + if (isNodeExcluded(Tree.AST.getSourceManager(), S)) + return true; + auto SavedState = PreTraverse(S); + RecursiveASTVisitor<PreorderVisitor>::TraverseStmt(S); + PostTraverse(SavedState); + return true; + } + bool TraverseType(QualType T) { return true; } + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + if (isNodeExcluded(Tree.AST.getSourceManager(), Init)) + return true; + auto SavedState = PreTraverse(Init); + RecursiveASTVisitor<PreorderVisitor>::TraverseConstructorInitializer(Init); + PostTraverse(SavedState); + return true; + } +}; +} // end anonymous namespace + +SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST) + : Parent(Parent), AST(AST), TypePP(AST.getLangOpts()) { + TypePP.AnonymousTagLocations = false; +} + +SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST) + : Impl(Parent, AST) { + PreorderVisitor PreorderWalker(*this); + PreorderWalker.TraverseDecl(N); + initTree(); +} + +SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST) + : Impl(Parent, AST) { + PreorderVisitor PreorderWalker(*this); + PreorderWalker.TraverseStmt(N); + initTree(); +} + +static std::vector<NodeId> getSubtreePostorder(const SyntaxTree::Impl &Tree, + NodeId Root) { + std::vector<NodeId> Postorder; + std::function<void(NodeId)> Traverse = [&](NodeId Id) { + const Node &N = Tree.getNode(Id); + for (NodeId Child : N.Children) + Traverse(Child); + Postorder.push_back(Id); + }; + Traverse(Root); + return Postorder; +} + +static std::vector<NodeId> getSubtreeBfs(const SyntaxTree::Impl &Tree, + NodeId Root) { + std::vector<NodeId> Ids; + size_t Expanded = 0; + Ids.push_back(Root); + while (Expanded < Ids.size()) + for (NodeId Child : Tree.getNode(Ids[Expanded++]).Children) + Ids.push_back(Child); + return Ids; +} + +void SyntaxTree::Impl::initTree() { + setLeftMostDescendants(); + int PostorderId = 0; + PostorderIds.resize(getSize()); + std::function<void(NodeId)> PostorderTraverse = [&](NodeId Id) { + for (NodeId Child : getNode(Id).Children) + PostorderTraverse(Child); + PostorderIds[Id] = PostorderId; + ++PostorderId; + }; + PostorderTraverse(getRootId()); + NodesBfs = getSubtreeBfs(*this, getRootId()); +} + +void SyntaxTree::Impl::setLeftMostDescendants() { + for (NodeId Leaf : Leaves) { + getMutableNode(Leaf).LeftMostDescendant = Leaf; + NodeId Parent, Cur = Leaf; + while ((Parent = getNode(Cur).Parent).isValid() && + getNode(Parent).Children[0] == Cur) { + Cur = Parent; + getMutableNode(Cur).LeftMostDescendant = Leaf; + } + } +} + +int SyntaxTree::Impl::getNumberOfDescendants(NodeId Id) const { + return getNode(Id).RightMostDescendant - Id + 1; +} + +bool SyntaxTree::Impl::isInSubtree(NodeId Id, NodeId SubtreeRoot) const { + return Id >= SubtreeRoot && Id <= getNode(SubtreeRoot).RightMostDescendant; +} + +int SyntaxTree::Impl::findPositionInParent(NodeId Id, bool Shifted) const { + NodeId Parent = getNode(Id).Parent; + if (Parent.isInvalid()) + return 0; + const auto &Siblings = getNode(Parent).Children; + int Position = 0; + for (size_t I = 0, E = Siblings.size(); I < E; ++I) { + if (Shifted) + Position += getNode(Siblings[I]).Shift; + if (Siblings[I] == Id) { + Position += I; + return Position; + } + } + llvm_unreachable("Node not found in parent's children."); +} + +// Returns the qualified name of ND. If it is subordinate to Context, +// then the prefix of the latter is removed from the returned value. +std::string +SyntaxTree::Impl::getRelativeName(const NamedDecl *ND, + const DeclContext *Context) const { + std::string Val = ND->getQualifiedNameAsString(); + std::string ContextPrefix; + if (!Context) + return Val; + if (auto *Namespace = dyn_cast<NamespaceDecl>(Context)) + ContextPrefix = Namespace->getQualifiedNameAsString(); + else if (auto *Record = dyn_cast<RecordDecl>(Context)) + ContextPrefix = Record->getQualifiedNameAsString(); + else if (AST.getLangOpts().CPlusPlus11) + if (auto *Tag = dyn_cast<TagDecl>(Context)) + ContextPrefix = Tag->getQualifiedNameAsString(); + // Strip the qualifier, if Val refers to somthing in the current scope. + // But leave one leading ':' in place, so that we know that this is a + // relative path. + if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix)) + Val = Val.substr(ContextPrefix.size() + 1); + return Val; +} + +std::string SyntaxTree::Impl::getRelativeName(const NamedDecl *ND) const { + return getRelativeName(ND, ND->getDeclContext()); +} + +static const DeclContext *getEnclosingDeclContext(ASTContext &AST, + const Stmt *S) { + while (S) { + const auto &Parents = AST.getParents(*S); + if (Parents.empty()) + return nullptr; + const auto &P = Parents[0]; + if (const auto *D = P.get<Decl>()) + return D->getDeclContext(); + S = P.get<Stmt>(); + } + return nullptr; +} + +static std::string getInitializerValue(const CXXCtorInitializer *Init, + const PrintingPolicy &TypePP) { + if (Init->isAnyMemberInitializer()) + return Init->getAnyMember()->getName(); + if (Init->isBaseInitializer()) + return QualType(Init->getBaseClass(), 0).getAsString(TypePP); + if (Init->isDelegatingInitializer()) + return Init->getTypeSourceInfo()->getType().getAsString(TypePP); + llvm_unreachable("Unknown initializer type"); +} + +std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const { + return getNodeValue(getNode(Id)); +} + +std::string SyntaxTree::Impl::getNodeValue(const Node &N) const { + const DynTypedNode &DTN = N.ASTNode; + if (auto *S = DTN.get<Stmt>()) + return getStmtValue(S); + if (auto *D = DTN.get<Decl>()) + return getDeclValue(D); + if (auto *Init = DTN.get<CXXCtorInitializer>()) + return getInitializerValue(Init, TypePP); + llvm_unreachable("Fatal: unhandled AST node.\n"); +} + +std::string SyntaxTree::Impl::getDeclValue(const Decl *D) const { + std::string Value; + if (auto *V = dyn_cast<ValueDecl>(D)) + return getRelativeName(V) + "(" + V->getType().getAsString(TypePP) + ")"; + if (auto *N = dyn_cast<NamedDecl>(D)) + Value += getRelativeName(N) + ";"; + if (auto *T = dyn_cast<TypedefNameDecl>(D)) + return Value + T->getUnderlyingType().getAsString(TypePP) + ";"; + if (auto *T = dyn_cast<TypeDecl>(D)) + if (T->getTypeForDecl()) + Value += + T->getTypeForDecl()->getCanonicalTypeInternal().getAsString(TypePP) + + ";"; + if (auto *U = dyn_cast<UsingDirectiveDecl>(D)) + return U->getNominatedNamespace()->getName(); + if (auto *A = dyn_cast<AccessSpecDecl>(D)) { + CharSourceRange Range(A->getSourceRange(), false); + return Lexer::getSourceText(Range, AST.getSourceManager(), + AST.getLangOpts()); + } + return Value; +} + +std::string SyntaxTree::Impl::getStmtValue(const Stmt *S) const { + if (auto *U = dyn_cast<UnaryOperator>(S)) + return UnaryOperator::getOpcodeStr(U->getOpcode()); + if (auto *B = dyn_cast<BinaryOperator>(S)) + return B->getOpcodeStr(); + if (auto *M = dyn_cast<MemberExpr>(S)) + return getRelativeName(M->getMemberDecl()); + if (auto *I = dyn_cast<IntegerLiteral>(S)) { + SmallString<256> Str; + I->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false); + return Str.str(); + } + if (auto *F = dyn_cast<FloatingLiteral>(S)) { + SmallString<256> Str; + F->getValue().toString(Str); + return Str.str(); + } + if (auto *D = dyn_cast<DeclRefExpr>(S)) + return getRelativeName(D->getDecl(), getEnclosingDeclContext(AST, S)); + if (auto *String = dyn_cast<StringLiteral>(S)) + return String->getString(); + if (auto *B = dyn_cast<CXXBoolLiteralExpr>(S)) + return B->getValue() ? "true" : "false"; + return ""; +} + +/// Identifies a node in a subtree by its postorder offset, starting at 1. +struct SNodeId { + int Id = 0; + + explicit SNodeId(int Id) : Id(Id) {} + explicit SNodeId() = default; + + operator int() const { return Id; } + SNodeId &operator++() { return ++Id, *this; } + SNodeId &operator--() { return --Id, *this; } + SNodeId operator+(int Other) const { return SNodeId(Id + Other); } +}; + +class Subtree { +private: + /// The parent tree. + const SyntaxTree::Impl &Tree; + /// Maps SNodeIds to original ids. + std::vector<NodeId> RootIds; + /// Maps subtree nodes to their leftmost descendants wtihin the subtree. + std::vector<SNodeId> LeftMostDescendants; + +public: + std::vector<SNodeId> KeyRoots; + + Subtree(const SyntaxTree::Impl &Tree, NodeId SubtreeRoot) : Tree(Tree) { + RootIds = getSubtreePostorder(Tree, SubtreeRoot); + int NumLeaves = setLeftMostDescendants(); + computeKeyRoots(NumLeaves); + } + int getSize() const { return RootIds.size(); } + NodeId getIdInRoot(SNodeId Id) const { + assert(Id > 0 && Id <= getSize() && "Invalid subtree node index."); + return RootIds[Id - 1]; + } + const Node &getNode(SNodeId Id) const { + return Tree.getNode(getIdInRoot(Id)); + } + SNodeId getLeftMostDescendant(SNodeId Id) const { + assert(Id > 0 && Id <= getSize() && "Invalid subtree node index."); + return LeftMostDescendants[Id - 1]; + } + /// Returns the postorder index of the leftmost descendant in the subtree. + NodeId getPostorderOffset() const { + return Tree.PostorderIds[getIdInRoot(SNodeId(1))]; + } + std::string getNodeValue(SNodeId Id) const { + return Tree.getNodeValue(getIdInRoot(Id)); + } + +private: + /// Returns the number of leafs in the subtree. + int setLeftMostDescendants() { + int NumLeaves = 0; + LeftMostDescendants.resize(getSize()); + for (int I = 0; I < getSize(); ++I) { + SNodeId SI(I + 1); + const Node &N = getNode(SI); + NumLeaves += N.isLeaf(); + assert(I == Tree.PostorderIds[getIdInRoot(SI)] - getPostorderOffset() && + "Postorder traversal in subtree should correspond to traversal in " + "the root tree by a constant offset."); + LeftMostDescendants[I] = SNodeId(Tree.PostorderIds[N.LeftMostDescendant] - + getPostorderOffset()); + } + return NumLeaves; + } + void computeKeyRoots(int Leaves) { + KeyRoots.resize(Leaves); + std::unordered_set<int> Visited; + int K = Leaves - 1; + for (SNodeId I(getSize()); I > 0; --I) { + SNodeId LeftDesc = getLeftMostDescendant(I); + if (Visited.count(LeftDesc)) + continue; + assert(K >= 0 && "K should be non-negative"); + KeyRoots[K] = I; + Visited.insert(LeftDesc); + --K; + } + } +}; + +/// Implementation of Zhang and Shasha's Algorithm for tree edit distance. +/// Computes an optimal mapping between two trees using only insertion, +/// deletion and update as edit actions (similar to the Levenshtein distance). +class ZhangShashaMatcher { + const ASTDiff::Impl &DiffImpl; + Subtree S1; + Subtree S2; + std::unique_ptr<std::unique_ptr<double[]>[]> TreeDist, ForestDist; + +public: + ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1, + const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2) + : DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) { + TreeDist = llvm::make_unique<std::unique_ptr<double[]>[]>( + size_t(S1.getSize()) + 1); + ForestDist = llvm::make_unique<std::unique_ptr<double[]>[]>( + size_t(S1.getSize()) + 1); + for (int I = 0, E = S1.getSize() + 1; I < E; ++I) { + TreeDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1); + ForestDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1); + } + } + + std::vector<std::pair<NodeId, NodeId>> getMatchingNodes() { + std::vector<std::pair<NodeId, NodeId>> Matches; + std::vector<std::pair<SNodeId, SNodeId>> TreePairs; + + computeTreeDist(); + + bool RootNodePair = true; + + TreePairs.emplace_back(SNodeId(S1.getSize()), SNodeId(S2.getSize())); + + while (!TreePairs.empty()) { + SNodeId LastRow, LastCol, FirstRow, FirstCol, Row, Col; + std::tie(LastRow, LastCol) = TreePairs.back(); + TreePairs.pop_back(); + + if (!RootNodePair) { + computeForestDist(LastRow, LastCol); + } + + RootNodePair = false; + + FirstRow = S1.getLeftMostDescendant(LastRow); + FirstCol = S2.getLeftMostDescendant(LastCol); + + Row = LastRow; + Col = LastCol; + + while (Row > FirstRow || Col > FirstCol) { + if (Row > FirstRow && + ForestDist[Row - 1][Col] + 1 == ForestDist[Row][Col]) { + --Row; + } else if (Col > FirstCol && + ForestDist[Row][Col - 1] + 1 == ForestDist[Row][Col]) { + --Col; + } else { + SNodeId LMD1 = S1.getLeftMostDescendant(Row); + SNodeId LMD2 = S2.getLeftMostDescendant(Col); + if (LMD1 == S1.getLeftMostDescendant(LastRow) && + LMD2 == S2.getLeftMostDescendant(LastCol)) { + NodeId Id1 = S1.getIdInRoot(Row); + NodeId Id2 = S2.getIdInRoot(Col); + assert(DiffImpl.isMatchingPossible(Id1, Id2) && + "These nodes must not be matched."); + Matches.emplace_back(Id1, Id2); + --Row; + --Col; + } else { + TreePairs.emplace_back(Row, Col); + Row = LMD1; + Col = LMD2; + } + } + } + } + return Matches; + } + +private: + /// We use a simple cost model for edit actions, which seems good enough. + /// Simple cost model for edit actions. This seems to make the matching + /// algorithm perform reasonably well. + /// The values range between 0 and 1, or infinity if this edit action should + /// always be avoided. + static constexpr double DeletionCost = 1; + static constexpr double InsertionCost = 1; + + double getUpdateCost(SNodeId Id1, SNodeId Id2) { + if (!DiffImpl.isMatchingPossible(S1.getIdInRoot(Id1), S2.getIdInRoot(Id2))) + return std::numeric_limits<double>::max(); + return S1.getNodeValue(Id1) != S2.getNodeValue(Id2); + } + + void computeTreeDist() { + for (SNodeId Id1 : S1.KeyRoots) + for (SNodeId Id2 : S2.KeyRoots) + computeForestDist(Id1, Id2); + } + + void computeForestDist(SNodeId Id1, SNodeId Id2) { + assert(Id1 > 0 && Id2 > 0 && "Expecting offsets greater than 0."); + SNodeId LMD1 = S1.getLeftMostDescendant(Id1); + SNodeId LMD2 = S2.getLeftMostDescendant(Id2); + + ForestDist[LMD1][LMD2] = 0; + for (SNodeId D1 = LMD1 + 1; D1 <= Id1; ++D1) { + ForestDist[D1][LMD2] = ForestDist[D1 - 1][LMD2] + DeletionCost; + for (SNodeId D2 = LMD2 + 1; D2 <= Id2; ++D2) { + ForestDist[LMD1][D2] = ForestDist[LMD1][D2 - 1] + InsertionCost; + SNodeId DLMD1 = S1.getLeftMostDescendant(D1); + SNodeId DLMD2 = S2.getLeftMostDescendant(D2); + if (DLMD1 == LMD1 && DLMD2 == LMD2) { + double UpdateCost = getUpdateCost(D1, D2); + ForestDist[D1][D2] = + std::min({ForestDist[D1 - 1][D2] + DeletionCost, + ForestDist[D1][D2 - 1] + InsertionCost, + ForestDist[D1 - 1][D2 - 1] + UpdateCost}); + TreeDist[D1][D2] = ForestDist[D1][D2]; + } else { + ForestDist[D1][D2] = + std::min({ForestDist[D1 - 1][D2] + DeletionCost, + ForestDist[D1][D2 - 1] + InsertionCost, + ForestDist[DLMD1][DLMD2] + TreeDist[D1][D2]}); + } + } + } + } +}; + +ast_type_traits::ASTNodeKind Node::getType() const { + return ASTNode.getNodeKind(); +} + +StringRef Node::getTypeLabel() const { return getType().asStringRef(); } + +llvm::Optional<std::string> Node::getQualifiedIdentifier() const { + if (auto *ND = ASTNode.get<NamedDecl>()) { + if (ND->getDeclName().isIdentifier()) + return ND->getQualifiedNameAsString(); + } + return llvm::None; +} + +llvm::Optional<StringRef> Node::getIdentifier() const { + if (auto *ND = ASTNode.get<NamedDecl>()) { + if (ND->getDeclName().isIdentifier()) + return ND->getName(); + } + return llvm::None; +} + +namespace { +// Compares nodes by their depth. +struct HeightLess { + const SyntaxTree::Impl &Tree; + HeightLess(const SyntaxTree::Impl &Tree) : Tree(Tree) {} + bool operator()(NodeId Id1, NodeId Id2) const { + return Tree.getNode(Id1).Height < Tree.getNode(Id2).Height; + } +}; +} // end anonymous namespace + +namespace { +// Priority queue for nodes, sorted descendingly by their height. +class PriorityList { + const SyntaxTree::Impl &Tree; + HeightLess Cmp; + std::vector<NodeId> Container; + PriorityQueue<NodeId, std::vector<NodeId>, HeightLess> List; + +public: + PriorityList(const SyntaxTree::Impl &Tree) + : Tree(Tree), Cmp(Tree), List(Cmp, Container) {} + + void push(NodeId id) { List.push(id); } + + std::vector<NodeId> pop() { + int Max = peekMax(); + std::vector<NodeId> Result; + if (Max == 0) + return Result; + while (peekMax() == Max) { + Result.push_back(List.top()); + List.pop(); + } + // TODO this is here to get a stable output, not a good heuristic + std::sort(Result.begin(), Result.end()); + return Result; + } + int peekMax() const { + if (List.empty()) + return 0; + return Tree.getNode(List.top()).Height; + } + void open(NodeId Id) { + for (NodeId Child : Tree.getNode(Id).Children) + push(Child); + } +}; +} // end anonymous namespace + +bool ASTDiff::Impl::identical(NodeId Id1, NodeId Id2) const { + const Node &N1 = T1.getNode(Id1); + const Node &N2 = T2.getNode(Id2); + if (N1.Children.size() != N2.Children.size() || + !isMatchingPossible(Id1, Id2) || + T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) + return false; + for (size_t Id = 0, E = N1.Children.size(); Id < E; ++Id) + if (!identical(N1.Children[Id], N2.Children[Id])) + return false; + return true; +} + +bool ASTDiff::Impl::isMatchingPossible(NodeId Id1, NodeId Id2) const { + return Options.isMatchingAllowed(T1.getNode(Id1), T2.getNode(Id2)); +} + +bool ASTDiff::Impl::haveSameParents(const Mapping &M, NodeId Id1, + NodeId Id2) const { + NodeId P1 = T1.getNode(Id1).Parent; + NodeId P2 = T2.getNode(Id2).Parent; + return (P1.isInvalid() && P2.isInvalid()) || + (P1.isValid() && P2.isValid() && M.getDst(P1) == P2); +} + +void ASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1, + NodeId Id2) const { + if (std::max(T1.getNumberOfDescendants(Id1), T2.getNumberOfDescendants(Id2)) > + Options.MaxSize) + return; + ZhangShashaMatcher Matcher(*this, T1, T2, Id1, Id2); + std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes(); + for (const auto Tuple : R) { + NodeId Src = Tuple.first; + NodeId Dst = Tuple.second; + if (!M.hasSrc(Src) && !M.hasDst(Dst)) + M.link(Src, Dst); + } +} + +double ASTDiff::Impl::getJaccardSimilarity(const Mapping &M, NodeId Id1, + NodeId Id2) const { + int CommonDescendants = 0; + const Node &N1 = T1.getNode(Id1); + // Count the common descendants, excluding the subtree root. + for (NodeId Src = Id1 + 1; Src <= N1.RightMostDescendant; ++Src) { + NodeId Dst = M.getDst(Src); + CommonDescendants += int(Dst.isValid() && T2.isInSubtree(Dst, Id2)); + } + // We need to subtract 1 to get the number of descendants excluding the root. + double Denominator = T1.getNumberOfDescendants(Id1) - 1 + + T2.getNumberOfDescendants(Id2) - 1 - CommonDescendants; + // CommonDescendants is less than the size of one subtree. + assert(Denominator >= 0 && "Expected non-negative denominator."); + if (Denominator == 0) + return 0; + return CommonDescendants / Denominator; +} + +NodeId ASTDiff::Impl::findCandidate(const Mapping &M, NodeId Id1) const { + NodeId Candidate; + double HighestSimilarity = 0.0; + for (NodeId Id2 : T2) { + if (!isMatchingPossible(Id1, Id2)) + continue; + if (M.hasDst(Id2)) + continue; + double Similarity = getJaccardSimilarity(M, Id1, Id2); + if (Similarity >= Options.MinSimilarity && Similarity > HighestSimilarity) { + HighestSimilarity = Similarity; + Candidate = Id2; + } + } + return Candidate; +} + +void ASTDiff::Impl::matchBottomUp(Mapping &M) const { + std::vector<NodeId> Postorder = getSubtreePostorder(T1, T1.getRootId()); + for (NodeId Id1 : Postorder) { + if (Id1 == T1.getRootId() && !M.hasSrc(T1.getRootId()) && + !M.hasDst(T2.getRootId())) { + if (isMatchingPossible(T1.getRootId(), T2.getRootId())) { + M.link(T1.getRootId(), T2.getRootId()); + addOptimalMapping(M, T1.getRootId(), T2.getRootId()); + } + break; + } + bool Matched = M.hasSrc(Id1); + const Node &N1 = T1.getNode(Id1); + bool MatchedChildren = + std::any_of(N1.Children.begin(), N1.Children.end(), + [&](NodeId Child) { return M.hasSrc(Child); }); + if (Matched || !MatchedChildren) + continue; + NodeId Id2 = findCandidate(M, Id1); + if (Id2.isValid()) { + M.link(Id1, Id2); + addOptimalMapping(M, Id1, Id2); + } + } +} + +Mapping ASTDiff::Impl::matchTopDown() const { + PriorityList L1(T1); + PriorityList L2(T2); + + Mapping M(T1.getSize() + T2.getSize()); + + L1.push(T1.getRootId()); + L2.push(T2.getRootId()); + + int Max1, Max2; + while (std::min(Max1 = L1.peekMax(), Max2 = L2.peekMax()) > + Options.MinHeight) { + if (Max1 > Max2) { + for (NodeId Id : L1.pop()) + L1.open(Id); + continue; + } + if (Max2 > Max1) { + for (NodeId Id : L2.pop()) + L2.open(Id); + continue; + } + std::vector<NodeId> H1, H2; + H1 = L1.pop(); + H2 = L2.pop(); + for (NodeId Id1 : H1) { + for (NodeId Id2 : H2) { + if (identical(Id1, Id2) && !M.hasSrc(Id1) && !M.hasDst(Id2)) { + for (int I = 0, E = T1.getNumberOfDescendants(Id1); I < E; ++I) + M.link(Id1 + I, Id2 + I); + } + } + } + for (NodeId Id1 : H1) { + if (!M.hasSrc(Id1)) + L1.open(Id1); + } + for (NodeId Id2 : H2) { + if (!M.hasDst(Id2)) + L2.open(Id2); + } + } + return M; +} + +ASTDiff::Impl::Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2, + const ComparisonOptions &Options) + : T1(T1), T2(T2), Options(Options) { + computeMapping(); + computeChangeKinds(TheMapping); +} + +void ASTDiff::Impl::computeMapping() { + TheMapping = matchTopDown(); + if (Options.StopAfterTopDown) + return; + matchBottomUp(TheMapping); +} + +void ASTDiff::Impl::computeChangeKinds(Mapping &M) { + for (NodeId Id1 : T1) { + if (!M.hasSrc(Id1)) { + T1.getMutableNode(Id1).Change = Delete; + T1.getMutableNode(Id1).Shift -= 1; + } + } + for (NodeId Id2 : T2) { + if (!M.hasDst(Id2)) { + T2.getMutableNode(Id2).Change = Insert; + T2.getMutableNode(Id2).Shift -= 1; + } + } + for (NodeId Id1 : T1.NodesBfs) { + NodeId Id2 = M.getDst(Id1); + if (Id2.isInvalid()) + continue; + if (!haveSameParents(M, Id1, Id2) || + T1.findPositionInParent(Id1, true) != + T2.findPositionInParent(Id2, true)) { + T1.getMutableNode(Id1).Shift -= 1; + T2.getMutableNode(Id2).Shift -= 1; + } + } + for (NodeId Id2 : T2.NodesBfs) { + NodeId Id1 = M.getSrc(Id2); + if (Id1.isInvalid()) + continue; + Node &N1 = T1.getMutableNode(Id1); + Node &N2 = T2.getMutableNode(Id2); + if (Id1.isInvalid()) + continue; + if (!haveSameParents(M, Id1, Id2) || + T1.findPositionInParent(Id1, true) != + T2.findPositionInParent(Id2, true)) { + N1.Change = N2.Change = Move; + } + if (T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) { + N1.Change = N2.Change = (N1.Change == Move ? UpdateMove : Update); + } + } +} + +ASTDiff::ASTDiff(SyntaxTree &T1, SyntaxTree &T2, + const ComparisonOptions &Options) + : DiffImpl(llvm::make_unique<Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {} + +ASTDiff::~ASTDiff() = default; + +NodeId ASTDiff::getMapped(const SyntaxTree &SourceTree, NodeId Id) const { + return DiffImpl->getMapped(SourceTree.TreeImpl, Id); +} + +SyntaxTree::SyntaxTree(ASTContext &AST) + : TreeImpl(llvm::make_unique<SyntaxTree::Impl>( + this, AST.getTranslationUnitDecl(), AST)) {} + +SyntaxTree::~SyntaxTree() = default; + +const ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; } + +const Node &SyntaxTree::getNode(NodeId Id) const { + return TreeImpl->getNode(Id); +} + +int SyntaxTree::getSize() const { return TreeImpl->getSize(); } +NodeId SyntaxTree::getRootId() const { return TreeImpl->getRootId(); } +SyntaxTree::PreorderIterator SyntaxTree::begin() const { + return TreeImpl->begin(); +} +SyntaxTree::PreorderIterator SyntaxTree::end() const { return TreeImpl->end(); } + +int SyntaxTree::findPositionInParent(NodeId Id) const { + return TreeImpl->findPositionInParent(Id); +} + +std::pair<unsigned, unsigned> +SyntaxTree::getSourceRangeOffsets(const Node &N) const { + const SourceManager &SrcMgr = TreeImpl->AST.getSourceManager(); + SourceRange Range = N.ASTNode.getSourceRange(); + SourceLocation BeginLoc = Range.getBegin(); + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + Range.getEnd(), /*Offset=*/0, SrcMgr, TreeImpl->AST.getLangOpts()); + if (auto *ThisExpr = N.ASTNode.get<CXXThisExpr>()) { + if (ThisExpr->isImplicit()) + EndLoc = BeginLoc; + } + unsigned Begin = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(BeginLoc)); + unsigned End = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(EndLoc)); + return {Begin, End}; +} + +std::string SyntaxTree::getNodeValue(NodeId Id) const { + return TreeImpl->getNodeValue(Id); +} + +std::string SyntaxTree::getNodeValue(const Node &N) const { + return TreeImpl->getNodeValue(N); +} + +} // end namespace diff +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp index ac9fd3c5cade4..7068ec2c4010e 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -58,14 +58,14 @@ ArgumentsAdjuster getClangStripDependencyFileAdjuster() { StringRef Arg = Args[i]; // All dependency-file options begin with -M. These include -MM, // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD. - if (!Arg.startswith("-M")) + if (!Arg.startswith("-M")) { AdjustedArgs.push_back(Args[i]); + continue; + } - if ((Arg == "-MF") || (Arg == "-MT") || (Arg == "-MQ") || - (Arg == "-MD") || (Arg == "-MMD")) { - // Output is specified as -MX foo. Skip the next argument also. + if (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ") + // These flags take an argument: -MX foo. Skip the next argument also. ++i; - } } return AdjustedArgs; }; @@ -96,6 +96,10 @@ ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, ArgumentsAdjuster Second) { + if (!First) + return Second; + if (!Second) + return First; return [First, Second](const CommandLineArguments &Args, StringRef File) { return Second(First(Args, File), File); }; diff --git a/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp index 9e9689e6b2524..74ad4e83ee3f3 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp @@ -24,10 +24,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/CommandLine.h" -#include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/Support/CommandLine.h" using namespace clang::tooling; using namespace llvm; @@ -54,80 +53,82 @@ const char *const CommonOptionsParser::HelpMessage = "\tsuffix of a path in the compile command database.\n" "\n"; -namespace { -class ArgumentsAdjustingCompilations : public CompilationDatabase { -public: - ArgumentsAdjustingCompilations( - std::unique_ptr<CompilationDatabase> Compilations) - : Compilations(std::move(Compilations)) {} - - void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) { - Adjusters.push_back(std::move(Adjuster)); - } - - std::vector<CompileCommand> - getCompileCommands(StringRef FilePath) const override { - return adjustCommands(Compilations->getCompileCommands(FilePath)); - } +void ArgumentsAdjustingCompilations::appendArgumentsAdjuster( + ArgumentsAdjuster Adjuster) { + Adjusters.push_back(std::move(Adjuster)); +} - std::vector<std::string> getAllFiles() const override { - return Compilations->getAllFiles(); - } +std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands( + StringRef FilePath) const { + return adjustCommands(Compilations->getCompileCommands(FilePath)); +} - std::vector<CompileCommand> getAllCompileCommands() const override { - return adjustCommands(Compilations->getAllCompileCommands()); - } +std::vector<std::string> +ArgumentsAdjustingCompilations::getAllFiles() const { + return Compilations->getAllFiles(); +} -private: - std::unique_ptr<CompilationDatabase> Compilations; - std::vector<ArgumentsAdjuster> Adjusters; +std::vector<CompileCommand> +ArgumentsAdjustingCompilations::getAllCompileCommands() const { + return adjustCommands(Compilations->getAllCompileCommands()); +} - std::vector<CompileCommand> - adjustCommands(std::vector<CompileCommand> Commands) const { - for (CompileCommand &Command : Commands) - for (const auto &Adjuster : Adjusters) - Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename); - return Commands; - } -}; -} // namespace +std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands( + std::vector<CompileCommand> Commands) const { + for (CompileCommand &Command : Commands) + for (const auto &Adjuster : Adjusters) + Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename); + return Commands; +} -CommonOptionsParser::CommonOptionsParser( +llvm::Error CommonOptionsParser::init( int &argc, const char **argv, cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { - static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); + static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden, + cl::sub(*cl::AllSubCommands)); static cl::opt<std::string> BuildPath("p", cl::desc("Build path"), - cl::Optional, cl::cat(Category)); + cl::Optional, cl::cat(Category), + cl::sub(*cl::AllSubCommands)); static cl::list<std::string> SourcePaths( cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag, - cl::cat(Category)); + cl::cat(Category), cl::sub(*cl::AllSubCommands)); static cl::list<std::string> ArgsAfter( "extra-arg", cl::desc("Additional argument to append to the compiler command line"), - cl::cat(Category)); + cl::cat(Category), cl::sub(*cl::AllSubCommands)); static cl::list<std::string> ArgsBefore( "extra-arg-before", cl::desc("Additional argument to prepend to the compiler command line"), - cl::cat(Category)); + cl::cat(Category), cl::sub(*cl::AllSubCommands)); + + cl::ResetAllOptionOccurrences(); cl::HideUnrelatedOptions(Category); std::string ErrorMessage; Compilations = FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); - if (!Compilations && !ErrorMessage.empty()) - llvm::errs() << ErrorMessage; - cl::ParseCommandLineOptions(argc, argv, Overview); + if (!ErrorMessage.empty()) + ErrorMessage.append("\n"); + llvm::raw_string_ostream OS(ErrorMessage); + // Stop initializing if command-line option parsing failed. + if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) { + OS.flush(); + return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " + + ErrorMessage, + llvm::inconvertibleErrorCode()); + } + cl::PrintOptionValues(); SourcePathList = SourcePaths; if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) && SourcePathList.empty()) - return; + return llvm::Error::success(); if (!Compilations) { if (!BuildPath.empty()) { Compilations = @@ -146,9 +147,34 @@ CommonOptionsParser::CommonOptionsParser( auto AdjustingCompilations = llvm::make_unique<ArgumentsAdjustingCompilations>( std::move(Compilations)); - AdjustingCompilations->appendArgumentsAdjuster( - getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN)); - AdjustingCompilations->appendArgumentsAdjuster( + Adjuster = + getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN); + Adjuster = combineAdjusters( + std::move(Adjuster), getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); + AdjustingCompilations->appendArgumentsAdjuster(Adjuster); Compilations = std::move(AdjustingCompilations); + return llvm::Error::success(); +} + +llvm::Expected<CommonOptionsParser> CommonOptionsParser::create( + int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { + CommonOptionsParser Parser; + llvm::Error Err = + Parser.init(argc, argv, Category, OccurrencesFlag, Overview); + if (Err) + return std::move(Err); + return std::move(Parser); +} + +CommonOptionsParser::CommonOptionsParser( + int &argc, const char **argv, cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { + llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview); + if (Err) { + llvm::report_fatal_error( + "CommonOptionsParser: failed to parse command-line arguments. " + + llvm::toString(std::move(Err))); + } } diff --git a/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp index 0e835579e04ed..92b76b157dcb0 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp @@ -10,6 +10,9 @@ // This file contains implementations of the CompilationDatabase base class // and the FixedCompilationDatabase. // +// FIXME: Various functions that take a string &ErrorMessage should be upgraded +// to Expected. +// //===----------------------------------------------------------------------===// #include "clang/Tooling/CompilationDatabase.h" @@ -26,6 +29,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Option/Arg.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <sstream> @@ -108,6 +112,15 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir, return DB; } +std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const { + std::vector<CompileCommand> Result; + for (const auto &File : getAllFiles()) { + auto C = getCompileCommands(File); + std::move(C.begin(), C.end(), std::back_inserter(Result)); + } + return Result; +} + CompilationDatabasePlugin::~CompilationDatabasePlugin() {} namespace { @@ -302,8 +315,22 @@ FixedCompilationDatabase::loadFromCommandLine(int &Argc, std::vector<std::string> StrippedArgs; if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg)) return nullptr; - return std::unique_ptr<FixedCompilationDatabase>( - new FixedCompilationDatabase(Directory, StrippedArgs)); + return llvm::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs); +} + +std::unique_ptr<FixedCompilationDatabase> +FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) { + ErrorMsg.clear(); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + llvm::MemoryBuffer::getFile(Path); + if (std::error_code Result = File.getError()) { + ErrorMsg = "Error while opening fixed database: " + Result.message(); + return nullptr; + } + std::vector<std::string> Args{llvm::line_iterator(**File), + llvm::line_iterator()}; + return llvm::make_unique<FixedCompilationDatabase>( + llvm::sys::path::parent_path(Path), std::move(Args)); } FixedCompilationDatabase:: @@ -324,15 +351,21 @@ FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const { return Result; } -std::vector<std::string> -FixedCompilationDatabase::getAllFiles() const { - return std::vector<std::string>(); -} +namespace { -std::vector<CompileCommand> -FixedCompilationDatabase::getAllCompileCommands() const { - return std::vector<CompileCommand>(); -} +class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin { + std::unique_ptr<CompilationDatabase> + loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override { + SmallString<1024> DatabasePath(Directory); + llvm::sys::path::append(DatabasePath, "compile_flags.txt"); + return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage); + } +}; + +static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin> +X("fixed-compilation-database", "Reads plain-text flags file"); + +} // namespace namespace clang { namespace tooling { diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp b/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp index e194b59a6e2b1..6d4f3a3401425 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Core/Replacement.cpp @@ -503,7 +503,7 @@ calculateRangesAfterReplacements(const Replacements &Replaces, std::string(R.getLength(), ' '))); assert(!Err && "Replacements must not conflict since ranges have been merged."); - (void)Err; + llvm::consumeError(std::move(Err)); } return FakeReplaces.merge(Replaces).getAffectedRanges(); } diff --git a/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp b/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp new file mode 100644 index 0000000000000..498d683f8924a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Execution.cpp @@ -0,0 +1,105 @@ +//===- lib/Tooling/Execution.cpp - Implements tool execution framework. ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Execution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" +#include "clang/Tooling/Tooling.h" + +LLVM_INSTANTIATE_REGISTRY(clang::tooling::ToolExecutorPluginRegistry) + +namespace clang { +namespace tooling { + +static llvm::cl::opt<std::string> + ExecutorName("executor", llvm::cl::desc("The name of the executor to use."), + llvm::cl::init("standalone")); + +void InMemoryToolResults::addResult(StringRef Key, StringRef Value) { + KVResults.push_back({Key.str(), Value.str()}); +} + +std::vector<std::pair<std::string, std::string>> +InMemoryToolResults::AllKVResults() { + return KVResults; +} + +void InMemoryToolResults::forEachResult( + llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) { + for (const auto &KV : KVResults) { + Callback(KV.first, KV.second); + } +} + +void ExecutionContext::reportResult(StringRef Key, StringRef Value) { + Results->addResult(Key, Value); +} + +llvm::Error +ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action) { + return execute(std::move(Action), ArgumentsAdjuster()); +} + +llvm::Error ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action, + ArgumentsAdjuster Adjuster) { + std::vector< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions; + Actions.emplace_back(std::move(Action), std::move(Adjuster)); + return execute(Actions); +} + +namespace internal { +llvm::Expected<std::unique_ptr<ToolExecutor>> +createExecutorFromCommandLineArgsImpl(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview) { + auto OptionsParser = + CommonOptionsParser::create(argc, argv, Category, llvm::cl::ZeroOrMore, + /*Overview=*/Overview); + if (!OptionsParser) + return OptionsParser.takeError(); + for (auto I = ToolExecutorPluginRegistry::begin(), + E = ToolExecutorPluginRegistry::end(); + I != E; ++I) { + if (I->getName() != ExecutorName) { + continue; + } + std::unique_ptr<ToolExecutorPlugin> Plugin(I->instantiate()); + llvm::Expected<std::unique_ptr<ToolExecutor>> Executor = + Plugin->create(*OptionsParser); + if (!Executor) { + return llvm::make_error<llvm::StringError>( + llvm::Twine("Failed to create '") + I->getName() + + "': " + llvm::toString(Executor.takeError()) + "\n", + llvm::inconvertibleErrorCode()); + } + return std::move(*Executor); + } + return llvm::make_error<llvm::StringError>( + llvm::Twine("Executor \"") + ExecutorName + "\" is not registered.", + llvm::inconvertibleErrorCode()); +} +} // end namespace internal + +llvm::Expected<std::unique_ptr<ToolExecutor>> +createExecutorFromCommandLineArgs(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview) { + return internal::createExecutorFromCommandLineArgsImpl(argc, argv, Category, + Overview); +} + +// This anchor is used to force the linker to link in the generated object file +// and thus register the StandaloneToolExecutorPlugin. +extern volatile int StandaloneToolExecutorAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED StandaloneToolExecutorAnchorDest = + StandaloneToolExecutorAnchorSource; + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp new file mode 100644 index 0000000000000..7123fc32cec9b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelection.cpp @@ -0,0 +1,453 @@ +//===--- ASTSelection.cpp - Clang refactoring library ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/ASTSelection.h" +#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/SaveAndRestore.h" + +using namespace clang; +using namespace tooling; +using ast_type_traits::DynTypedNode; + +namespace { + +CharSourceRange getLexicalDeclRange(Decl *D, const SourceManager &SM, + const LangOptions &LangOpts) { + if (!isa<ObjCImplDecl>(D)) + return CharSourceRange::getTokenRange(D->getSourceRange()); + // Objective-C implementation declarations end at the '@' instead of the 'end' + // keyword. Use the lexer to find the location right after 'end'. + SourceRange R = D->getSourceRange(); + SourceLocation LocAfterEnd = Lexer::findLocationAfterToken( + R.getEnd(), tok::raw_identifier, SM, LangOpts, + /*SkipTrailingWhitespaceAndNewLine=*/false); + return LocAfterEnd.isValid() + ? CharSourceRange::getCharRange(R.getBegin(), LocAfterEnd) + : CharSourceRange::getTokenRange(R); +} + +/// Constructs the tree of selected AST nodes that either contain the location +/// of the cursor or overlap with the selection range. +class ASTSelectionFinder + : public LexicallyOrderedRecursiveASTVisitor<ASTSelectionFinder> { +public: + ASTSelectionFinder(SourceRange Selection, FileID TargetFile, + const ASTContext &Context) + : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()), + SelectionBegin(Selection.getBegin()), + SelectionEnd(Selection.getBegin() == Selection.getEnd() + ? SourceLocation() + : Selection.getEnd()), + TargetFile(TargetFile), Context(Context) { + // The TU decl is the root of the selected node tree. + SelectionStack.push_back( + SelectedASTNode(DynTypedNode::create(*Context.getTranslationUnitDecl()), + SourceSelectionKind::None)); + } + + Optional<SelectedASTNode> getSelectedASTNode() { + assert(SelectionStack.size() == 1 && "stack was not popped"); + SelectedASTNode Result = std::move(SelectionStack.back()); + SelectionStack.pop_back(); + if (Result.Children.empty()) + return None; + return std::move(Result); + } + + bool TraversePseudoObjectExpr(PseudoObjectExpr *E) { + // Avoid traversing the semantic expressions. They should be handled by + // looking through the appropriate opaque expressions in order to build + // a meaningful selection tree. + llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, true); + return TraverseStmt(E->getSyntacticForm()); + } + + bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) { + if (!LookThroughOpaqueValueExprs) + return true; + llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, false); + return TraverseStmt(E->getSourceExpr()); + } + + bool TraverseDecl(Decl *D) { + if (isa<TranslationUnitDecl>(D)) + return LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D); + if (D->isImplicit()) + return true; + + // Check if this declaration is written in the file of interest. + const SourceRange DeclRange = D->getSourceRange(); + const SourceManager &SM = Context.getSourceManager(); + SourceLocation FileLoc; + if (DeclRange.getBegin().isMacroID() && !DeclRange.getEnd().isMacroID()) + FileLoc = DeclRange.getEnd(); + else + FileLoc = SM.getSpellingLoc(DeclRange.getBegin()); + if (SM.getFileID(FileLoc) != TargetFile) + return true; + + SourceSelectionKind SelectionKind = + selectionKindFor(getLexicalDeclRange(D, SM, Context.getLangOpts())); + SelectionStack.push_back( + SelectedASTNode(DynTypedNode::create(*D), SelectionKind)); + LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D); + popAndAddToSelectionIfSelected(SelectionKind); + + if (DeclRange.getEnd().isValid() && + SM.isBeforeInTranslationUnit(SelectionEnd.isValid() ? SelectionEnd + : SelectionBegin, + DeclRange.getEnd())) { + // Stop early when we've reached a declaration after the selection. + return false; + } + return true; + } + + bool TraverseStmt(Stmt *S) { + if (!S) + return true; + if (auto *Opaque = dyn_cast<OpaqueValueExpr>(S)) + return TraverseOpaqueValueExpr(Opaque); + // Avoid selecting implicit 'this' expressions. + if (auto *TE = dyn_cast<CXXThisExpr>(S)) { + if (TE->isImplicit()) + return true; + } + // FIXME (Alex Lorenz): Improve handling for macro locations. + SourceSelectionKind SelectionKind = + selectionKindFor(CharSourceRange::getTokenRange(S->getSourceRange())); + SelectionStack.push_back( + SelectedASTNode(DynTypedNode::create(*S), SelectionKind)); + LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S); + popAndAddToSelectionIfSelected(SelectionKind); + return true; + } + +private: + void popAndAddToSelectionIfSelected(SourceSelectionKind SelectionKind) { + SelectedASTNode Node = std::move(SelectionStack.back()); + SelectionStack.pop_back(); + if (SelectionKind != SourceSelectionKind::None || !Node.Children.empty()) + SelectionStack.back().Children.push_back(std::move(Node)); + } + + SourceSelectionKind selectionKindFor(CharSourceRange Range) { + SourceLocation End = Range.getEnd(); + const SourceManager &SM = Context.getSourceManager(); + if (Range.isTokenRange()) + End = Lexer::getLocForEndOfToken(End, 0, SM, Context.getLangOpts()); + if (!SourceLocation::isPairOfFileLocations(Range.getBegin(), End)) + return SourceSelectionKind::None; + if (!SelectionEnd.isValid()) { + // Do a quick check when the selection is of length 0. + if (SM.isPointWithin(SelectionBegin, Range.getBegin(), End)) + return SourceSelectionKind::ContainsSelection; + return SourceSelectionKind::None; + } + bool HasStart = SM.isPointWithin(SelectionBegin, Range.getBegin(), End); + bool HasEnd = SM.isPointWithin(SelectionEnd, Range.getBegin(), End); + if (HasStart && HasEnd) + return SourceSelectionKind::ContainsSelection; + if (SM.isPointWithin(Range.getBegin(), SelectionBegin, SelectionEnd) && + SM.isPointWithin(End, SelectionBegin, SelectionEnd)) + return SourceSelectionKind::InsideSelection; + // Ensure there's at least some overlap with the 'start'/'end' selection + // types. + if (HasStart && SelectionBegin != End) + return SourceSelectionKind::ContainsSelectionStart; + if (HasEnd && SelectionEnd != Range.getBegin()) + return SourceSelectionKind::ContainsSelectionEnd; + + return SourceSelectionKind::None; + } + + const SourceLocation SelectionBegin, SelectionEnd; + FileID TargetFile; + const ASTContext &Context; + std::vector<SelectedASTNode> SelectionStack; + /// Controls whether we can traverse through the OpaqueValueExpr. This is + /// typically enabled during the traversal of syntactic form for + /// PseudoObjectExprs. + bool LookThroughOpaqueValueExprs = false; +}; + +} // end anonymous namespace + +Optional<SelectedASTNode> +clang::tooling::findSelectedASTNodes(const ASTContext &Context, + SourceRange SelectionRange) { + assert(SelectionRange.isValid() && + SourceLocation::isPairOfFileLocations(SelectionRange.getBegin(), + SelectionRange.getEnd()) && + "Expected a file range"); + FileID TargetFile = + Context.getSourceManager().getFileID(SelectionRange.getBegin()); + assert(Context.getSourceManager().getFileID(SelectionRange.getEnd()) == + TargetFile && + "selection range must span one file"); + + ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context); + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + return Visitor.getSelectedASTNode(); +} + +static const char *selectionKindToString(SourceSelectionKind Kind) { + switch (Kind) { + case SourceSelectionKind::None: + return "none"; + case SourceSelectionKind::ContainsSelection: + return "contains-selection"; + case SourceSelectionKind::ContainsSelectionStart: + return "contains-selection-start"; + case SourceSelectionKind::ContainsSelectionEnd: + return "contains-selection-end"; + case SourceSelectionKind::InsideSelection: + return "inside"; + } + llvm_unreachable("invalid selection kind"); +} + +static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS, + unsigned Indent = 0) { + OS.indent(Indent * 2); + if (const Decl *D = Node.Node.get<Decl>()) { + OS << D->getDeclKindName() << "Decl"; + if (const auto *ND = dyn_cast<NamedDecl>(D)) + OS << " \"" << ND->getNameAsString() << '"'; + } else if (const Stmt *S = Node.Node.get<Stmt>()) { + OS << S->getStmtClassName(); + } + OS << ' ' << selectionKindToString(Node.SelectionKind) << "\n"; + for (const auto &Child : Node.Children) + dump(Child, OS, Indent + 1); +} + +void SelectedASTNode::dump(llvm::raw_ostream &OS) const { ::dump(*this, OS); } + +/// Returns true if the given node has any direct children with the following +/// selection kind. +/// +/// Note: The direct children also include children of direct children with the +/// "None" selection kind. +static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node, + SourceSelectionKind Kind) { + assert(Kind != SourceSelectionKind::None && "invalid predicate!"); + for (const auto &Child : Node.Children) { + if (Child.SelectionKind == Kind) + return true; + if (Child.SelectionKind == SourceSelectionKind::None) + return hasAnyDirectChildrenWithKind(Child, Kind); + } + return false; +} + +namespace { +struct SelectedNodeWithParents { + SelectedNodeWithParents(SelectedNodeWithParents &&) = default; + SelectedNodeWithParents &operator=(SelectedNodeWithParents &&) = default; + SelectedASTNode::ReferenceType Node; + llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents; + + /// Canonicalizes the given selection by selecting different related AST nodes + /// when it makes sense to do so. + void canonicalize(); +}; + +enum SelectionCanonicalizationAction { KeepSelection, SelectParent }; + +/// Returns the canonicalization action which should be applied to the +/// selected statement. +SelectionCanonicalizationAction +getSelectionCanonizalizationAction(const Stmt *S, const Stmt *Parent) { + // Select the parent expression when: + // - The string literal in ObjC string literal is selected, e.g.: + // @"test" becomes @"test" + // ~~~~~~ ~~~~~~~ + if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent)) + return SelectParent; + // The entire call should be selected when just the member expression + // that refers to the method or the decl ref that refers to the function + // is selected. + // f.call(args) becomes f.call(args) + // ~~~~ ~~~~~~~~~~~~ + // func(args) becomes func(args) + // ~~~~ ~~~~~~~~~~ + else if (const auto *CE = dyn_cast<CallExpr>(Parent)) { + if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) && + CE->getCallee()->IgnoreImpCasts() == S) + return SelectParent; + } + // FIXME: Syntactic form -> Entire pseudo-object expr. + return KeepSelection; +} + +} // end anonymous namespace + +void SelectedNodeWithParents::canonicalize() { + const Stmt *S = Node.get().Node.get<Stmt>(); + assert(S && "non statement selection!"); + const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>(); + if (!Parent) + return; + + // Look through the implicit casts in the parents. + unsigned ParentIndex = 1; + for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(Parent); + ++ParentIndex) { + const Stmt *NewParent = + Parents[Parents.size() - ParentIndex - 1].get().Node.get<Stmt>(); + if (!NewParent) + break; + Parent = NewParent; + } + + switch (getSelectionCanonizalizationAction(S, Parent)) { + case SelectParent: + Node = Parents[Parents.size() - ParentIndex]; + for (; ParentIndex != 0; --ParentIndex) + Parents.pop_back(); + break; + case KeepSelection: + break; + } +} + +/// Finds the set of bottom-most selected AST nodes that are in the selection +/// tree with the specified selection kind. +/// +/// For example, given the following selection tree: +/// +/// FunctionDecl "f" contains-selection +/// CompoundStmt contains-selection [#1] +/// CallExpr inside +/// ImplicitCastExpr inside +/// DeclRefExpr inside +/// IntegerLiteral inside +/// IntegerLiteral inside +/// FunctionDecl "f2" contains-selection +/// CompoundStmt contains-selection [#2] +/// CallExpr inside +/// ImplicitCastExpr inside +/// DeclRefExpr inside +/// IntegerLiteral inside +/// IntegerLiteral inside +/// +/// This function will find references to nodes #1 and #2 when searching for the +/// \c ContainsSelection kind. +static void findDeepestWithKind( + const SelectedASTNode &ASTSelection, + llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes, + SourceSelectionKind Kind, + llvm::SmallVectorImpl<SelectedASTNode::ReferenceType> &ParentStack) { + if (ASTSelection.Node.get<DeclStmt>()) { + // Select the entire decl stmt when any of its child declarations is the + // bottom-most. + for (const auto &Child : ASTSelection.Children) { + if (!hasAnyDirectChildrenWithKind(Child, Kind)) { + MatchingNodes.push_back(SelectedNodeWithParents{ + std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}}); + return; + } + } + } else { + if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) { + // This node is the bottom-most. + MatchingNodes.push_back(SelectedNodeWithParents{ + std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}}); + return; + } + } + // Search in the children. + ParentStack.push_back(std::cref(ASTSelection)); + for (const auto &Child : ASTSelection.Children) + findDeepestWithKind(Child, MatchingNodes, Kind, ParentStack); + ParentStack.pop_back(); +} + +static void findDeepestWithKind( + const SelectedASTNode &ASTSelection, + llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes, + SourceSelectionKind Kind) { + llvm::SmallVector<SelectedASTNode::ReferenceType, 16> ParentStack; + findDeepestWithKind(ASTSelection, MatchingNodes, Kind, ParentStack); +} + +Optional<CodeRangeASTSelection> +CodeRangeASTSelection::create(SourceRange SelectionRange, + const SelectedASTNode &ASTSelection) { + // Code range is selected when the selection range is not empty. + if (SelectionRange.getBegin() == SelectionRange.getEnd()) + return None; + llvm::SmallVector<SelectedNodeWithParents, 4> ContainSelection; + findDeepestWithKind(ASTSelection, ContainSelection, + SourceSelectionKind::ContainsSelection); + // We are looking for a selection in one body of code, so let's focus on + // one matching result. + if (ContainSelection.size() != 1) + return None; + SelectedNodeWithParents &Selected = ContainSelection[0]; + if (!Selected.Node.get().Node.get<Stmt>()) + return None; + const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>(); + if (!isa<CompoundStmt>(CodeRangeStmt)) { + Selected.canonicalize(); + return CodeRangeASTSelection(Selected.Node, Selected.Parents, + /*AreChildrenSelected=*/false); + } + // FIXME (Alex L): First selected SwitchCase means that first case statement. + // is selected actually + // (See https://github.com/apple/swift-clang & CompoundStmtRange). + + // FIXME (Alex L): Tweak selection rules for compound statements, see: + // https://github.com/apple/swift-clang/blob/swift-4.1-branch/lib/Tooling/ + // Refactor/ASTSlice.cpp#L513 + // The user selected multiple statements in a compound statement. + Selected.Parents.push_back(Selected.Node); + return CodeRangeASTSelection(Selected.Node, Selected.Parents, + /*AreChildrenSelected=*/true); +} + +static bool isFunctionLikeDeclaration(const Decl *D) { + // FIXME (Alex L): Test for BlockDecl. + return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D); +} + +bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const { + bool IsPrevCompound = false; + // Scan through the parents (bottom-to-top) and check if the selection is + // contained in a compound statement that's a body of a function/method + // declaration. + for (const auto &Parent : llvm::reverse(Parents)) { + const DynTypedNode &Node = Parent.get().Node; + if (const auto *D = Node.get<Decl>()) { + if (isFunctionLikeDeclaration(D)) + return IsPrevCompound; + // Stop the search at any type declaration to avoid returning true for + // expressions in type declarations in functions, like: + // function foo() { struct X { + // int m = /*selection:*/ 1 + 2 /*selection end*/; }; }; + if (isa<TypeDecl>(D)) + return false; + } + IsPrevCompound = Node.get<CompoundStmt>() != nullptr; + } + return false; +} + +const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const { + for (const auto &Parent : llvm::reverse(Parents)) { + const DynTypedNode &Node = Parent.get().Node; + if (const auto *D = Node.get<Decl>()) { + if (isFunctionLikeDeclaration(D)) + return D; + } + } + return nullptr; +} diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp new file mode 100644 index 0000000000000..c0232c5da4429 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp @@ -0,0 +1,48 @@ +//===--- ASTSelectionRequirements.cpp - Clang refactoring library ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" + +using namespace clang; +using namespace tooling; + +Expected<SelectedASTNode> +ASTSelectionRequirement::evaluate(RefactoringRuleContext &Context) const { + // FIXME: Memoize so that selection is evaluated only once. + Expected<SourceRange> Range = + SourceRangeSelectionRequirement::evaluate(Context); + if (!Range) + return Range.takeError(); + + Optional<SelectedASTNode> Selection = + findSelectedASTNodes(Context.getASTContext(), *Range); + if (!Selection) + return Context.createDiagnosticError( + Range->getBegin(), diag::err_refactor_selection_invalid_ast); + return std::move(*Selection); +} + +Expected<CodeRangeASTSelection> CodeRangeASTSelectionRequirement::evaluate( + RefactoringRuleContext &Context) const { + // FIXME: Memoize so that selection is evaluated only once. + Expected<SelectedASTNode> ASTSelection = + ASTSelectionRequirement::evaluate(Context); + if (!ASTSelection) + return ASTSelection.takeError(); + std::unique_ptr<SelectedASTNode> StoredSelection = + llvm::make_unique<SelectedASTNode>(std::move(*ASTSelection)); + Optional<CodeRangeASTSelection> CodeRange = CodeRangeASTSelection::create( + Context.getSelectionRange(), *StoredSelection); + if (!CodeRange) + return Context.createDiagnosticError( + Context.getSelectionRange().getBegin(), + diag::err_refactor_selection_invalid_ast); + Context.setASTSelection(std::move(StoredSelection)); + return std::move(*CodeRange); +} diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp index 79dd346acf72f..e4cc6a5617b65 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp @@ -83,6 +83,116 @@ template <> struct MappingTraits<clang::tooling::AtomicChange> { namespace clang { namespace tooling { +namespace { + +// Returns true if there is any line that violates \p ColumnLimit in range +// [Start, End]. +bool violatesColumnLimit(llvm::StringRef Code, unsigned ColumnLimit, + unsigned Start, unsigned End) { + auto StartPos = Code.rfind('\n', Start); + StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1; + + auto EndPos = Code.find("\n", End); + if (EndPos == llvm::StringRef::npos) + EndPos = Code.size(); + + llvm::SmallVector<llvm::StringRef, 8> Lines; + Code.substr(StartPos, EndPos - StartPos).split(Lines, '\n'); + for (llvm::StringRef Line : Lines) + if (Line.size() > ColumnLimit) + return true; + return false; +} + +std::vector<Range> +getRangesForFormating(llvm::StringRef Code, unsigned ColumnLimit, + ApplyChangesSpec::FormatOption Format, + const clang::tooling::Replacements &Replaces) { + // kNone suppresses formatting entirely. + if (Format == ApplyChangesSpec::kNone) + return {}; + std::vector<clang::tooling::Range> Ranges; + // This works assuming that replacements are ordered by offset. + // FIXME: use `getAffectedRanges()` to calculate when it does not include '\n' + // at the end of an insertion in affected ranges. + int Offset = 0; + for (const clang::tooling::Replacement &R : Replaces) { + int Start = R.getOffset() + Offset; + int End = Start + R.getReplacementText().size(); + if (!R.getReplacementText().empty() && + R.getReplacementText().back() == '\n' && R.getLength() == 0 && + R.getOffset() > 0 && R.getOffset() <= Code.size() && + Code[R.getOffset() - 1] == '\n') + // If we are inserting at the start of a line and the replacement ends in + // a newline, we don't need to format the subsequent line. + --End; + Offset += R.getReplacementText().size() - R.getLength(); + + if (Format == ApplyChangesSpec::kAll || + violatesColumnLimit(Code, ColumnLimit, Start, End)) + Ranges.emplace_back(Start, End - Start); + } + return Ranges; +} + +inline llvm::Error make_string_error(const llvm::Twine &Message) { + return llvm::make_error<llvm::StringError>(Message, + llvm::inconvertibleErrorCode()); +} + +// Creates replacements for inserting/deleting #include headers. +llvm::Expected<Replacements> +createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code, + llvm::ArrayRef<AtomicChange> Changes, + const format::FormatStyle &Style) { + // Create header insertion/deletion replacements to be cleaned up + // (i.e. converted to real insertion/deletion replacements). + Replacements HeaderReplacements; + for (const auto &Change : Changes) { + for (llvm::StringRef Header : Change.getInsertedHeaders()) { + std::string EscapedHeader = + Header.startswith("<") || Header.startswith("\"") + ? Header.str() + : ("\"" + Header + "\"").str(); + std::string ReplacementText = "#include " + EscapedHeader; + // Offset UINT_MAX and length 0 indicate that the replacement is a header + // insertion. + llvm::Error Err = HeaderReplacements.add( + tooling::Replacement(FilePath, UINT_MAX, 0, ReplacementText)); + if (Err) + return std::move(Err); + } + for (const std::string &Header : Change.getRemovedHeaders()) { + // Offset UINT_MAX and length 1 indicate that the replacement is a header + // deletion. + llvm::Error Err = + HeaderReplacements.add(Replacement(FilePath, UINT_MAX, 1, Header)); + if (Err) + return std::move(Err); + } + } + + // cleanupAroundReplacements() converts header insertions/deletions into + // actual replacements that add/remove headers at the right location. + return clang::format::cleanupAroundReplacements(Code, HeaderReplacements, + Style); +} + +// Combine replacements in all Changes as a `Replacements`. This ignores the +// file path in all replacements and replaces them with \p FilePath. +llvm::Expected<Replacements> +combineReplacementsInChanges(llvm::StringRef FilePath, + llvm::ArrayRef<AtomicChange> Changes) { + Replacements Replaces; + for (const auto &Change : Changes) + for (const auto &R : Change.getReplacements()) + if (auto Err = Replaces.add(Replacement( + FilePath, R.getOffset(), R.getLength(), R.getReplacementText()))) + return std::move(Err); + return Replaces; +} + +} // end namespace AtomicChange::AtomicChange(const SourceManager &SM, SourceLocation KeyPosition) { @@ -105,6 +215,15 @@ AtomicChange::AtomicChange(std::string Key, std::string FilePath, RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) { } +bool AtomicChange::operator==(const AtomicChange &Other) const { + if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error) + return false; + if (!(Replaces == Other.Replaces)) + return false; + // FXIME: Compare header insertions/removals. + return true; +} + std::string AtomicChange::toYAMLString() { std::string YamlContent; llvm::raw_string_ostream YamlContentStream(YamlContent); @@ -173,5 +292,74 @@ void AtomicChange::removeHeader(llvm::StringRef Header) { RemovedHeaders.push_back(Header); } +llvm::Expected<std::string> +applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code, + llvm::ArrayRef<AtomicChange> Changes, + const ApplyChangesSpec &Spec) { + llvm::Expected<Replacements> HeaderReplacements = + createReplacementsForHeaders(FilePath, Code, Changes, Spec.Style); + if (!HeaderReplacements) + return make_string_error( + "Failed to create replacements for header changes: " + + llvm::toString(HeaderReplacements.takeError())); + + llvm::Expected<Replacements> Replaces = + combineReplacementsInChanges(FilePath, Changes); + if (!Replaces) + return make_string_error("Failed to combine replacements in all changes: " + + llvm::toString(Replaces.takeError())); + + Replacements AllReplaces = std::move(*Replaces); + for (const auto &R : *HeaderReplacements) { + llvm::Error Err = AllReplaces.add(R); + if (Err) + return make_string_error( + "Failed to combine existing replacements with header replacements: " + + llvm::toString(std::move(Err))); + } + + if (Spec.Cleanup) { + llvm::Expected<Replacements> CleanReplaces = + format::cleanupAroundReplacements(Code, AllReplaces, Spec.Style); + if (!CleanReplaces) + return make_string_error("Failed to cleanup around replacements: " + + llvm::toString(CleanReplaces.takeError())); + AllReplaces = std::move(*CleanReplaces); + } + + // Apply all replacements. + llvm::Expected<std::string> ChangedCode = + applyAllReplacements(Code, AllReplaces); + if (!ChangedCode) + return make_string_error("Failed to apply all replacements: " + + llvm::toString(ChangedCode.takeError())); + + // Sort inserted headers. This is done even if other formatting is turned off + // as incorrectly sorted headers are always just wrong, it's not a matter of + // taste. + Replacements HeaderSortingReplacements = format::sortIncludes( + Spec.Style, *ChangedCode, AllReplaces.getAffectedRanges(), FilePath); + ChangedCode = applyAllReplacements(*ChangedCode, HeaderSortingReplacements); + if (!ChangedCode) + return make_string_error( + "Failed to apply replacements for sorting includes: " + + llvm::toString(ChangedCode.takeError())); + + AllReplaces = AllReplaces.merge(HeaderSortingReplacements); + + std::vector<Range> FormatRanges = getRangesForFormating( + *ChangedCode, Spec.Style.ColumnLimit, Spec.Format, AllReplaces); + if (!FormatRanges.empty()) { + Replacements FormatReplacements = + format::reformat(Spec.Style, *ChangedCode, FormatRanges, FilePath); + ChangedCode = applyAllReplacements(*ChangedCode, FormatReplacements); + if (!ChangedCode) + return make_string_error( + "Failed to apply replacements for formatting changed code: " + + llvm::toString(ChangedCode.takeError())); + } + return ChangedCode; +} + } // end namespace tooling } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp new file mode 100644 index 0000000000000..b0847a7400481 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/Extract.cpp @@ -0,0 +1,199 @@ +//===--- Extract.cpp - Clang refactoring library --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements the "extract" refactoring that can pull code into +/// new functions, methods or declare new variables. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Extract/Extract.h" +#include "SourceExtraction.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Rewrite/Core/Rewriter.h" + +namespace clang { +namespace tooling { + +namespace { + +/// Returns true if \c E is a simple literal or a reference expression that +/// should not be extracted. +bool isSimpleExpression(const Expr *E) { + if (!E) + return false; + switch (E->IgnoreParenCasts()->getStmtClass()) { + case Stmt::DeclRefExprClass: + case Stmt::PredefinedExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + return true; + default: + return false; + } +} + +SourceLocation computeFunctionExtractionLocation(const Decl *D) { + if (isa<CXXMethodDecl>(D)) { + // Code from method that is defined in class body should be extracted to a + // function defined just before the class. + while (const auto *RD = dyn_cast<CXXRecordDecl>(D->getLexicalDeclContext())) + D = RD; + } + return D->getLocStart(); +} + +} // end anonymous namespace + +const RefactoringDescriptor &ExtractFunction::describe() { + static const RefactoringDescriptor Descriptor = { + "extract-function", + "Extract Function", + "(WIP action; use with caution!) Extracts code into a new function", + }; + return Descriptor; +} + +Expected<ExtractFunction> +ExtractFunction::initiate(RefactoringRuleContext &Context, + CodeRangeASTSelection Code, + Optional<std::string> DeclName) { + // We would like to extract code out of functions/methods/blocks. + // Prohibit extraction from things like global variable / field + // initializers and other top-level expressions. + if (!Code.isInFunctionLikeBodyOfCode()) + return Context.createDiagnosticError( + diag::err_refactor_code_outside_of_function); + + if (Code.size() == 1) { + // Avoid extraction of simple literals and references. + if (isSimpleExpression(dyn_cast<Expr>(Code[0]))) + return Context.createDiagnosticError( + diag::err_refactor_extract_simple_expression); + + // Property setters can't be extracted. + if (const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(Code[0])) { + if (!PRE->isMessagingGetter()) + return Context.createDiagnosticError( + diag::err_refactor_extract_prohibited_expression); + } + } + + return ExtractFunction(std::move(Code), DeclName); +} + +// FIXME: Support C++ method extraction. +// FIXME: Support Objective-C method extraction. +Expected<AtomicChanges> +ExtractFunction::createSourceReplacements(RefactoringRuleContext &Context) { + const Decl *ParentDecl = Code.getFunctionLikeNearestParent(); + assert(ParentDecl && "missing parent"); + + // Compute the source range of the code that should be extracted. + SourceRange ExtractedRange(Code[0]->getLocStart(), + Code[Code.size() - 1]->getLocEnd()); + // FIXME (Alex L): Add code that accounts for macro locations. + + ASTContext &AST = Context.getASTContext(); + SourceManager &SM = AST.getSourceManager(); + const LangOptions &LangOpts = AST.getLangOpts(); + Rewriter ExtractedCodeRewriter(SM, LangOpts); + + // FIXME: Capture used variables. + + // Compute the return type. + QualType ReturnType = AST.VoidTy; + // FIXME (Alex L): Account for the return statement in extracted code. + // FIXME (Alex L): Check for lexical expression instead. + bool IsExpr = Code.size() == 1 && isa<Expr>(Code[0]); + if (IsExpr) { + // FIXME (Alex L): Get a more user-friendly type if needed. + ReturnType = cast<Expr>(Code[0])->getType(); + } + + // FIXME: Rewrite the extracted code performing any required adjustments. + + // FIXME: Capture any field if necessary (method -> function extraction). + + // FIXME: Sort captured variables by name. + + // FIXME: Capture 'this' / 'self' if necessary. + + // FIXME: Compute the actual parameter types. + + // Compute the location of the extracted declaration. + SourceLocation ExtractedDeclLocation = + computeFunctionExtractionLocation(ParentDecl); + // FIXME: Adjust the location to account for any preceding comments. + + // FIXME: Adjust with PP awareness like in Sema to get correct 'bool' + // treatment. + PrintingPolicy PP = AST.getPrintingPolicy(); + // FIXME: PP.UseStdFunctionForLambda = true; + PP.SuppressStrongLifetime = true; + PP.SuppressLifetimeQualifiers = true; + PP.SuppressUnwrittenScope = true; + + ExtractionSemicolonPolicy Semicolons = ExtractionSemicolonPolicy::compute( + Code[Code.size() - 1], ExtractedRange, SM, LangOpts); + AtomicChange Change(SM, ExtractedDeclLocation); + // Create the replacement for the extracted declaration. + { + std::string ExtractedCode; + llvm::raw_string_ostream OS(ExtractedCode); + // FIXME: Use 'inline' in header. + OS << "static "; + ReturnType.print(OS, PP, DeclName); + OS << '('; + // FIXME: Arguments. + OS << ')'; + + // Function body. + OS << " {\n"; + if (IsExpr && !ReturnType->isVoidType()) + OS << "return "; + OS << ExtractedCodeRewriter.getRewrittenText(ExtractedRange); + if (Semicolons.isNeededInExtractedFunction()) + OS << ';'; + OS << "\n}\n\n"; + auto Err = Change.insert(SM, ExtractedDeclLocation, OS.str()); + if (Err) + return std::move(Err); + } + + // Create the replacement for the call to the extracted declaration. + { + std::string ReplacedCode; + llvm::raw_string_ostream OS(ReplacedCode); + + OS << DeclName << '('; + // FIXME: Forward arguments. + OS << ')'; + if (Semicolons.isNeededInOriginalFunction()) + OS << ';'; + + auto Err = Change.replace( + SM, CharSourceRange::getTokenRange(ExtractedRange), OS.str()); + if (Err) + return std::move(Err); + } + + // FIXME: Add support for assocciated symbol location to AtomicChange to mark + // the ranges of the name of the extracted declaration. + return AtomicChanges{std::move(Change)}; +} + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp new file mode 100644 index 0000000000000..7fd8cc2d3c7fb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp @@ -0,0 +1,112 @@ +//===--- SourceExtraction.cpp - Clang refactoring library -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SourceExtraction.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" + +using namespace clang; + +namespace { + +/// Returns true if the token at the given location is a semicolon. +bool isSemicolonAtLocation(SourceLocation TokenLoc, const SourceManager &SM, + const LangOptions &LangOpts) { + return Lexer::getSourceText( + CharSourceRange::getTokenRange(TokenLoc, TokenLoc), SM, + LangOpts) == ";"; +} + +/// Returns true if there should be a semicolon after the given statement. +bool isSemicolonRequiredAfter(const Stmt *S) { + if (isa<CompoundStmt>(S)) + return false; + if (const auto *If = dyn_cast<IfStmt>(S)) + return isSemicolonRequiredAfter(If->getElse() ? If->getElse() + : If->getThen()); + if (const auto *While = dyn_cast<WhileStmt>(S)) + return isSemicolonRequiredAfter(While->getBody()); + if (const auto *For = dyn_cast<ForStmt>(S)) + return isSemicolonRequiredAfter(For->getBody()); + if (const auto *CXXFor = dyn_cast<CXXForRangeStmt>(S)) + return isSemicolonRequiredAfter(CXXFor->getBody()); + if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(S)) + return isSemicolonRequiredAfter(ObjCFor->getBody()); + switch (S->getStmtClass()) { + case Stmt::SwitchStmtClass: + case Stmt::CXXTryStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAutoreleasePoolStmtClass: + case Stmt::ObjCAtTryStmtClass: + return false; + default: + return true; + } +} + +/// Returns true if the two source locations are on the same line. +bool areOnSameLine(SourceLocation Loc1, SourceLocation Loc2, + const SourceManager &SM) { + return !Loc1.isMacroID() && !Loc2.isMacroID() && + SM.getSpellingLineNumber(Loc1) == SM.getSpellingLineNumber(Loc2); +} + +} // end anonymous namespace + +namespace clang { +namespace tooling { + +ExtractionSemicolonPolicy +ExtractionSemicolonPolicy::compute(const Stmt *S, SourceRange &ExtractedRange, + const SourceManager &SM, + const LangOptions &LangOpts) { + auto neededInExtractedFunction = []() { + return ExtractionSemicolonPolicy(true, false); + }; + auto neededInOriginalFunction = []() { + return ExtractionSemicolonPolicy(false, true); + }; + + /// The extracted expression should be terminated with a ';'. The call to + /// the extracted function will replace this expression, so it won't need + /// a terminating ';'. + if (isa<Expr>(S)) + return neededInExtractedFunction(); + + /// Some statements don't need to be terminated with ';'. The call to the + /// extracted function will be a standalone statement, so it should be + /// terminated with a ';'. + bool NeedsSemi = isSemicolonRequiredAfter(S); + if (!NeedsSemi) + return neededInOriginalFunction(); + + /// Some statements might end at ';'. The extraction will move that ';', so + /// the call to the extracted function should be terminated with a ';'. + SourceLocation End = ExtractedRange.getEnd(); + if (isSemicolonAtLocation(End, SM, LangOpts)) + return neededInOriginalFunction(); + + /// Other statements should generally have a trailing ';'. We can try to find + /// it and move it together it with the extracted code. + Optional<Token> NextToken = Lexer::findNextToken(End, SM, LangOpts); + if (NextToken && NextToken->is(tok::semi) && + areOnSameLine(NextToken->getLocation(), End, SM)) { + ExtractedRange.setEnd(NextToken->getLocation()); + return neededInOriginalFunction(); + } + + /// Otherwise insert semicolons in both places. + return ExtractionSemicolonPolicy(true, true); +} + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h new file mode 100644 index 0000000000000..4b4bd8b477ff4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.h @@ -0,0 +1,52 @@ +//===--- SourceExtraction.cpp - Clang refactoring library -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H +#define LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + +class LangOptions; +class SourceManager; +class SourceRange; +class Stmt; + +namespace tooling { + +/// Determines which semicolons should be inserted during extraction. +class ExtractionSemicolonPolicy { +public: + bool isNeededInExtractedFunction() const { + return IsNeededInExtractedFunction; + } + + bool isNeededInOriginalFunction() const { return IsNeededInOriginalFunction; } + + /// Returns the semicolon insertion policy that is needed for extraction of + /// the given statement from the given source range. + static ExtractionSemicolonPolicy compute(const Stmt *S, + SourceRange &ExtractedRange, + const SourceManager &SM, + const LangOptions &LangOpts); + +private: + ExtractionSemicolonPolicy(bool IsNeededInExtractedFunction, + bool IsNeededInOriginalFunction) + : IsNeededInExtractedFunction(IsNeededInExtractedFunction), + IsNeededInOriginalFunction(IsNeededInOriginalFunction) {} + bool IsNeededInExtractedFunction; + bool IsNeededInOriginalFunction; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp new file mode 100644 index 0000000000000..37a1639cb4464 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/RefactoringActions.cpp @@ -0,0 +1,114 @@ +//===--- RefactoringActions.cpp - Constructs refactoring actions ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Extract/Extract.h" +#include "clang/Tooling/Refactoring/RefactoringAction.h" +#include "clang/Tooling/Refactoring/RefactoringOptions.h" +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h" + +namespace clang { +namespace tooling { + +namespace { + +class DeclNameOption final : public OptionalRefactoringOption<std::string> { +public: + StringRef getName() const { return "name"; } + StringRef getDescription() const { + return "Name of the extracted declaration"; + } +}; + +// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with +// rules. +class ExtractRefactoring final : public RefactoringAction { +public: + StringRef getCommand() const override { return "extract"; } + + StringRef getDescription() const override { + return "(WIP action; use with caution!) Extracts code into a new function"; + } + + /// Returns a set of refactoring actions rules that are defined by this + /// action. + RefactoringActionRules createActionRules() const override { + RefactoringActionRules Rules; + Rules.push_back(createRefactoringActionRule<ExtractFunction>( + CodeRangeASTSelectionRequirement(), + OptionRequirement<DeclNameOption>())); + return Rules; + } +}; + +class OldQualifiedNameOption : public RequiredRefactoringOption<std::string> { +public: + StringRef getName() const override { return "old-qualified-name"; } + StringRef getDescription() const override { + return "The old qualified name to be renamed"; + } +}; + +class NewQualifiedNameOption : public RequiredRefactoringOption<std::string> { +public: + StringRef getName() const override { return "new-qualified-name"; } + StringRef getDescription() const override { + return "The new qualified name to change the symbol to"; + } +}; + +class NewNameOption : public RequiredRefactoringOption<std::string> { +public: + StringRef getName() const override { return "new-name"; } + StringRef getDescription() const override { + return "The new name to change the symbol to"; + } +}; + +// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with +// rules. +class LocalRename final : public RefactoringAction { +public: + StringRef getCommand() const override { return "local-rename"; } + + StringRef getDescription() const override { + return "Finds and renames symbols in code with no indexer support"; + } + + /// Returns a set of refactoring actions rules that are defined by this + /// action. + RefactoringActionRules createActionRules() const override { + RefactoringActionRules Rules; + Rules.push_back(createRefactoringActionRule<RenameOccurrences>( + SourceRangeSelectionRequirement(), OptionRequirement<NewNameOption>())); + // FIXME: Use NewNameOption. + Rules.push_back(createRefactoringActionRule<QualifiedRenameRule>( + OptionRequirement<OldQualifiedNameOption>(), + OptionRequirement<NewQualifiedNameOption>())); + return Rules; + } +}; + +} // end anonymous namespace + +std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() { + std::vector<std::unique_ptr<RefactoringAction>> Actions; + + Actions.push_back(llvm::make_unique<LocalRename>()); + Actions.push_back(llvm::make_unique<ExtractRefactoring>()); + + return Actions; +} + +RefactoringActionRules RefactoringAction::createActiveActionRules() { + // FIXME: Filter out rules that are not supported by a particular client. + return createActionRules(); +} + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp index de6aba944a4aa..c8ed9dd19a8e8 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp @@ -22,8 +22,17 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/RefactoringAction.h" +#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" +#include "clang/Tooling/Refactoring/RefactoringOptions.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" +#include "clang/Tooling/Refactoring/Rename/USRFinder.h" +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h" #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include <string> #include <vector> @@ -32,6 +41,143 @@ using namespace llvm; namespace clang { namespace tooling { +namespace { + +Expected<SymbolOccurrences> +findSymbolOccurrences(const NamedDecl *ND, RefactoringRuleContext &Context) { + std::vector<std::string> USRs = + getUSRsForDeclaration(ND, Context.getASTContext()); + std::string PrevName = ND->getNameAsString(); + return getOccurrencesOfUSRs(USRs, PrevName, + Context.getASTContext().getTranslationUnitDecl()); +} + +} // end anonymous namespace + +const RefactoringDescriptor &RenameOccurrences::describe() { + static const RefactoringDescriptor Descriptor = { + "local-rename", + "Rename", + "Finds and renames symbols in code with no indexer support", + }; + return Descriptor; +} + +Expected<RenameOccurrences> +RenameOccurrences::initiate(RefactoringRuleContext &Context, + SourceRange SelectionRange, std::string NewName) { + const NamedDecl *ND = + getNamedDeclAt(Context.getASTContext(), SelectionRange.getBegin()); + if (!ND) + return Context.createDiagnosticError( + SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol); + return RenameOccurrences(getCanonicalSymbolDeclaration(ND), + std::move(NewName)); +} + +Expected<AtomicChanges> +RenameOccurrences::createSourceReplacements(RefactoringRuleContext &Context) { + Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(ND, Context); + if (!Occurrences) + return Occurrences.takeError(); + // FIXME: Verify that the new name is valid. + SymbolName Name(NewName); + return createRenameReplacements( + *Occurrences, Context.getASTContext().getSourceManager(), Name); +} + +Expected<QualifiedRenameRule> +QualifiedRenameRule::initiate(RefactoringRuleContext &Context, + std::string OldQualifiedName, + std::string NewQualifiedName) { + const NamedDecl *ND = + getNamedDeclFor(Context.getASTContext(), OldQualifiedName); + if (!ND) + return llvm::make_error<llvm::StringError>("Could not find symbol " + + OldQualifiedName, + llvm::errc::invalid_argument); + return QualifiedRenameRule(ND, std::move(NewQualifiedName)); +} + +const RefactoringDescriptor &QualifiedRenameRule::describe() { + static const RefactoringDescriptor Descriptor = { + /*Name=*/"local-qualified-rename", + /*Title=*/"Qualified Rename", + /*Description=*/ + R"(Finds and renames qualified symbols in code within a translation unit. +It is used to move/rename a symbol to a new namespace/name: + * Supported symbols: classes, class members, functions, enums, and type alias. + * Renames all symbol occurrences from the old qualified name to the new + qualified name. All symbol references will be correctly qualified; For + symbol definitions, only name will be changed. +For example, rename "A::Foo" to "B::Bar": + Old code: + namespace foo { + class A {}; + } + + namespace bar { + void f(foo::A a) {} + } + + New code after rename: + namespace foo { + class B {}; + } + + namespace bar { + void f(B b) {} + })" + }; + return Descriptor; +} + +Expected<AtomicChanges> +QualifiedRenameRule::createSourceReplacements(RefactoringRuleContext &Context) { + auto USRs = getUSRsForDeclaration(ND, Context.getASTContext()); + assert(!USRs.empty()); + return tooling::createRenameAtomicChanges( + USRs, NewQualifiedName, Context.getASTContext().getTranslationUnitDecl()); +} + +Expected<std::vector<AtomicChange>> +createRenameReplacements(const SymbolOccurrences &Occurrences, + const SourceManager &SM, const SymbolName &NewName) { + // FIXME: A true local rename can use just one AtomicChange. + std::vector<AtomicChange> Changes; + for (const auto &Occurrence : Occurrences) { + ArrayRef<SourceRange> Ranges = Occurrence.getNameRanges(); + assert(NewName.getNamePieces().size() == Ranges.size() && + "Mismatching number of ranges and name pieces"); + AtomicChange Change(SM, Ranges[0].getBegin()); + for (const auto &Range : llvm::enumerate(Ranges)) { + auto Error = + Change.replace(SM, CharSourceRange::getCharRange(Range.value()), + NewName.getNamePieces()[Range.index()]); + if (Error) + return std::move(Error); + } + Changes.push_back(std::move(Change)); + } + return std::move(Changes); +} + +/// Takes each atomic change and inserts its replacements into the set of +/// replacements that belong to the appropriate file. +static void convertChangesToFileReplacements( + ArrayRef<AtomicChange> AtomicChanges, + std::map<std::string, tooling::Replacements> *FileToReplaces) { + for (const auto &AtomicChange : AtomicChanges) { + for (const auto &Replace : AtomicChange.getReplacements()) { + llvm::Error Err = (*FileToReplaces)[Replace.getFilePath()].add(Replace); + if (Err) { + llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " + << llvm::toString(std::move(Err)) << "\n"; + } + } + } +} + class RenamingASTConsumer : public ASTConsumer { public: RenamingASTConsumer( @@ -44,37 +190,42 @@ public: FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} void HandleTranslationUnit(ASTContext &Context) override { - for (unsigned I = 0; I < NewNames.size(); ++I) + for (unsigned I = 0; I < NewNames.size(); ++I) { + // If the previous name was not found, ignore this rename request. + if (PrevNames[I].empty()) + continue; + HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]); + } } void HandleOneRename(ASTContext &Context, const std::string &NewName, const std::string &PrevName, const std::vector<std::string> &USRs) { const SourceManager &SourceMgr = Context.getSourceManager(); - std::vector<SourceLocation> RenamingCandidates; - std::vector<SourceLocation> NewCandidates; - NewCandidates = tooling::getLocationsOfUSRs( + SymbolOccurrences Occurrences = tooling::getOccurrencesOfUSRs( USRs, PrevName, Context.getTranslationUnitDecl()); - RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), - NewCandidates.end()); - - unsigned PrevNameLen = PrevName.length(); - for (const auto &Loc : RenamingCandidates) { - if (PrintLocations) { - FullSourceLoc FullLoc(Loc, SourceMgr); - errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) + if (PrintLocations) { + for (const auto &Occurrence : Occurrences) { + FullSourceLoc FullLoc(Occurrence.getNameRanges()[0].getBegin(), + SourceMgr); + errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(FullLoc) << ":" << FullLoc.getSpellingLineNumber() << ":" << FullLoc.getSpellingColumnNumber() << "\n"; } - // FIXME: better error handling. - tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); - llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); - if (Err) - llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " - << llvm::toString(std::move(Err)) << "\n"; } + // FIXME: Support multi-piece names. + // FIXME: better error handling (propagate error out). + SymbolName NewNameRef(NewName); + Expected<std::vector<AtomicChange>> Change = + createRenameReplacements(Occurrences, SourceMgr, NewNameRef); + if (!Change) { + llvm::errs() << "Failed to create renaming replacements for '" << PrevName + << "'! " << llvm::toString(Change.takeError()) << "\n"; + return; + } + convertChangesToFileReplacements(*Change, &FileToReplaces); } private: @@ -103,15 +254,7 @@ public: // ready. auto AtomicChanges = tooling::createRenameAtomicChanges( USRList[I], NewNames[I], Context.getTranslationUnitDecl()); - for (const auto AtomicChange : AtomicChanges) { - for (const auto &Replace : AtomicChange.getReplacements()) { - llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); - if (Err) { - llvm::errs() << "Renaming failed in " << Replace.getFilePath() - << "! " << llvm::toString(std::move(Err)) << "\n"; - } - } - } + convertChangesToFileReplacements(AtomicChanges, &FileToReplaces); } } diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp new file mode 100644 index 0000000000000..ea64b2c1aa8c7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp @@ -0,0 +1,37 @@ +//===--- SymbolOccurrences.cpp - Clang refactoring library ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; +using namespace tooling; + +SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, + ArrayRef<SourceLocation> Locations) + : Kind(Kind) { + ArrayRef<std::string> NamePieces = Name.getNamePieces(); + assert(Locations.size() == NamePieces.size() && + "mismatching number of locations and lengths"); + assert(!Locations.empty() && "no locations"); + if (Locations.size() == 1) { + RangeOrNumRanges = SourceRange( + Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size())); + return; + } + MultipleRanges = llvm::make_unique<SourceRange[]>(Locations.size()); + RangeOrNumRanges.setBegin( + SourceLocation::getFromRawEncoding(Locations.size())); + for (const auto &Loc : llvm::enumerate(Locations)) { + MultipleRanges[Loc.index()] = SourceRange( + Loc.value(), + Loc.value().getLocWithOffset(NamePieces[Loc.index()].size())); + } +} diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp index 2769802ad2bc6..40b70d8a05902 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp @@ -39,6 +39,21 @@ using namespace llvm; namespace clang { namespace tooling { +const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) { + // If FoundDecl is a constructor or destructor, we want to instead take + // the Decl of the corresponding class. + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) + FoundDecl = CtorDecl->getParent(); + else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) + FoundDecl = DtorDecl->getParent(); + // FIXME: (Alex L): Canonicalize implicit template instantions, just like + // the indexer does it. + + // Note: please update the declaration's doc comment every time the + // canonicalization rules are changed. + return FoundDecl; +} + namespace { // \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to // AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given @@ -58,6 +73,7 @@ public: if (checkIfOverriddenFunctionAscends(OverriddenMethod)) USRSet.insert(getUSRForDecl(OverriddenMethod)); } + addUSRsOfInstantiatedMethods(MethodDecl); } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) { handleCXXRecordDecl(RecordDecl); } else if (const auto *TemplateDecl = @@ -69,9 +85,13 @@ public: return std::vector<std::string>(USRSet.begin(), USRSet.end()); } + bool shouldVisitTemplateInstantiations() const { return true; } + bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { if (MethodDecl->isVirtual()) OverriddenMethods.push_back(MethodDecl); + if (MethodDecl->getInstantiatedFromMemberFunction()) + InstantiatedMethods.push_back(MethodDecl); return true; } @@ -122,6 +142,20 @@ private: addUSRsOfOverridenFunctions(OverriddenMethod); } + void addUSRsOfInstantiatedMethods(const CXXMethodDecl *MethodDecl) { + // For renaming a class template method, all references of the instantiated + // member methods should be renamed too, so add USRs of the instantiated + // methods to the USR set. + USRSet.insert(getUSRForDecl(MethodDecl)); + if (const auto *FT = MethodDecl->getInstantiatedFromMemberFunction()) + USRSet.insert(getUSRForDecl(FT)); + for (const auto *Method : InstantiatedMethods) { + if (USRSet.find(getUSRForDecl( + Method->getInstantiatedFromMemberFunction())) != USRSet.end()) + USRSet.insert(getUSRForDecl(Method)); + } + } + bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) @@ -135,10 +169,17 @@ private: ASTContext &Context; std::set<std::string> USRSet; std::vector<const CXXMethodDecl *> OverriddenMethods; + std::vector<const CXXMethodDecl *> InstantiatedMethods; std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs; }; } // namespace +std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND, + ASTContext &Context) { + AdditionalUSRFinder Finder(ND, Context); + return Finder.Find(); +} + class NamedDeclFindingConsumer : public ASTConsumer { public: NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets, @@ -183,8 +224,11 @@ private: return false; } - if (Force) + if (Force) { + SpellingNames.push_back(std::string()); + USRList.push_back(std::vector<std::string>()); return true; + } unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID( DiagnosticsEngine::Error, "clang-rename could not find symbol %0"); @@ -193,13 +237,7 @@ private: return false; } - // If FoundDecl is a constructor or destructor, we want to instead take - // the Decl of the corresponding class. - if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) - FoundDecl = CtorDecl->getParent(); - else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) - FoundDecl = DtorDecl->getParent(); - + FoundDecl = getCanonicalSymbolDeclaration(FoundDecl); SpellingNames.push_back(FoundDecl->getNameAsString()); AdditionalUSRFinder Finder(FoundDecl, Context); USRList.push_back(Finder.Find()); diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index dc21a94610cbb..c77304a17332b 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -23,6 +23,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Tooling/Core/Lookup.h" #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" #include "clang/Tooling/Refactoring/Rename/USRFinder.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -38,6 +39,17 @@ namespace tooling { namespace { +// Returns true if the given Loc is valid for edit. We don't edit the +// SourceLocations that are valid or in temporary buffer. +bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { + if (Loc.isInvalid()) + return false; + const clang::FullSourceLoc FullLoc(Loc, SM); + std::pair<clang::FileID, unsigned> FileIdAndOffset = + FullLoc.getSpellingLoc().getDecomposedLoc(); + return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; +} + // \brief This visitor recursively searches for all instances of a USR in a // translation unit and stores them for later usage. class USRLocFindingASTVisitor @@ -68,11 +80,9 @@ public: // Non-visitors: - // \brief Returns a list of unique locations. Duplicate or overlapping - // locations are erroneous and should be reported! - const std::vector<clang::SourceLocation> &getLocationsFound() const { - return LocationsFound; - } + /// \brief Returns a set of unique symbol occurrences. Duplicate or + /// overlapping occurrences are erroneous and should be reported! + SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } private: void checkAndAddLocation(SourceLocation Loc) { @@ -82,17 +92,18 @@ private: StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), Context.getSourceManager(), Context.getLangOpts()); - size_t Offset = TokenName.find(PrevName); + size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); // The token of the source location we find actually has the old // name. if (Offset != StringRef::npos) - LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); + Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, + BeginLoc.getLocWithOffset(Offset)); } const std::set<std::string> USRSet; - const std::string PrevName; - std::vector<clang::SourceLocation> LocationsFound; + const SymbolName PrevName; + SymbolOccurrences Occurrences; const ASTContext &Context; }; @@ -160,13 +171,14 @@ public: const Decl *Context; // The nested name being replaced (can be nullptr). const NestedNameSpecifier *Specifier; + // Determine whether the prefix qualifiers of the NewName should be ignored. + // Normally, we set it to true for the symbol declaration and definition to + // avoid adding prefix qualifiers. + // For example, if it is true and NewName is "a::b::foo", then the symbol + // occurrence which the RenameInfo points to will be renamed to "foo". + bool IgnorePrefixQualifers; }; - // FIXME: Currently, prefix qualifiers will be added to the renamed symbol - // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming - // "a::Foo" to "b::Bar"). - // For renaming declarations/definitions, prefix qualifiers should be filtered - // out. bool VisitNamedDecl(const NamedDecl *Decl) { // UsingDecl has been handled in other place. if (llvm::isa<UsingDecl>(Decl)) @@ -180,19 +192,129 @@ public: return true; if (isInUSRSet(Decl)) { - RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr, - nullptr, nullptr}; - RenameInfos.push_back(Info); + // For the case of renaming an alias template, we actually rename the + // underlying alias declaration of the template. + if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) + Decl = TAT->getTemplatedDecl(); + + auto StartLoc = Decl->getLocation(); + auto EndLoc = StartLoc; + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, + EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifers=*/true}; + RenameInfos.push_back(Info); + } } return true; } - bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + bool VisitMemberExpr(const MemberExpr *Expr) { const NamedDecl *Decl = Expr->getFoundDecl(); + auto StartLoc = Expr->getMemberLoc(); + auto EndLoc = Expr->getMemberLoc(); if (isInUSRSet(Decl)) { - RenameInfo Info = {Expr->getSourceRange().getBegin(), - Expr->getSourceRange().getEnd(), Decl, - getClosestAncestorDecl(*Expr), Expr->getQualifier()}; + RenameInfos.push_back({StartLoc, EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + } + return true; + } + + bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { + // Fix the constructor initializer when renaming class members. + for (const auto *Initializer : CD->inits()) { + // Ignore implicit initializers. + if (!Initializer->isWritten()) + continue; + + if (const FieldDecl *FD = Initializer->getMember()) { + if (isInUSRSet(FD)) { + auto Loc = Initializer->getSourceLocation(); + RenameInfos.push_back({Loc, Loc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + } + } + } + return true; + } + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + // Get the underlying declaration of the shadow declaration introduced by a + // using declaration. + if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { + Decl = UsingShadow->getTargetDecl(); + } + + auto StartLoc = Expr->getLocStart(); + // For template function call expressions like `foo<int>()`, we want to + // restrict the end of location to just before the `<` character. + SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() + ? Expr->getLAngleLoc().getLocWithOffset(-1) + : Expr->getLocEnd(); + + if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) { + if (isInUSRSet(MD)) { + // Handle renaming static template class methods, we only rename the + // name without prefix qualifiers and restrict the source range to the + // name. + RenameInfos.push_back({EndLoc, EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + return true; + } + } + + // In case of renaming an enum declaration, we have to explicitly handle + // unscoped enum constants referenced in expressions (e.g. + // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped + // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by + // TypeLoc. + if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { + // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) + // when renaming an unscoped enum declaration with a new namespace. + if (!Expr->hasQualifier()) + return true; + + if (const auto *ED = + llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { + if (ED->isScoped()) + return true; + Decl = ED; + } + // The current fix would qualify "ns1::ns2::Green" as + // "ns1::ns2::Color::Green". + // + // Get the EndLoc of the replacement by moving 1 character backward ( + // to exclude the last '::'). + // + // ns1::ns2::Green; + // ^ ^^ + // BeginLoc |EndLoc of the qualifier + // new EndLoc + EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); + assert(EndLoc.isValid() && + "The enum constant should have prefix qualifers."); + } + if (isInUSRSet(Decl) && + IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, + EndLoc, + Decl, + getClosestAncestorDecl(*Expr), + Expr->getQualifier(), + /*IgnorePrefixQualifers=*/false}; RenameInfos.push_back(Info); } @@ -212,16 +334,16 @@ public: bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { if (!NestedLoc.getNestedNameSpecifier()->getAsType()) return true; - if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc())) - return true; if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { if (isInUSRSet(TargetDecl)) { RenameInfo Info = {NestedLoc.getBeginLoc(), EndLocationForType(NestedLoc.getTypeLoc()), - TargetDecl, getClosestAncestorDecl(NestedLoc), - NestedLoc.getNestedNameSpecifier()->getPrefix()}; + TargetDecl, + getClosestAncestorDecl(NestedLoc), + NestedLoc.getNestedNameSpecifier()->getPrefix(), + /*IgnorePrefixQualifers=*/false}; RenameInfos.push_back(Info); } } @@ -229,9 +351,6 @@ public: } bool VisitTypeLoc(TypeLoc Loc) { - if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc)) - return true; - auto Parents = Context.getParents(Loc); TypeLoc ParentTypeLoc; if (!Parents.empty()) { @@ -265,10 +384,18 @@ public: if (!ParentTypeLoc.isNull() && isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) return true; - RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc), - TargetDecl, getClosestAncestorDecl(Loc), - GetNestedNameForType(Loc)}; - RenameInfos.push_back(Info); + + auto StartLoc = StartLocationForType(Loc); + auto EndLoc = EndLocationForType(Loc); + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, + EndLoc, + TargetDecl, + getClosestAncestorDecl(Loc), + GetNestedNameForType(Loc), + /*IgnorePrefixQualifers=*/false}; + RenameInfos.push_back(Info); + } return true; } } @@ -292,13 +419,20 @@ public: if (!ParentTypeLoc.isNull() && llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) TargetLoc = ParentTypeLoc; - RenameInfo Info = { - StartLocationForType(TargetLoc), EndLocationForType(TargetLoc), - TemplateSpecType->getTemplateName().getAsTemplateDecl(), - getClosestAncestorDecl( - ast_type_traits::DynTypedNode::create(TargetLoc)), - GetNestedNameForType(TargetLoc)}; - RenameInfos.push_back(Info); + + auto StartLoc = StartLocationForType(TargetLoc); + auto EndLoc = EndLocationForType(TargetLoc); + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = { + StartLoc, + EndLoc, + TemplateSpecType->getTemplateName().getAsTemplateDecl(), + getClosestAncestorDecl( + ast_type_traits::DynTypedNode::create(TargetLoc)), + GetNestedNameForType(TargetLoc), + /*IgnorePrefixQualifers=*/false}; + RenameInfos.push_back(Info); + } } } return true; @@ -313,40 +447,16 @@ public: } private: - // FIXME: This method may not be suitable for renaming other types like alias - // types. Need to figure out a way to handle it. - bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const { - while (!TL.isNull()) { - // SubstTemplateTypeParm is the TypeLocation class for a substituted type - // inside a template expansion so we ignore these. For example: - // - // template<typename T> struct S { - // T t; // <-- this T becomes a TypeLoc(int) with class - // // SubstTemplateTypeParm when S<int> is instantiated - // } - if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm) - return true; - - // Typedef is the TypeLocation class for a type which is a typedef to the - // type we want to replace. We ignore the use of the typedef as we will - // replace the definition of it. For example: - // - // typedef int T; - // T a; // <--- This T is a TypeLoc(int) with class Typedef. - if (TL.getTypeLocClass() == TypeLoc::Typedef) - return true; - TL = TL.getNextTypeLoc(); - } - return false; - } - // Get the supported declaration from a given typeLoc. If the declaration type // is not supported, returns nullptr. - // - // FIXME: support more types, e.g. enum, type alias. const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { + if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) + return TT->getDecl(); if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) return RD; + if (const auto *ED = + llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) + return ED; return nullptr; } @@ -391,12 +501,11 @@ private: } // namespace -std::vector<SourceLocation> -getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName, - Decl *Decl) { +SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, + StringRef PrevName, Decl *Decl) { USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); Visitor.TraverseDecl(Decl); - return Visitor.getLocationsFound(); + return Visitor.takeOccurrences(); } std::vector<tooling::AtomicChange> @@ -424,18 +533,43 @@ createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, for (const auto &RenameInfo : Finder.getRenameInfos()) { std::string ReplacedName = NewName.str(); - if (RenameInfo.FromDecl && RenameInfo.Context) { - if (!llvm::isa<clang::TranslationUnitDecl>( - RenameInfo.Context->getDeclContext())) { - ReplacedName = tooling::replaceNestedName( - RenameInfo.Specifier, RenameInfo.Context->getDeclContext(), - RenameInfo.FromDecl, - NewName.startswith("::") ? NewName.str() : ("::" + NewName).str()); + if (RenameInfo.IgnorePrefixQualifers) { + // Get the name without prefix qualifiers from NewName. + size_t LastColonPos = NewName.find_last_of(':'); + if (LastColonPos != std::string::npos) + ReplacedName = NewName.substr(LastColonPos + 1); + } else { + if (RenameInfo.FromDecl && RenameInfo.Context) { + if (!llvm::isa<clang::TranslationUnitDecl>( + RenameInfo.Context->getDeclContext())) { + ReplacedName = tooling::replaceNestedName( + RenameInfo.Specifier, RenameInfo.Context->getDeclContext(), + RenameInfo.FromDecl, + NewName.startswith("::") ? NewName.str() + : ("::" + NewName).str()); + } else { + // This fixes the case where type `T` is a parameter inside a function + // type (e.g. `std::function<void(T)>`) and the DeclContext of `T` + // becomes the translation unit. As a workaround, we simply use + // fully-qualified name here for all references whose `DeclContext` is + // the translation unit and ignore the possible existence of + // using-decls (in the global scope) that can shorten the replaced + // name. + llvm::StringRef ActualName = Lexer::getSourceText( + CharSourceRange::getTokenRange( + SourceRange(RenameInfo.Begin, RenameInfo.End)), + SM, TranslationUnitDecl->getASTContext().getLangOpts()); + // Add the leading "::" back if the name written in the code contains + // it. + if (ActualName.startswith("::") && !NewName.startswith("::")) { + ReplacedName = "::" + NewName.str(); + } + } } + // If the NewName contains leading "::", add it back. + if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) + ReplacedName = NewName.str(); } - // If the NewName contains leading "::", add it back. - if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) - ReplacedName = NewName.str(); Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); } diff --git a/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp b/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp new file mode 100644 index 0000000000000..eea8e39d134c2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/StandaloneExecution.cpp @@ -0,0 +1,91 @@ +//===- lib/Tooling/Execution.cpp - Standalone clang action execution. -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/StandaloneExecution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" + +namespace clang { +namespace tooling { + +static llvm::Error make_string_error(const llvm::Twine &Message) { + return llvm::make_error<llvm::StringError>(Message, + llvm::inconvertibleErrorCode()); +} + +const char *StandaloneToolExecutor::ExecutorName = "StandaloneToolExecutor"; + +static ArgumentsAdjuster getDefaultArgumentsAdjusters() { + return combineAdjusters( + getClangStripOutputAdjuster(), + combineAdjusters(getClangSyntaxOnlyAdjuster(), + getClangStripDependencyFileAdjuster())); +} + +StandaloneToolExecutor::StandaloneToolExecutor( + const CompilationDatabase &Compilations, + llvm::ArrayRef<std::string> SourcePaths, + std::shared_ptr<PCHContainerOperations> PCHContainerOps) + : Tool(Compilations, SourcePaths), Context(&Results), + ArgsAdjuster(getDefaultArgumentsAdjusters()) { + // Use self-defined default argument adjusters instead of the default + // adjusters that come with the old `ClangTool`. + Tool.clearArgumentsAdjusters(); +} + +StandaloneToolExecutor::StandaloneToolExecutor( + CommonOptionsParser Options, + std::shared_ptr<PCHContainerOperations> PCHContainerOps) + : OptionsParser(std::move(Options)), + Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList(), + PCHContainerOps), + Context(&Results), ArgsAdjuster(getDefaultArgumentsAdjusters()) { + Tool.clearArgumentsAdjusters(); +} + +llvm::Error StandaloneToolExecutor::execute( + llvm::ArrayRef< + std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> + Actions) { + if (Actions.empty()) + return make_string_error("No action to execute."); + + if (Actions.size() != 1) + return make_string_error( + "Only support executing exactly 1 action at this point."); + + auto &Action = Actions.front(); + Tool.appendArgumentsAdjuster(Action.second); + Tool.appendArgumentsAdjuster(ArgsAdjuster); + if (Tool.run(Action.first.get())) + return make_string_error("Failed to run action."); + + return llvm::Error::success(); +} + +class StandaloneToolExecutorPlugin : public ToolExecutorPlugin { +public: + llvm::Expected<std::unique_ptr<ToolExecutor>> + create(CommonOptionsParser &OptionsParser) override { + if (OptionsParser.getSourcePathList().empty()) + return make_string_error( + "[StandaloneToolExecutorPlugin] No positional argument found."); + return llvm::make_unique<StandaloneToolExecutor>(std::move(OptionsParser)); + } +}; + +static ToolExecutorPluginRegistry::Add<StandaloneToolExecutorPlugin> + X("standalone", "Runs FrontendActions on a set of files provided " + "via positional arguments."); + +// This anchor is used to force the linker to link in the generated object file +// and thus register the plugin. +volatile int StandaloneToolExecutorAnchorSource = 0; + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp index 662f02dca2a66..4fbfa4f004736 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp @@ -29,6 +29,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -190,11 +191,12 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine, } auto TargetMode = clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs); - if (!AlreadyHasMode && !TargetMode.second.empty()) { - CommandLine.insert(++CommandLine.begin(), TargetMode.second); + if (!AlreadyHasMode && TargetMode.DriverMode) { + CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode); } - if (!AlreadyHasTarget && !TargetMode.first.empty()) { - CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first}); + if (!AlreadyHasTarget && TargetMode.TargetIsValid) { + CommandLine.insert(++CommandLine.begin(), {"-target", + TargetMode.TargetPrefix}); } } } @@ -346,11 +348,7 @@ void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) { } void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) { - if (ArgsAdjuster) - ArgsAdjuster = - combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster)); - else - ArgsAdjuster = std::move(Adjuster); + ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster)); } void ClangTool::clearArgumentsAdjusters() { diff --git a/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp b/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp index 14bff19a1a0c6..b7179ffd64163 100644 --- a/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp +++ b/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp @@ -102,6 +102,10 @@ static cl::opt<bool> SortIncludes( "SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt<bool> + Verbose("verbose", cl::desc("If set, shows the list of processed files"), + cl::cat(ClangFormatCategory)); + static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), cl::cat(ClangFormatCategory)); @@ -285,7 +289,7 @@ static bool format(StringRef FileName) { "xml:space='preserve' incomplete_format='" << (Status.FormatComplete ? "false" : "true") << "'"; if (!Status.FormatComplete) - outs() << " line=" << Status.Line; + outs() << " line='" << Status.Line << "'"; outs() << ">\n"; if (Cursor.getNumOccurrences() != 0) outs() << "<cursor>" @@ -328,8 +332,7 @@ static bool format(StringRef FileName) { } // namespace format } // namespace clang -static void PrintVersion() { - raw_ostream &OS = outs(); +static void PrintVersion(raw_ostream &OS) { OS << clang::getClangToolFullVersion("clang-format") << '\n'; } @@ -348,8 +351,10 @@ int main(int argc, const char **argv) { "together with <file>s, the files are edited in-place. Otherwise, the\n" "result is written to the standard output.\n"); - if (Help) + if (Help) { cl::PrintHelpMessage(); + return 0; + } if (DumpConfig) { llvm::Expected<clang::format::FormatStyle> FormatStyle = @@ -366,23 +371,19 @@ int main(int argc, const char **argv) { } bool Error = false; - switch (FileNames.size()) { - case 0: + if (FileNames.empty()) { Error = clang::format::format("-"); - break; - case 1: - Error = clang::format::format(FileNames[0]); - break; - default: - if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) { - errs() << "error: -offset, -length and -lines can only be used for " - "single file.\n"; - return 1; - } - for (unsigned i = 0; i < FileNames.size(); ++i) - Error |= clang::format::format(FileNames[i]); - break; + return Error ? 1 : 0; + } + if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { + errs() << "error: -offset, -length and -lines can only be used for " + "single file.\n"; + return 1; + } + for (const auto &FileName : FileNames) { + if (Verbose) + errs() << "Formatting " << FileName << "\n"; + Error |= clang::format::format(FileName); } return Error ? 1 : 0; } - diff --git a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp index 2fc2b508ef21b..9b90562af903a 100644 --- a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp +++ b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp @@ -356,7 +356,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, PIC = false; } - MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, CodeModel::Default, Ctx); + MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx); if (Opts.SaveTemporaryLabels) Ctx.setAllowTemporaryLabels(false); if (Opts.GenDwarfForAssembly) @@ -419,8 +419,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Opts.CPU, Options); Triple T(Opts.Triple); Str.reset(TheTarget->createMCObjectStreamer( - T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll, - Opts.IncrementalLinkerCompatible, + T, Ctx, std::unique_ptr<MCAsmBackend>(MAB), *Out, std::unique_ptr<MCCodeEmitter>(CE), *STI, + Opts.RelaxAll, Opts.IncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ true)); Str.get()->InitSections(Opts.NoExecStack); } @@ -504,7 +504,8 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { if (Asm.ShowHelp) { std::unique_ptr<OptTable> Opts(driver::createDriverOptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler", - /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0); + /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, + /*ShowAllAliases=*/false); return 0; } diff --git a/contrib/llvm/tools/clang/tools/driver/driver.cpp b/contrib/llvm/tools/clang/tools/driver/driver.cpp index 9f37c428ff932..fa757da9535c2 100644 --- a/contrib/llvm/tools/clang/tools/driver/driver.cpp +++ b/contrib/llvm/tools/clang/tools/driver/driver.cpp @@ -206,23 +206,26 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr); -static void insertTargetAndModeArgs(StringRef Target, StringRef Mode, +static void insertTargetAndModeArgs(const ParsedClangName &NameParts, SmallVectorImpl<const char *> &ArgVector, std::set<std::string> &SavedStrings) { - if (!Mode.empty()) { + // Put target and mode arguments at the start of argument list so that + // arguments specified in command line could override them. Avoid putting + // them at index 0, as an option like '-cc1' must remain the first. + auto InsertionPoint = ArgVector.begin(); + if (InsertionPoint != ArgVector.end()) + ++InsertionPoint; + + if (NameParts.DriverMode) { // Add the mode flag to the arguments. - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - ArgVector.insert(it, GetStableCStr(SavedStrings, Mode)); + ArgVector.insert(InsertionPoint, + GetStableCStr(SavedStrings, NameParts.DriverMode)); } - if (!Target.empty()) { - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)}; - ArgVector.insert(it, std::begin(arr), std::end(arr)); + if (NameParts.TargetIsValid) { + const char *arr[] = {"-target", GetStableCStr(SavedStrings, + NameParts.TargetPrefix)}; + ArgVector.insert(InsertionPoint, std::begin(arr), std::end(arr)); } } @@ -330,9 +333,7 @@ int main(int argc_, const char **argv_) { } llvm::InitializeAllTargets(); - std::string ProgName = argv[0]; - std::pair<std::string, std::string> TargetAndMode = - ToolChain::getTargetAndModeFromProgramName(ProgName); + auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]); llvm::BumpPtrAllocator A; llvm::StringSaver Saver(A); @@ -345,7 +346,7 @@ int main(int argc_, const char **argv_) { // Finally, our -cc1 tools don't care which tokenization mode we use because // response files written by clang will tokenize the same way in either mode. bool ClangCLMode = false; - if (TargetAndMode.second == "--driver-mode=cl" || + if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") || std::find_if(argv.begin(), argv.end(), [](const char *F) { return F && strcmp(F, "--driver-mode=cl") == 0; }) != argv.end()) { @@ -454,9 +455,9 @@ int main(int argc_, const char **argv_) { Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); SetInstallDir(argv, TheDriver, CanonicalPrefixes); + TheDriver.setTargetAndMode(TargetAndMode); - insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv, - SavedStrings); + insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings); SetBackdoorDriverOutputsFromEnvVars(TheDriver); diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp index b6d2988964b48..70ce15f5a24ed 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -56,9 +56,9 @@ public: V(Spelling.getValueAsString("Variety")), N(Spelling.getValueAsString("Name")) { - assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been" - "flattened!"); - if (V == "CXX11" || V == "Pragma") + assert(V != "GCC" && V != "Clang" && + "Given a GCC spelling, which means this hasn't been flattened!"); + if (V == "CXX11" || V == "C2x" || V == "Pragma") NS = Spelling.getValueAsString("Namespace"); bool Unset; K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset); @@ -78,11 +78,15 @@ GetFlattenedSpellings(const Record &Attr) { std::vector<FlattenedSpelling> Ret; for (const auto &Spelling : Spellings) { - if (Spelling->getValueAsString("Variety") == "GCC") { + StringRef Variety = Spelling->getValueAsString("Variety"); + StringRef Name = Spelling->getValueAsString("Name"); + if (Variety == "GCC") { // Gin up two new spelling objects to add into the list. - Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true); - Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu", - true); + Ret.emplace_back("GNU", Name, "", true); + Ret.emplace_back("CXX11", Name, "gnu", true); + } else if (Variety == "Clang") { + Ret.emplace_back("GNU", Name, "", false); + Ret.emplace_back("CXX11", Name, "clang", false); } else Ret.push_back(FlattenedSpelling(*Spelling)); } @@ -490,6 +494,17 @@ namespace { OS << "}\n"; } + void writeASTVisitorTraversal(raw_ostream &OS) const override { + StringRef Name = getUpperName(); + OS << " if (A->is" << Name << "Expr()) {\n" + << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n" + << " return false;\n" + << " } else if (auto *TSI = A->get" << Name << "Type()) {\n" + << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n" + << " return false;\n" + << " }\n"; + } + void writeCloneArgs(raw_ostream &OS) const override { OS << "is" << getLowerName() << "Expr, is" << getLowerName() << "Expr ? static_cast<void*>(" << getLowerName() @@ -630,6 +645,10 @@ namespace { << "A->" << getLowerName() << "_size()"; } + void writeASTVisitorTraversal(raw_ostream &OS) const override { + // FIXME: Traverse the elements. + } + void writeCtorBody(raw_ostream &OS) const override { OS << " std::copy(" << getUpperName() << ", " << getUpperName() << " + " << ArgSizeName << ", " << ArgName << ");\n"; @@ -1153,6 +1172,12 @@ namespace { OS << " }"; } + void writeASTVisitorTraversal(raw_ostream &OS) const override { + OS << " if (auto *TSI = A->get" << getUpperName() << "Loc())\n"; + OS << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n"; + OS << " return false;\n"; + } + void writeTemplateInstantiationArgs(raw_ostream &OS) const override { OS << "A->get" << getUpperName() << "Loc()"; } @@ -1305,7 +1330,7 @@ writePrettyPrintFunction(Record &R, if (Variety == "GNU") { Prefix = " __attribute__(("; Suffix = "))"; - } else if (Variety == "CXX11") { + } else if (Variety == "CXX11" || Variety == "C2x") { Prefix = " [["; Suffix = "]]"; std::string Namespace = Spellings[I].nameSpace(); @@ -1419,7 +1444,7 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { assert(!SpellingList.empty() && "Attribute with empty spelling list can't have accessors!"); for (const auto *Accessor : Accessors) { - std::string Name = Accessor->getValueAsString("Name"); + const StringRef Name = Accessor->getValueAsString("Name"); std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor); OS << " bool " << Name << "() const { return SpellingListIndex == "; @@ -1568,7 +1593,7 @@ struct AttributeSubjectMatchRule { // Abstract rules are used only for sub-rules bool isAbstractRule() const { return getSubjects().empty(); } - std::string getName() const { + StringRef getName() const { return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name"); } @@ -1800,13 +1825,11 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, // Generate a function that constructs a set of matching rules that describe // to which declarations the attribute should apply to. std::string FnName = "matchRulesFor" + Attr.getName().str(); - std::stringstream SS; - SS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<" + OS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<" << AttributeSubjectMatchRule::EnumName << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n"; if (Attr.isValueUnset("Subjects")) { - SS << "}\n\n"; - OS << SS.str(); + OS << "}\n\n"; return FnName; } const Record *SubjectObj = Attr.getValueAsDef("Subjects"); @@ -1819,24 +1842,23 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, // The rule might be language specific, so only subtract it from the given // rules if the specific language options are specified. std::vector<Record *> LangOpts = Rule.getLangOpts(); - SS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() + OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() << ", /*IsSupported=*/"; if (!LangOpts.empty()) { for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - std::string Part = (*I)->getValueAsString("Name"); + const StringRef Part = (*I)->getValueAsString("Name"); if ((*I)->getValueAsBit("Negated")) - SS << "!"; - SS << "LangOpts." + Part; + OS << "!"; + OS << "LangOpts." << Part; if (I + 1 != E) - SS << " || "; + OS << " || "; } } else - SS << "true"; - SS << "));\n"; + OS << "true"; + OS << "));\n"; } } - SS << "}\n\n"; - OS << SS.str(); + OS << "}\n\n"; return FnName; } @@ -1892,7 +1914,8 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { continue; std::string SubRuleFunction; if (SubMatchRules.count(Rule.MetaSubject)) - SubRuleFunction = "isAttributeSubjectMatchSubRuleFor_" + Rule.getName(); + SubRuleFunction = + ("isAttributeSubjectMatchSubRuleFor_" + Rule.getName()).str(); else SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor"; OS << " Case(\"" << Rule.getName() << "\", std::make_pair(" @@ -2695,10 +2718,14 @@ static void GenerateHasAttrSpellingStringSwitch( // If this is the C++11 variety, also add in the LangOpts test. if (Variety == "CXX11") Test += " && LangOpts.CPlusPlus11"; + else if (Variety == "C2x") + Test += " && LangOpts.DoubleSquareBracketAttributes"; } else if (Variety == "CXX11") // C++11 mode should be checked against LangOpts, which is presumed to be // present in the caller. Test = "LangOpts.CPlusPlus11"; + else if (Variety == "C2x") + Test = "LangOpts.DoubleSquareBracketAttributes"; std::string TestStr = !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1"; @@ -2719,7 +2746,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { // and declspecs. Then generate a big switch statement for each of them. std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); std::vector<Record *> Declspec, Microsoft, GNU, Pragma; - std::map<std::string, std::vector<Record *>> CXX; + std::map<std::string, std::vector<Record *>> CXX, C2x; // Walk over the list of all attributes, and split them out based on the // spelling variety. @@ -2735,6 +2762,8 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { Microsoft.push_back(R); else if (Variety == "CXX11") CXX[SI.nameSpace()].push_back(R); + else if (Variety == "C2x") + C2x[SI.nameSpace()].push_back(R); else if (Variety == "Pragma") Pragma.push_back(R); } @@ -2754,20 +2783,25 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << "case AttrSyntax::Pragma:\n"; OS << " return llvm::StringSwitch<int>(Name)\n"; GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); - OS << "case AttrSyntax::CXX: {\n"; - // C++11-style attributes are further split out based on the Scope. - for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) { - if (I != CXX.begin()) - OS << " else "; - if (I->first.empty()) - OS << "if (!Scope || Scope->getName() == \"\") {\n"; - else - OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; - OS << " return llvm::StringSwitch<int>(Name)\n"; - GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first); - OS << "}"; - } - OS << "\n}\n"; + auto fn = [&OS](const char *Spelling, const char *Variety, + const std::map<std::string, std::vector<Record *>> &List) { + OS << "case AttrSyntax::" << Variety << ": {\n"; + // C++11-style attributes are further split out based on the Scope. + for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { + if (I != List.cbegin()) + OS << " else "; + if (I->first.empty()) + OS << "if (!Scope || Scope->getName() == \"\") {\n"; + else + OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; + OS << " return llvm::StringSwitch<int>(Name)\n"; + GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); + OS << "}"; + } + OS << "\n} break;\n"; + }; + fn("CXX11", "CXX", CXX); + fn("C2x", "C", C2x); OS << "}\n"; } @@ -2788,10 +2822,11 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { << StringSwitch<unsigned>(Spellings[I].variety()) .Case("GNU", 0) .Case("CXX11", 1) - .Case("Declspec", 2) - .Case("Microsoft", 3) - .Case("Keyword", 4) - .Case("Pragma", 5) + .Case("C2x", 2) + .Case("Declspec", 3) + .Case("Microsoft", 4) + .Case("Keyword", 5) + .Case("Pragma", 6) .Default(0) << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" << " return " << I << ";\n"; @@ -2965,7 +3000,7 @@ static bool isArgVariadic(const Record &R, StringRef AttrName) { return createArgument(R, AttrName)->isVariadic(); } -static void emitArgInfo(const Record &R, std::stringstream &OS) { +static void emitArgInfo(const Record &R, raw_ostream &OS) { // This function will count the number of arguments specified for the // attribute and emit the number of required arguments followed by the // number of optional arguments. @@ -2994,136 +3029,72 @@ static void GenerateDefaultAppertainsTo(raw_ostream &OS) { OS << "}\n\n"; } +static std::string GetDiagnosticSpelling(const Record &R) { + std::string Ret = R.getValueAsString("DiagSpelling"); + if (!Ret.empty()) + return Ret; + + // If we couldn't find the DiagSpelling in this object, we can check to see + // if the object is one that has a base, and if it is, loop up to the Base + // member recursively. + std::string Super = R.getSuperClasses().back().first->getName(); + if (Super == "DDecl" || Super == "DStmt") + return GetDiagnosticSpelling(*R.getValueAsDef("Base")); + + return ""; +} + static std::string CalculateDiagnostic(const Record &S) { // If the SubjectList object has a custom diagnostic associated with it, // return that directly. - std::string CustomDiag = S.getValueAsString("CustomDiag"); + const StringRef CustomDiag = S.getValueAsString("CustomDiag"); if (!CustomDiag.empty()) - return CustomDiag; - - // Given the list of subjects, determine what diagnostic best fits. - enum { - Func = 1U << 0, - Var = 1U << 1, - ObjCMethod = 1U << 2, - Param = 1U << 3, - Class = 1U << 4, - GenericRecord = 1U << 5, - Type = 1U << 6, - ObjCIVar = 1U << 7, - ObjCProp = 1U << 8, - ObjCInterface = 1U << 9, - Block = 1U << 10, - Namespace = 1U << 11, - Field = 1U << 12, - CXXMethod = 1U << 13, - ObjCProtocol = 1U << 14, - Enum = 1U << 15, - Named = 1U << 16, - }; - uint32_t SubMask = 0; + return ("\"" + Twine(CustomDiag) + "\"").str(); + std::vector<std::string> DiagList; std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects"); for (const auto *Subject : Subjects) { const Record &R = *Subject; - std::string Name; - - if (R.isSubClassOf("SubsetSubject")) { - PrintError(R.getLoc(), "SubsetSubjects should use a custom diagnostic"); - // As a fallback, look through the SubsetSubject to see what its base - // type is, and use that. This needs to be updated if SubsetSubjects - // are allowed within other SubsetSubjects. - Name = R.getValueAsDef("Base")->getName(); - } else - Name = R.getName(); - - uint32_t V = StringSwitch<uint32_t>(Name) - .Case("Function", Func) - .Case("Var", Var) - .Case("ObjCMethod", ObjCMethod) - .Case("ParmVar", Param) - .Case("TypedefName", Type) - .Case("ObjCIvar", ObjCIVar) - .Case("ObjCProperty", ObjCProp) - .Case("Record", GenericRecord) - .Case("ObjCInterface", ObjCInterface) - .Case("ObjCProtocol", ObjCProtocol) - .Case("Block", Block) - .Case("CXXRecord", Class) - .Case("Namespace", Namespace) - .Case("Field", Field) - .Case("CXXMethod", CXXMethod) - .Case("Enum", Enum) - .Case("Named", Named) - .Default(0); - if (!V) { - // Something wasn't in our mapping, so be helpful and let the developer - // know about it. - PrintFatalError(R.getLoc(), "Unknown subject type: " + R.getName()); - return ""; + // Get the diagnostic text from the Decl or Stmt node given. + std::string V = GetDiagnosticSpelling(R); + if (V.empty()) { + PrintError(R.getLoc(), + "Could not determine diagnostic spelling for the node: " + + R.getName() + "; please add one to DeclNodes.td"); + } else { + // The node may contain a list of elements itself, so split the elements + // by a comma, and trim any whitespace. + SmallVector<StringRef, 2> Frags; + llvm::SplitString(V, Frags, ","); + for (auto Str : Frags) { + DiagList.push_back(Str.trim()); + } } - - SubMask |= V; } - switch (SubMask) { - // For the simple cases where there's only a single entry in the mask, we - // don't have to resort to bit fiddling. - case Func: return "ExpectedFunction"; - case Var: return "ExpectedVariable"; - case Param: return "ExpectedParameter"; - case Class: return "ExpectedClass"; - case Enum: return "ExpectedEnum"; - case CXXMethod: - // FIXME: Currently, this maps to ExpectedMethod based on existing code, - // but should map to something a bit more accurate at some point. - case ObjCMethod: return "ExpectedMethod"; - case Type: return "ExpectedType"; - case ObjCInterface: return "ExpectedObjectiveCInterface"; - case ObjCProtocol: return "ExpectedObjectiveCProtocol"; - - // "GenericRecord" means struct, union or class; check the language options - // and if not compiling for C++, strip off the class part. Note that this - // relies on the fact that the context for this declares "Sema &S". - case GenericRecord: - return "(S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass : " - "ExpectedStructOrUnion)"; - case Func | ObjCMethod | Block: return "ExpectedFunctionMethodOrBlock"; - case Func | ObjCMethod | Class: return "ExpectedFunctionMethodOrClass"; - case Func | Param: - case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; - case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; - case Func | Var: return "ExpectedVariableOrFunction"; - - // If not compiling for C++, the class portion does not apply. - case Func | Var | Class: - return "(S.getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass : " - "ExpectedVariableOrFunction)"; - - case Func | Var | Class | ObjCInterface: - return "(S.getLangOpts().CPlusPlus" - " ? ((S.getLangOpts().ObjC1 || S.getLangOpts().ObjC2)" - " ? ExpectedFunctionVariableClassOrObjCInterface" - " : ExpectedFunctionVariableOrClass)" - " : ((S.getLangOpts().ObjC1 || S.getLangOpts().ObjC2)" - " ? ExpectedFunctionVariableOrObjCInterface" - " : ExpectedVariableOrFunction))"; + if (DiagList.empty()) { + PrintFatalError(S.getLoc(), + "Could not deduce diagnostic argument for Attr subjects"); + return ""; + } - case ObjCMethod | ObjCProp: return "ExpectedMethodOrProperty"; - case Func | ObjCMethod | ObjCProp: - return "ExpectedFunctionOrMethodOrProperty"; - case ObjCProtocol | ObjCInterface: - return "ExpectedObjectiveCInterfaceOrProtocol"; - case Field | Var: return "ExpectedFieldOrGlobalVar"; + // FIXME: this is not particularly good for localization purposes and ideally + // should be part of the diagnostics engine itself with some sort of list + // specifier. - case Named: - return "ExpectedNamedDecl"; - } + // A single member of the list can be returned directly. + if (DiagList.size() == 1) + return '"' + DiagList.front() + '"'; - PrintFatalError(S.getLoc(), - "Could not deduce diagnostic argument for Attr subjects"); + if (DiagList.size() == 2) + return '"' + DiagList[0] + " and " + DiagList[1] + '"'; - return ""; + // If there are more than two in the list, we serialize the first N - 1 + // elements with a comma. This leaves the string in the state: foo, bar, + // baz (but misses quux). We can then add ", and " for the last element + // manually. + std::string Diag = llvm::join(DiagList.begin(), DiagList.end() - 1, ", "); + return '"' + Diag + ", and " + *(DiagList.end() - 1) + '"'; } static std::string GetSubjectWithSuffix(const Record *R) { @@ -3210,8 +3181,8 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { } SS << ") {\n"; SS << " S.Diag(Attr.getLoc(), diag::"; - SS << (Warn ? "warn_attribute_wrong_decl_type" : - "err_attribute_wrong_decl_type"); + SS << (Warn ? "warn_attribute_wrong_decl_type_str" : + "err_attribute_wrong_decl_type_str"); SS << ")\n"; SS << " << Attr.getName() << "; SS << CalculateDiagnostic(*SubjectObj) << ";\n"; @@ -3281,12 +3252,13 @@ static std::string GenerateLangOptRequirements(const Record &R, // codegen efficiency). std::string FnName = "check", Test; for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - std::string Part = (*I)->getValueAsString("Name"); + const StringRef Part = (*I)->getValueAsString("Name"); if ((*I)->getValueAsBit("Negated")) { FnName += "Not"; Test += "!"; } - Test += "S.LangOpts." + Part; + Test += "S.LangOpts."; + Test += Part; if (I + 1 != E) Test += " || "; FnName += Part; @@ -3342,7 +3314,7 @@ static std::string GenerateTargetRequirements(const Record &Attr, // applies to multiple target architectures. In order for the attribute to be // considered valid, all of its architectures need to be included. if (!Attr.isValueUnset("ParseKind")) { - std::string APK = Attr.getValueAsString("ParseKind"); + const StringRef APK = Attr.getValueAsString("ParseKind"); for (const auto &I : Dupes) { if (I.first == APK) { std::vector<StringRef> DA = @@ -3438,7 +3410,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { // another mapping. At the same time, generate the AttrInfoMap object // contents. Due to the reliance on generated code, use separate streams so // that code will not be interleaved. - std::stringstream SS; + std::string Buffer; + raw_string_ostream SS {Buffer}; for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { // TODO: If the attribute's kind appears in the list of duplicates, that is // because it is a target-specific attribute that appears multiple times. @@ -3484,7 +3457,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11, - Keywords, Pragma; + Keywords, Pragma, C2x; std::set<std::string> Seen; for (const auto *A : Attrs) { const Record &Attr = *A; @@ -3522,6 +3495,10 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { Matches = &CXX11; Spelling += S.nameSpace(); Spelling += "::"; + } else if (Variety == "C2x") { + Matches = &C2x; + Spelling += S.nameSpace(); + Spelling += "::"; } else if (Variety == "GNU") Matches = &GNU; else if (Variety == "Declspec") @@ -3560,6 +3537,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { StringMatcher("Name", Microsoft, OS).Emit(); OS << " } else if (AttributeList::AS_CXX11 == Syntax) {\n"; StringMatcher("Name", CXX11, OS).Emit(); + OS << " } else if (AttributeList::AS_C2x == Syntax) {\n"; + StringMatcher("Name", C2x, OS).Emit(); OS << " } else if (AttributeList::AS_Keyword == Syntax || "; OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n"; StringMatcher("Name", Keywords, OS).Emit(); @@ -3624,20 +3603,25 @@ class DocumentationData { public: const Record *Documentation; const Record *Attribute; + std::string Heading; + unsigned SupportedSpellings; - DocumentationData(const Record &Documentation, const Record &Attribute) - : Documentation(&Documentation), Attribute(&Attribute) {} + DocumentationData(const Record &Documentation, const Record &Attribute, + const std::pair<std::string, unsigned> HeadingAndKinds) + : Documentation(&Documentation), Attribute(&Attribute), + Heading(std::move(HeadingAndKinds.first)), + SupportedSpellings(HeadingAndKinds.second) {} }; static void WriteCategoryHeader(const Record *DocCategory, raw_ostream &OS) { - const std::string &Name = DocCategory->getValueAsString("Name"); - OS << Name << "\n" << std::string(Name.length(), '=') << "\n"; + const StringRef Name = DocCategory->getValueAsString("Name"); + OS << Name << "\n" << std::string(Name.size(), '=') << "\n"; // If there is content, print that as well. - std::string ContentStr = DocCategory->getValueAsString("Content"); + const StringRef ContentStr = DocCategory->getValueAsString("Content"); // Trim leading and trailing newlines and spaces. - OS << StringRef(ContentStr).trim(); + OS << ContentStr.trim(); OS << "\n\n"; } @@ -3645,22 +3629,24 @@ static void WriteCategoryHeader(const Record *DocCategory, enum SpellingKind { GNU = 1 << 0, CXX11 = 1 << 1, - Declspec = 1 << 2, - Microsoft = 1 << 3, - Keyword = 1 << 4, - Pragma = 1 << 5 + C2x = 1 << 2, + Declspec = 1 << 3, + Microsoft = 1 << 4, + Keyword = 1 << 5, + Pragma = 1 << 6 }; -static void WriteDocumentation(RecordKeeper &Records, - const DocumentationData &Doc, raw_ostream &OS) { +static std::pair<std::string, unsigned> +GetAttributeHeadingAndSpellingKinds(const Record &Documentation, + const Record &Attribute) { // FIXME: there is no way to have a per-spelling category for the attribute // documentation. This may not be a limiting factor since the spellings // should generally be consistently applied across the category. - std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Doc.Attribute); + std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute); // Determine the heading to be used for this attribute. - std::string Heading = Doc.Documentation->getValueAsString("Heading"); + std::string Heading = Documentation.getValueAsString("Heading"); bool CustomHeading = !Heading.empty(); if (Heading.empty()) { // If there's only one spelling, we can simply use that. @@ -3682,7 +3668,7 @@ static void WriteDocumentation(RecordKeeper &Records, // If the heading is still empty, it is an error. if (Heading.empty()) - PrintFatalError(Doc.Attribute->getLoc(), + PrintFatalError(Attribute.getLoc(), "This attribute requires a heading to be specified"); // Gather a list of unique spellings; this is not the same as the semantic @@ -3695,6 +3681,7 @@ static void WriteDocumentation(RecordKeeper &Records, SpellingKind Kind = StringSwitch<SpellingKind>(I.variety()) .Case("GNU", GNU) .Case("CXX11", CXX11) + .Case("C2x", C2x) .Case("Declspec", Declspec) .Case("Microsoft", Microsoft) .Case("Keyword", Keyword) @@ -3704,7 +3691,7 @@ static void WriteDocumentation(RecordKeeper &Records, SupportedSpellings |= Kind; std::string Name; - if (Kind == CXX11 && !I.nameSpace().empty()) + if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty()) Name = I.nameSpace() + "::"; Name += I.name(); @@ -3724,27 +3711,33 @@ static void WriteDocumentation(RecordKeeper &Records, } Heading += ")"; } - OS << Heading << "\n" << std::string(Heading.length(), '-') << "\n"; - if (!SupportedSpellings) - PrintFatalError(Doc.Attribute->getLoc(), + PrintFatalError(Attribute.getLoc(), "Attribute has no supported spellings; cannot be " "documented"); + return std::make_pair(std::move(Heading), SupportedSpellings); +} + +static void WriteDocumentation(RecordKeeper &Records, + const DocumentationData &Doc, raw_ostream &OS) { + OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n"; // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; - OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\","; + OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\","; OS << " \"Pragma\", \"Pragma clang attribute\"\n\n"; OS << " \""; - if (SupportedSpellings & GNU) OS << "X"; + if (Doc.SupportedSpellings & GNU) OS << "X"; + OS << "\",\""; + if (Doc.SupportedSpellings & CXX11) OS << "X"; OS << "\",\""; - if (SupportedSpellings & CXX11) OS << "X"; + if (Doc.SupportedSpellings & C2x) OS << "X"; OS << "\",\""; - if (SupportedSpellings & Declspec) OS << "X"; + if (Doc.SupportedSpellings & Declspec) OS << "X"; OS << "\",\""; - if (SupportedSpellings & Keyword) OS << "X"; + if (Doc.SupportedSpellings & Keyword) OS << "X"; OS << "\", \""; - if (SupportedSpellings & Pragma) OS << "X"; + if (Doc.SupportedSpellings & Pragma) OS << "X"; OS << "\", \""; if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute)) OS << "X"; @@ -3756,16 +3749,16 @@ static void WriteDocumentation(RecordKeeper &Records, OS << "This attribute has been deprecated, and may be removed in a future " << "version of Clang."; const Record &Deprecated = *Doc.Documentation->getValueAsDef("Deprecated"); - std::string Replacement = Deprecated.getValueAsString("Replacement"); + const StringRef Replacement = Deprecated.getValueAsString("Replacement"); if (!Replacement.empty()) OS << " This attribute has been superseded by ``" << Replacement << "``."; OS << "\n\n"; } - std::string ContentStr = Doc.Documentation->getValueAsString("Content"); + const StringRef ContentStr = Doc.Documentation->getValueAsString("Content"); // Trim leading and trailing newlines and spaces. - OS << StringRef(ContentStr).trim(); + OS << ContentStr.trim(); OS << "\n\n\n"; } @@ -3794,23 +3787,29 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { // If the category is "undocumented", then there cannot be any other // documentation categories (otherwise, the attribute would become // documented). - std::string Cat = Category->getValueAsString("Name"); + const StringRef Cat = Category->getValueAsString("Name"); bool Undocumented = Cat == "Undocumented"; if (Undocumented && Docs.size() > 1) PrintFatalError(Doc.getLoc(), "Attribute is \"Undocumented\", but has multiple " - "documentation categories"); + "documentation categories"); if (!Undocumented) - SplitDocs[Category].push_back(DocumentationData(Doc, Attr)); + SplitDocs[Category].push_back(DocumentationData( + Doc, Attr, GetAttributeHeadingAndSpellingKinds(Doc, Attr))); } } // Having split the attributes out based on what documentation goes where, // we can begin to generate sections of documentation. - for (const auto &I : SplitDocs) { + for (auto &I : SplitDocs) { WriteCategoryHeader(I.first, OS); + std::sort(I.second.begin(), I.second.end(), + [](const DocumentationData &D1, const DocumentationData &D2) { + return D1.Heading < D2.Heading; + }); + // Walk over each of the attributes in the category and write out their // documentation. for (const auto &Doc : I.second) diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp new file mode 100644 index 0000000000000..4079efc808231 --- /dev/null +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangDataCollectorsEmitter.cpp @@ -0,0 +1,18 @@ +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +namespace clang { +void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) { + const auto &Defs = RK.getClasses(); + for (const auto &Entry : Defs) { + Record &R = *Entry.second; + OS << "DEF_ADD_DATA(" << R.getName() << ", {\n"; + auto Code = R.getValue("Code")->getValue(); + OS << Code->getAsUnquotedString() << "}\n)"; + OS << "\n"; + } + OS << "#undef DEF_ADD_DATA\n"; +} +} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp index 781518ddbc312..840b330a732c1 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp @@ -57,6 +57,7 @@ enum ActionType { GenAttrDocs, GenDiagDocs, GenOptDocs, + GenDataCollectors, GenTestPragmaAttributeSupportedAttributes }; @@ -147,6 +148,8 @@ cl::opt<ActionType> Action( clEnumValN(GenDiagDocs, "gen-diag-docs", "Generate diagnostic documentation"), clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"), + clEnumValN(GenDataCollectors, "gen-clang-data-collectors", + "Generate data collectors for AST nodes"), clEnumValN(GenTestPragmaAttributeSupportedAttributes, "gen-clang-test-pragma-attribute-supported-attributes", "Generate a list of attributes supported by #pragma clang " @@ -262,6 +265,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenOptDocs: EmitClangOptDocs(Records, OS); break; + case GenDataCollectors: + EmitClangDataCollectors(Records, OS); + break; case GenTestPragmaAttributeSupportedAttributes: EmitTestPragmaAttributeSupportedAttributes(Records, OS); break; diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h index e1b7d0ec63be3..342c889ca47a6 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h @@ -75,6 +75,8 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS); void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS); void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS); +void EmitClangDataCollectors(RecordKeeper &Records, raw_ostream &OS); + void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records, raw_ostream &OS); |
