diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
commit | 06d4ba388873e6d1cfa9cd715a8935ecc8cd2097 (patch) | |
tree | 3eb853da77d46cc77c4b017525a422f9ddb1385b /include/clang | |
parent | 30d791273d07fac9c0c1641a0731191bca6e8606 (diff) | |
download | src-06d4ba388873e6d1cfa9cd715a8935ecc8cd2097.tar.gz src-06d4ba388873e6d1cfa9cd715a8935ecc8cd2097.zip |
Vendor import of clang RELEASE_360/rc1 tag r226102 (effectively, 3.6.0 RC1):vendor/clang/clang-release_360-r226102
Notes
Notes:
svn path=/vendor/clang/dist/; revision=277325
svn path=/vendor/clang/clang-release_360-r226102/; revision=277326; tag=vendor/clang/clang-release_360-r226102
Diffstat (limited to 'include/clang')
322 files changed, 9281 insertions, 3735 deletions
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h index b3e74b996678..c830aa3d7874 100644 --- a/include/clang/ARCMigrate/ARCMTActions.h +++ b/include/clang/ARCMigrate/ARCMTActions.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H -#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H +#ifndef LLVM_CLANG_ARCMIGRATE_ARCMTACTIONS_H +#define LLVM_CLANG_ARCMIGRATE_ARCMTACTIONS_H #include "clang/ARCMigrate/FileRemapper.h" #include "clang/Frontend/FrontendAction.h" @@ -37,8 +37,8 @@ class MigrateSourceAction : public ASTFrontendAction { FileRemapper Remapper; protected: bool BeginInvocation(CompilerInstance &CI) override; - ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) override; + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; }; class MigrateAction : public WrapperFrontendAction { @@ -65,8 +65,8 @@ public: unsigned migrateAction); protected: - ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) override; + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; bool BeginInvocation(CompilerInstance &CI) override; }; diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h index e094301ae6c4..53b88e9eb5e5 100644 --- a/include/clang/ARCMigrate/FileRemapper.h +++ b/include/clang/ARCMigrate/FileRemapper.h @@ -52,14 +52,14 @@ public: bool overwriteOriginal(DiagnosticsEngine &Diag, StringRef outputDir = StringRef()); - void remap(StringRef filePath, llvm::MemoryBuffer *memBuf); + void remap(StringRef filePath, std::unique_ptr<llvm::MemoryBuffer> memBuf); void applyMappings(PreprocessorOptions &PPOpts) const; void clear(StringRef outputDir = StringRef()); private: - void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf); + void remap(const FileEntry *file, std::unique_ptr<llvm::MemoryBuffer> memBuf); void remap(const FileEntry *file, const FileEntry *newfile); const FileEntry *getOriginalFile(StringRef filePath); diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 8134f6b080b7..195d748b5be8 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -30,6 +30,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -74,6 +75,15 @@ namespace clang { class FullComment; } + struct TypeInfo { + uint64_t Width; + unsigned Align; + bool AlignIsRequired : 1; + TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} + TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) + : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + }; + /// \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> { @@ -144,8 +154,7 @@ class ASTContext : public RefCountedBase<ASTContext> { ObjCLayouts; /// \brief A cache from types to size and alignment information. - typedef llvm::DenseMap<const Type*, - std::pair<uint64_t, unsigned> > TypeInfoMap; + typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap; mutable TypeInfoMap MemoizedTypeInfo; /// \brief A cache mapping from CXXRecordDecls to key functions. @@ -264,8 +273,6 @@ class ASTContext : public RefCountedBase<ASTContext> { /// \brief Declaration for the CUDA cudaConfigureCall function. FunctionDecl *cudaConfigureCallDecl; - TypeSourceInfo NullTypeSourceInfo; - /// \brief Keeps track of all declaration attributes. /// /// Since so few decls have attrs, we keep them in a hash map instead of @@ -384,6 +391,10 @@ private: /// this ASTContext object. LangOptions &LangOpts; + /// \brief Blacklist object that is used by sanitizers to decide which + /// entities should not be instrumented. + std::unique_ptr<SanitizerBlacklist> SanitizerBL; + /// \brief The allocator used to create AST objects. /// /// AST objects are never destructed; rather, all memory associated with the @@ -453,11 +464,12 @@ public: /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc, /// NestedNameSpecifier or NestedNameSpecifierLoc. template <typename NodeT> - ParentVector getParents(const NodeT &Node) { + ArrayRef<ast_type_traits::DynTypedNode> getParents(const NodeT &Node) { return getParents(ast_type_traits::DynTypedNode::create(Node)); } - ParentVector getParents(const ast_type_traits::DynTypedNode &Node); + ArrayRef<ast_type_traits::DynTypedNode> + getParents(const ast_type_traits::DynTypedNode &Node); const clang::PrintingPolicy &getPrintingPolicy() const { return PrintingPolicy; @@ -508,6 +520,10 @@ public: const LangOptions& getLangOpts() const { return LangOpts; } + const SanitizerBlacklist &getSanitizerBlacklist() const { + return *SanitizerBL; + } + DiagnosticsEngine &getDiagnostics() const; FullSourceLoc getFullLoc(SourceLocation Loc) const { @@ -912,6 +928,12 @@ public: /// \brief Change the result type of a function type once it is deduced. void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType); + /// \brief Change the exception specification on a function once it is + /// delay-parsed, instantiated, or computed. + void adjustExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExceptionSpecInfo &ESI, + bool AsWritten = false); + /// \brief Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T) const; @@ -1371,7 +1393,8 @@ public: /// /// If \p Field is specified then record field names are also encoded. void getObjCEncodingForType(QualType T, std::string &S, - const FieldDecl *Field=nullptr) const; + const FieldDecl *Field=nullptr, + QualType *NotEncodedT=nullptr) const; /// \brief Emit the Objective-C property type encoding for the given /// type \p T into \p S. @@ -1581,7 +1604,7 @@ public: private: CanQualType getFromTargetType(unsigned Type) const; - std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const; + TypeInfo getTypeInfoImpl(const Type *T) const; //===--------------------------------------------------------------------===// // Type Predicates. @@ -1614,18 +1637,12 @@ public: const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; /// \brief Get the size and alignment of the specified complete type in bits. - std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const; - std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const { - return getTypeInfo(T.getTypePtr()); - } + TypeInfo getTypeInfo(const Type *T) const; + TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } /// \brief Return the size of the specified (complete) type \p T, in bits. - uint64_t getTypeSize(QualType T) const { - return getTypeInfo(T).first; - } - uint64_t getTypeSize(const Type *T) const { - return getTypeInfo(T).first; - } + uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).Width; } + uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).Width; } /// \brief Return the size of the character type, in bits. uint64_t getCharWidth() const { @@ -1645,12 +1662,8 @@ public: /// \brief Return the ABI-specified alignment of a (complete) type \p T, in /// bits. - unsigned getTypeAlign(QualType T) const { - return getTypeInfo(T).second; - } - unsigned getTypeAlign(const Type *T) const { - return getTypeInfo(T).second; - } + unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; } + unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; } /// \brief Return the ABI-specified alignment of a (complete) type \p T, in /// characters. @@ -1664,6 +1677,11 @@ public: std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const; std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const; + /// \brief Determine if the alignment the type has was required using an + /// alignment attribute. + bool isAlignmentRequired(const Type *T) const; + bool isAlignmentRequired(QualType T) const; + /// \brief Return the "preferred" alignment of the specified type \p T for /// the current target, in bits. /// @@ -2153,8 +2171,6 @@ public: getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation()) const; - TypeSourceInfo *getNullTypeSourceInfo() { return &NullTypeSourceInfo; } - /// \brief Add a deallocation callback that will be invoked when the /// ASTContext is destroyed. /// @@ -2272,12 +2288,14 @@ private: bool StructField = false, bool EncodeBlockParameters = false, bool EncodeClassNames = false, - bool EncodePointerToObjCTypedef = false) const; + bool EncodePointerToObjCTypedef = false, + QualType *NotEncodedT=nullptr) const; // Adds the encoding of the structure's members. void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, const FieldDecl *Field, - bool includeVBases = true) const; + bool includeVBases = true, + QualType *NotEncodedT=nullptr) const; public: // Adds the encoding of a method parameter or return type. void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, @@ -2312,6 +2330,31 @@ private: std::unique_ptr<ParentMap> AllParents; std::unique_ptr<VTableContextBase> VTContext; + +public: + enum PragmaSectionFlag : unsigned { + PSF_None = 0, + PSF_Read = 0x1, + PSF_Write = 0x2, + PSF_Execute = 0x4, + PSF_Implicit = 0x8, + PSF_Invalid = 0x80000000U, + }; + + struct SectionInfo { + DeclaratorDecl *Decl; + SourceLocation PragmaSectionLocation; + int SectionFlags; + SectionInfo() {} + SectionInfo(DeclaratorDecl *Decl, + SourceLocation PragmaSectionLocation, + int SectionFlags) + : Decl(Decl), + PragmaSectionLocation(PragmaSectionLocation), + SectionFlags(SectionFlags) {} + }; + + llvm::StringMap<SectionInfo> SectionInfos; }; /// \brief Utility function for constructing a nullary selector. @@ -2349,9 +2392,9 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) { /// // Specific alignment /// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments); /// @endcode -/// Please note that you cannot use delete on the pointer; it must be -/// deallocated using an explicit destructor call followed by -/// @c Context.Deallocate(Ptr). +/// Memory allocated through this placement new operator does not need to be +/// explicitly freed, as ASTContext will free all of this memory when it gets +/// destroyed. Please note that you cannot use delete on the pointer. /// /// @param Bytes The number of bytes to allocate. Calculated by the compiler. /// @param C The ASTContext that provides the allocator. @@ -2386,9 +2429,9 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) { /// // Specific alignment /// char *data = new (Context, 4) char[10]; /// @endcode -/// Please note that you cannot use delete on the pointer; it must be -/// deallocated using an explicit destructor call followed by -/// @c Context.Deallocate(Ptr). +/// Memory allocated through this placement new[] operator does not need to be +/// explicitly freed, as ASTContext will free all of this memory when it gets +/// destroyed. Please note that you cannot use delete on the pointer. /// /// @param Bytes The number of bytes to allocate. Calculated by the compiler. /// @param C The ASTContext that provides the allocator. diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 484ca4cb8632..27c85e65f2c1 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DIAGNOSTICAST_H -#define LLVM_CLANG_DIAGNOSTICAST_H +#ifndef LLVM_CLANG_AST_ASTDIAGNOSTIC_H +#define LLVM_CLANG_AST_ASTDIAGNOSTIC_H #include "clang/Basic/Diagnostic.h" diff --git a/include/clang/AST/ASTFwd.h b/include/clang/AST/ASTFwd.h index 4f3279874b16..003d489c1ca4 100644 --- a/include/clang/AST/ASTFwd.h +++ b/include/clang/AST/ASTFwd.h @@ -12,6 +12,9 @@ /// //===-------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTFWD_H +#define LLVM_CLANG_AST_ASTFWD_H + namespace clang { class Decl; @@ -26,3 +29,5 @@ class Type; class CXXCtorInitializer; } // end namespace clang + +#endif diff --git a/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h index 9af016b13d45..69df2d8c0113 100644 --- a/include/clang/AST/ASTLambda.h +++ b/include/clang/AST/ASTLambda.h @@ -13,8 +13,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_LAMBDA_H -#define LLVM_CLANG_AST_LAMBDA_H +#ifndef LLVM_CLANG_AST_ASTLAMBDA_H +#define LLVM_CLANG_AST_ASTLAMBDA_H #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" @@ -77,4 +77,4 @@ inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) { } // clang -#endif // LLVM_CLANG_AST_LAMBDA_H +#endif diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index a89bfed53fbd..48eb6292772c 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -102,6 +102,12 @@ public: /// \param D the declaration marked used virtual void DeclarationMarkedUsed(const Decl *D) {} + /// \brief A declaration is marked as OpenMP threadprivate which was not + /// previously marked as threadprivate. + /// + /// \param D the declaration marked OpenMP threadprivate. + virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {} + // NOTE: If new methods are added they should also be added to // MultiplexASTMutationListener. }; diff --git a/include/clang/AST/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h index 0e06e26e6d80..dc3c34f28d94 100644 --- a/include/clang/AST/ASTTypeTraits.h +++ b/include/clang/AST/ASTTypeTraits.h @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H -#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H +#ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H +#define LLVM_CLANG_AST_ASTTYPETRAITS_H #include "clang/AST/ASTFwd.h" #include "clang/AST/Decl.h" @@ -23,6 +23,7 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/AlignOf.h" namespace llvm { @@ -53,9 +54,19 @@ public: return ASTNodeKind(KindToKindId<T>::Id); } + /// \{ + /// \brief Construct an identifier for the dynamic type of the node + static ASTNodeKind getFromNode(const Decl &D); + static ASTNodeKind getFromNode(const Stmt &S); + static ASTNodeKind getFromNode(const Type &T); + /// \} + /// \brief Returns \c true if \c this and \c Other represent the same kind. bool isSame(ASTNodeKind Other) const; + /// \brief Returns \c true only for the default \c ASTNodeKind() + bool isNone() const { return KindId == NKI_None; } + /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other. /// \param Distance If non-null, used to return the distance between \c this /// and \c Other in the class hierarchy. @@ -69,6 +80,32 @@ public: return KindId < Other.KindId; } + /// \brief Return the most derived type between \p Kind1 and \p Kind2. + /// + /// Return ASTNodeKind() if they are not related. + static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2); + + /// \brief Return the most derived common ancestor between Kind1 and Kind2. + /// + /// Return ASTNodeKind() if they are not related. + static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1, + ASTNodeKind Kind2); + + /// \brief Hooks for using ASTNodeKind as a key in a DenseMap. + struct DenseMapInfo { + // ASTNodeKind() is a good empty key because it is represented as a 0. + static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); } + // NKI_NumberOfKinds is not a valid value, so it is good for a + // tombstone key. + static inline ASTNodeKind getTombstoneKey() { + return ASTNodeKind(NKI_NumberOfKinds); + } + static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; } + static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) { + return LHS.KindId == RHS.KindId; + } + }; + private: /// \brief Kind ids. /// @@ -108,6 +145,8 @@ private: template <class T> struct KindToKindId { static const NodeKindId Id = NKI_None; }; + template <class T> + struct KindToKindId<const T> : KindToKindId<T> {}; /// \brief Per kind info. struct KindInfo { @@ -184,12 +223,22 @@ public: return BaseConverter<T>::get(NodeKind, Storage.buffer); } + /// \brief Retrieve the stored node as type \c T. + /// + /// Similar to \c get(), but asserts that the type is what we are expecting. + template <typename T> + const T &getUnchecked() const { + return BaseConverter<T>::getUnchecked(NodeKind, Storage.buffer); + } + + ASTNodeKind getNodeKind() const { return NodeKind; } + /// \brief Returns a pointer that identifies the stored AST node. /// /// Note that this is not supported by all AST nodes. For AST nodes /// that don't have a pointer-defined identity inside the AST, this /// method returns NULL. - const void *getMemoizationData() const; + const void *getMemoizationData() const { return MemoizationData; } /// \brief Prints the node to the given output stream. void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const; @@ -212,14 +261,15 @@ public: return getMemoizationData() < Other.getMemoizationData(); } bool operator==(const DynTypedNode &Other) const { - if (!NodeKind.isBaseOf(Other.NodeKind) && - !Other.NodeKind.isBaseOf(NodeKind)) + // DynTypedNode::create() stores the exact kind of the node in NodeKind. + // If they contain the same node, their NodeKind must be the same. + if (!NodeKind.isSame(Other.NodeKind)) return false; // FIXME: Implement for other types. - if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) { - return *get<QualType>() == *Other.get<QualType>(); - } + if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind)) + return getUnchecked<QualType>() == Other.getUnchecked<QualType>(); + assert(getMemoizationData() && Other.getMemoizationData()); return getMemoizationData() == Other.getMemoizationData(); } @@ -235,13 +285,18 @@ private: /// \brief Converter that uses dyn_cast<T> from a stored BaseT*. template <typename T, typename BaseT> struct DynCastPtrConverter { static const T *get(ASTNodeKind NodeKind, const char Storage[]) { - if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind)) - return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage)); + if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)) + return cast<T>(*reinterpret_cast<BaseT *const *>(Storage)); return nullptr; } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)); + return *cast<T>(*reinterpret_cast<BaseT *const *>(Storage)); + } static DynTypedNode create(const BaseT &Node) { DynTypedNode Result; - Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); + Result.NodeKind = ASTNodeKind::getFromNode(Node); + Result.MemoizationData = &Node; new (Result.Storage.buffer) const BaseT * (&Node); return Result; } @@ -254,9 +309,14 @@ private: return *reinterpret_cast<T *const *>(Storage); return nullptr; } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); + return **reinterpret_cast<T *const *>(Storage); + } static DynTypedNode create(const T &Node) { DynTypedNode Result; Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); + Result.MemoizationData = &Node; new (Result.Storage.buffer) const T * (&Node); return Result; } @@ -269,15 +329,21 @@ private: return reinterpret_cast<const T *>(Storage); return nullptr; } + static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) { + assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); + return *reinterpret_cast<const T *>(Storage); + } static DynTypedNode create(const T &Node) { DynTypedNode Result; Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); + Result.MemoizationData = nullptr; new (Result.Storage.buffer) T(Node); return Result; } }; ASTNodeKind NodeKind; + const void *MemoizationData; /// \brief Stores the data of the node. /// @@ -345,20 +411,15 @@ template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { } }; -inline const void *DynTypedNode::getMemoizationData() const { - if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) { - return BaseConverter<Decl>::get(NodeKind, Storage.buffer); - } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) { - return BaseConverter<Stmt>::get(NodeKind, Storage.buffer); - } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) { - return BaseConverter<Type>::get(NodeKind, Storage.buffer); - } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) { - return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer); - } - return nullptr; -} - } // end namespace ast_type_traits } // end namespace clang -#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H +namespace llvm { + +template <> +struct DenseMapInfo<clang::ast_type_traits::ASTNodeKind> + : clang::ast_type_traits::ASTNodeKind::DenseMapInfo {}; + +} // end namespace llvm + +#endif diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h index d92167e95992..6ec054582e26 100644 --- a/include/clang/AST/ASTVector.h +++ b/include/clang/AST/ASTVector.h @@ -15,8 +15,8 @@ // FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h. // We can refactor this core logic into something common. -#ifndef LLVM_CLANG_AST_VECTOR -#define LLVM_CLANG_AST_VECTOR +#ifndef LLVM_CLANG_AST_ASTVECTOR_H +#define LLVM_CLANG_AST_ASTVECTOR_H #include "clang/AST/AttrIterator.h" #include "llvm/ADT/PointerIntPair.h" @@ -236,14 +236,14 @@ public: iterator insert(const ASTContext &C, iterator I, size_type NumToInsert, const T &Elt) { - if (I == this->end()) { // Important special case for empty vector. - append(C, NumToInsert, Elt); - return this->end()-1; - } - // Convert iterator to elt# to avoid invalidating iterator when we reserve() size_t InsertElt = I - this->begin(); + if (I == this->end()) { // Important special case for empty vector. + append(C, NumToInsert, Elt); + return this->begin() + InsertElt; + } + // Ensure there is enough space. reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); @@ -284,14 +284,15 @@ public: template<typename ItTy> iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) { - if (I == this->end()) { // Important special case for empty vector. + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. append(C, From, To); - return this->end()-1; + return this->begin() + InsertElt; } size_t NumToInsert = std::distance(From, To); - // Convert iterator to elt# to avoid invalidating iterator when we reserve() - size_t InsertElt = I - this->begin(); // Ensure there is enough space. reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index fc4881619bce..787843e64f56 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -16,6 +16,7 @@ #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/LLVM.h" diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 7cccef69ddf8..aa3c84682983 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H -#define LLVM_CLANG_AST_CANONICAL_TYPE_H +#ifndef LLVM_CLANG_AST_CANONICALTYPE_H +#define LLVM_CLANG_AST_CANONICALTYPE_H #include "clang/AST/Type.h" #include "llvm/Support/Casting.h" @@ -736,4 +736,4 @@ CanTypeIterator<InputIterator>::operator->() const { } -#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H +#endif diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h index e18fe9ab86a0..94470cbf305f 100644 --- a/include/clang/AST/Comment.h +++ b/include/clang/AST/Comment.h @@ -96,9 +96,10 @@ protected: unsigned : NumInlineContentCommentBits; unsigned RenderKind : 2; - unsigned CommandID : 8; + unsigned CommandID : CommandInfo::NumCommandIDBits; }; - enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 }; + enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 2 + + CommandInfo::NumCommandIDBits }; class HTMLTagCommentBitfields { friend class HTMLTagComment; @@ -139,13 +140,14 @@ protected: unsigned : NumCommentBits; - unsigned CommandID : 8; + unsigned CommandID : CommandInfo::NumCommandIDBits; /// Describes the syntax that was used in a documentation command. /// Contains values from CommandMarkerKind enum. unsigned CommandMarker : 1; }; - enum { NumBlockCommandCommentBits = NumCommentBits + 9 }; + enum { NumBlockCommandCommentBits = NumCommentBits + + CommandInfo::NumCommandIDBits + 1 }; class ParamCommandCommentBitfields { friend class ParamCommandComment; diff --git a/include/clang/AST/CommentBriefParser.h b/include/clang/AST/CommentBriefParser.h index 5d508860635d..be5b8eeb80c3 100644 --- a/include/clang/AST/CommentBriefParser.h +++ b/include/clang/AST/CommentBriefParser.h @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H -#define LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H +#ifndef LLVM_CLANG_AST_COMMENTBRIEFPARSER_H +#define LLVM_CLANG_AST_COMMENTBRIEFPARSER_H #include "clang/AST/CommentLexer.h" diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h index dde7a1442fe1..ec6d83c03021 100644 --- a/include/clang/AST/CommentCommandTraits.h +++ b/include/clang/AST/CommentCommandTraits.h @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H -#define LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H +#ifndef LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H +#define LLVM_CLANG_AST_COMMENTCOMMANDTRAITS_H #include "clang/Basic/CommentOptions.h" #include "clang/Basic/LLVM.h" @@ -40,7 +40,11 @@ struct CommandInfo { /// Name of the command that ends the verbatim block. const char *EndCommandName; - unsigned ID : 8; + /// DRY definition of the number of bits used for a command ID. + enum { NumCommandIDBits = 20 }; + + /// The ID of the command. + unsigned ID : NumCommandIDBits; /// Number of word-like arguments for a given block command, except for /// \\param and \\tparam commands -- these have special argument parsers. diff --git a/include/clang/AST/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h index 312da065ff59..f3a209bf6e7c 100644 --- a/include/clang/AST/CommentDiagnostic.h +++ b/include/clang/AST/CommentDiagnostic.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_COMMENTDIAGNOSTIC_H -#define LLVM_CLANG_COMMENTDIAGNOSTIC_H +#ifndef LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H +#define LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H #include "clang/Basic/Diagnostic.h" diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h index a6e3ed89b27e..d995df921282 100644 --- a/include/clang/AST/CommentLexer.h +++ b/include/clang/AST/CommentLexer.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_COMMENT_LEXER_H -#define LLVM_CLANG_AST_COMMENT_LEXER_H +#ifndef LLVM_CLANG_AST_COMMENTLEXER_H +#define LLVM_CLANG_AST_COMMENTLEXER_H #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h index 7e008131d205..2c444f0dc3a6 100644 --- a/include/clang/AST/CommentParser.h +++ b/include/clang/AST/CommentParser.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_COMMENT_PARSER_H -#define LLVM_CLANG_AST_COMMENT_PARSER_H +#ifndef LLVM_CLANG_AST_COMMENTPARSER_H +#define LLVM_CLANG_AST_COMMENTPARSER_H #include "clang/AST/Comment.h" #include "clang/AST/CommentLexer.h" diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h index 027c3b929df6..4ae6fe0c613d 100644 --- a/include/clang/AST/CommentSema.h +++ b/include/clang/AST/CommentSema.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_COMMENT_SEMA_H -#define LLVM_CLANG_AST_COMMENT_SEMA_H +#ifndef LLVM_CLANG_AST_COMMENTSEMA_H +#define LLVM_CLANG_AST_COMMENTSEMA_H #include "clang/AST/Comment.h" #include "clang/Basic/Diagnostic.h" @@ -85,7 +85,7 @@ public: std::uninitialized_copy(Source.begin(), Source.end(), Mem); return llvm::makeArrayRef(Mem, Size); } - return ArrayRef<T>(); + return None; } ParagraphComment *actOnParagraphComment( diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 9ef008717b1b..c0526e1cfd45 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -424,6 +424,7 @@ private: bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + bool TraverseOMPLoopDirective(OMPLoopDirective *S); bool TraverseOMPClause(OMPClause *C); #define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C); #include "clang/Basic/OpenMPKinds.def" @@ -623,6 +624,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier( case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -647,6 +649,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -875,6 +878,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) @@ -1083,6 +1089,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) @@ -2122,21 +2131,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - if (S->hasExplicitParameters() || S->hasExplicitResultType()) { - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - if (S->hasExplicitParameters() && S->hasExplicitResultType()) { - // Visit the whole type. - TRY_TO(TraverseTypeLoc(TL)); - } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { - if (S->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { - TRY_TO(TraverseDecl(Proto.getParam(I))); - } - } else { - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); + + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else { + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getParam(I))); } + } else if (S->hasExplicitResultType()) { + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + } + + auto *T = Proto.getTypePtr(); + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); } TRY_TO(TraverseLambdaBody(S)); @@ -2237,6 +2254,7 @@ DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); }) DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {}) DEF_TRAVERSE_STMT(OpaqueValueExpr, {}) +DEF_TRAVERSE_STMT(TypoExpr, {}) DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {}) // These operators (all of them) do not need any action except @@ -2253,6 +2271,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {}) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {}) DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) +DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) // These literals (all of them) do not need any action. @@ -2279,6 +2298,12 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective( return true; } +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) { + return TraverseOMPExecutableDirective(S); +} + DEF_TRAVERSE_STMT(OMPParallelDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2288,6 +2313,9 @@ DEF_TRAVERSE_STMT(OMPSimdDirective, DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPSectionsDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2308,6 +2336,9 @@ DEF_TRAVERSE_STMT(OMPCriticalDirective, { DEF_TRAVERSE_STMT(OMPParallelForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPParallelForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPParallelSectionsDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2326,6 +2357,18 @@ DEF_TRAVERSE_STMT(OMPTaskwaitDirective, DEF_TRAVERSE_STMT(OMPFlushDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPOrderedDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPAtomicDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTargetDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTeamsDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { @@ -2415,6 +2458,31 @@ RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) { + return true; +} + +template <typename Derived> template <typename T> bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { @@ -2426,6 +2494,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } @@ -2433,6 +2504,12 @@ template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause( OMPFirstprivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } return true; } diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ce8b8b7dbcd6..a39888f9e1f0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -43,6 +43,7 @@ class Stmt; class StringLiteral; class TemplateArgumentList; class TemplateParameterList; +class TypeAliasTemplateDecl; class TypeLoc; class UnresolvedSetImpl; class VarTemplateDecl; @@ -67,6 +68,9 @@ public: /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc getTypeLoc() const; // implemented in TypeLoc.h + + /// \brief Override the type stored in this TypeSourceInfo. Use with caution! + void overrideType(QualType T) { Ty = T; } }; /// TranslationUnitDecl - The top declaration context. @@ -288,6 +292,8 @@ public: return const_cast<NamedDecl*>(this)->getMostRecentDecl(); } + ObjCStringFormatFamily getObjCFStringFormattingFamily() const; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; } }; @@ -305,6 +311,8 @@ inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { class LabelDecl : public NamedDecl { void anchor() override; LabelStmt *TheStmt; + StringRef MSAsmName; + bool MSAsmNameResolved; /// LocStart - For normal labels, this is the same as the main declaration /// label, i.e., the location of the identifier; for GNU local labels, /// this is the location of the __label__ keyword. @@ -312,7 +320,10 @@ class LabelDecl : public NamedDecl { LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, LabelStmt *S, SourceLocation StartL) - : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {} + : NamedDecl(Label, DC, IdentL, II), + TheStmt(S), + MSAsmNameResolved(false), + LocStart(StartL) {} public: static LabelDecl *Create(ASTContext &C, DeclContext *DC, @@ -332,6 +343,12 @@ public: return SourceRange(LocStart, getLocation()); } + bool isMSAsmLabel() const { return MSAsmName.size() != 0; } + bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; } + void setMSAsmLabel(StringRef Name); + StringRef getMSAsmLabel() const { return MSAsmName; } + void setMSAsmLabelResolved() { MSAsmNameResolved = true; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Label; } @@ -648,8 +665,6 @@ struct EvaluatedStmt { /// declaration or definition. class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { public: - typedef clang::StorageClass StorageClass; - /// getStorageClassSpecifierString - Return the string used to /// specify the storage class \p SC. /// @@ -891,6 +906,11 @@ public: return false; } + /// \brief Similar to isLocalVarDecl but also includes parameters. + bool isLocalVarDeclOrParm() const { + return isLocalVarDecl() || getKind() == Decl::ParmVar; + } + /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but /// excludes variables declared in blocks. bool isFunctionOrMethodVarDecl() const { @@ -1423,8 +1443,6 @@ private: class FunctionDecl : public DeclaratorDecl, public DeclContext, public Redeclarable<FunctionDecl> { public: - typedef clang::StorageClass StorageClass; - /// \brief The kind of templated function a FunctionDecl can be. enum TemplatedKind { TK_NonTemplate, @@ -1650,7 +1668,7 @@ public: /// unnecessary AST de-serialization of the body. Stmt *getBody(const FunctionDecl *&Definition) const; - Stmt *getBody() const override { + Stmt *getBody() const override { const FunctionDecl* Definition; return getBody(Definition); } @@ -1880,7 +1898,7 @@ public: return llvm::makeArrayRef(ParamInfo, getNumParams()); } - const ArrayRef<NamedDecl *> &getDeclsInPrototypeScope() const { + ArrayRef<NamedDecl *> getDeclsInPrototypeScope() const { return DeclsInPrototypeScope; } void setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls); @@ -2154,17 +2172,41 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { bool Mutable : 1; mutable unsigned CachedFieldIndex : 31; - /// \brief An InClassInitStyle value, and either a bit width expression (if - /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class - /// initializer for this field (otherwise). + /// The kinds of value we can store in InitializerOrBitWidth. /// - /// We can safely combine these two because in-class initializers are not - /// permitted for bit-fields. + /// Note that this is compatible with InClassInitStyle except for + /// ISK_CapturedVLAType. + enum InitStorageKind { + /// If the pointer is null, there's nothing special. Otherwise, + /// this is a bitfield and the pointer is the Expr* storing the + /// bit-width. + ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the copy-initializer. + ISK_InClassCopyInit = (unsigned) ICIS_CopyInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the list-initializer. + ISK_InClassListInit = (unsigned) ICIS_ListInit, + + /// The pointer is a VariableArrayType* that's been captured; + /// the enclosing context is a lambda or captured statement. + ISK_CapturedVLAType, + }; + + /// \brief Storage for either the bit-width, the in-class + /// initializer, or the captured variable length array bound. + /// + /// We can safely combine these because in-class initializers are + /// not permitted for bit-fields, and both are exclusive with VLA + /// captures. /// - /// If the InClassInitStyle is not ICIS_NoInit and the initializer is null, - /// then this field has an in-class initializer which has not yet been parsed + /// If the storage kind is ISK_InClassCopyInit or + /// ISK_InClassListInit, but the initializer is null, then this + /// field has an in-class initializer which has not yet been parsed /// and attached. - llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth; + llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, @@ -2172,7 +2214,7 @@ protected: InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable), CachedFieldIndex(0), - InitializerOrBitWidth(BW, InitStyle) { + InitStorage(BW, (InitStorageKind) InitStyle) { assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); } @@ -2192,10 +2234,10 @@ public: /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } - /// isBitfield - Determines whether this field is a bitfield. + /// \brief Determines whether this field is a bitfield. bool isBitField() const { - return getInClassInitStyle() == ICIS_NoInit && - InitializerOrBitWidth.getPointer(); + return InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() != nullptr; } /// @brief Determines whether this is an unnamed bitfield. @@ -2208,24 +2250,34 @@ public: bool isAnonymousStructOrUnion() const; Expr *getBitWidth() const { - return isBitField() ? InitializerOrBitWidth.getPointer() : nullptr; + return isBitField() + ? static_cast<Expr *>(InitStorage.getPointer()) + : nullptr; } unsigned getBitWidthValue(const ASTContext &Ctx) const; /// setBitWidth - Set the bit-field width for this member. // Note: used by some clients (i.e., do not remove it). - void setBitWidth(Expr *Width); + void setBitWidth(Expr *Width) { + assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() == nullptr && + "bit width, initializer or captured type already set"); + InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); + } + /// removeBitWidth - Remove the bit-field width from this member. // Note: used by some clients (i.e., do not remove it). void removeBitWidth() { assert(isBitField() && "no bitfield width to remove"); - InitializerOrBitWidth.setPointer(nullptr); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); } /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which /// this field has. InClassInitStyle getInClassInitStyle() const { - return static_cast<InClassInitStyle>(InitializerOrBitWidth.getInt()); + InitStorageKind storageKind = InitStorage.getInt(); + return (storageKind == ISK_CapturedVLAType + ? ICIS_NoInit : (InClassInitStyle) storageKind); } /// hasInClassInitializer - Determine whether this member has a C++11 in-class @@ -2233,24 +2285,47 @@ public: bool hasInClassInitializer() const { return getInClassInitStyle() != ICIS_NoInit; } + /// getInClassInitializer - Get the C++11 in-class initializer for this /// member, or null if one has not been set. If a valid declaration has an /// in-class initializer, but this returns null, then we have not parsed and /// attached it yet. Expr *getInClassInitializer() const { - return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() - : nullptr; + return hasInClassInitializer() + ? static_cast<Expr *>(InitStorage.getPointer()) + : nullptr; } + /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. - void setInClassInitializer(Expr *Init); + void setInClassInitializer(Expr *Init) { + assert(hasInClassInitializer() && + InitStorage.getPointer() == nullptr && + "bit width, initializer or captured type already set"); + InitStorage.setPointer(Init); + } + /// removeInClassInitializer - Remove the C++11 in-class initializer from this /// member. void removeInClassInitializer() { assert(hasInClassInitializer() && "no initializer to remove"); - InitializerOrBitWidth.setPointer(nullptr); - InitializerOrBitWidth.setInt(ICIS_NoInit); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + } + + /// \brief Determine whether this member captures the variable length array + /// type. + bool hasCapturedVLAType() const { + return InitStorage.getInt() == ISK_CapturedVLAType; + } + + /// \brief Get the captured variable length array type. + const VariableArrayType *getCapturedVLAType() const { + return hasCapturedVLAType() ? static_cast<const VariableArrayType *>( + InitStorage.getPointer()) + : nullptr; } + /// \brief Set the captured variable length array type for this field. + void setCapturedVLAType(const VariableArrayType *VLAType); /// getParent - Returns the parent of this field declaration, which /// is the struct in which this method is defined. @@ -2492,9 +2567,13 @@ public: /// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x /// alias-declaration. class TypeAliasDecl : public TypedefNameDecl { + /// The template for which this is the pattern, if any. + TypeAliasTemplateDecl *Template; + TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) - : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo) {} + : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), + Template(nullptr) {} public: static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, @@ -2504,6 +2583,9 @@ public: SourceRange getSourceRange() const override LLVM_READONLY; + TypeAliasTemplateDecl *getDescribedAliasTemplate() const { return Template; } + void setDescribedAliasTemplate(TypeAliasTemplateDecl *TAT) { Template = TAT; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TypeAlias; } @@ -2647,7 +2729,7 @@ public: } /// isThisDeclarationADefinition() - Return true if this declaration - /// is a completion definintion of the type. Provided for consistency. + /// is a completion definition of the type. Provided for consistency. bool isThisDeclarationADefinition() const { return isCompleteDefinition(); } @@ -3136,6 +3218,17 @@ public: /// \endcode bool isInjectedClassName() const; + /// \brief Determine whether this record is a class describing a lambda + /// function object. + bool isLambda() const; + + /// \brief Determine whether this record is a record for captured variables in + /// CapturedStmt construct. + bool isCapturedRecord() const; + /// \brief Mark the record as a record for captured variables in CapturedStmt + /// construct. + void setCapturedRecord(); + /// getDefinition - Returns the RecordDecl that actually defines /// this struct/union/class. When determining whether or not a /// struct/union/class is completely defined, one should use this @@ -3181,6 +3274,15 @@ public: /// commandline option. bool isMsStruct(const ASTContext &C) const; + /// \brief Whether we are allowed to insert extra padding between fields. + /// These padding are added to help AddressSanitizer detect + /// intra-object-overflow bugs. + bool mayInsertExtraPadding(bool EmitRemark = false) const; + + /// Finds the first data member which has a name. + /// nullptr is returned if no named data member exists. + const FieldDecl *findFirstNamedDataMember() const; + private: /// \brief Deserialize just the fields. void LoadFieldsFromExternalStorage() const; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 607ca4ec27c6..984ab13df426 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -48,6 +48,7 @@ class ObjCInterfaceDecl; class ObjCMethodDecl; class ObjCProtocolDecl; struct PrintingPolicy; +class RecordDecl; class Stmt; class StoredDeclsMap; class TranslationUnitDecl; @@ -515,9 +516,13 @@ public: /// indicating the declaration is used. void markUsed(ASTContext &C); - /// \brief Whether this declaration was referenced. + /// \brief Whether any declaration of this entity was referenced. bool isReferenced() const; + /// \brief Whether this declaration was referenced. This should not be relied + /// upon for anything other than debugging. + bool isThisDeclarationReferenced() const { return Referenced; } + void setReferenced(bool R = true) { Referenced = R; } /// \brief Whether this declaration is a top-level declaration (function, @@ -675,9 +680,9 @@ public: return const_cast<Decl*>(this)->getLexicalDeclContext(); } - virtual bool isOutOfLine() const { - return getLexicalDeclContext() != getDeclContext(); - } + /// Determine whether this declaration is declared out of line (outside its + /// semantic context). + virtual bool isOutOfLine() const; /// setDeclContext - Set both the semantic and lexical DeclContext /// to DC. @@ -1234,6 +1239,12 @@ public: return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext(); } + /// \brief Retrieve the outermost lexically enclosing record context. + RecordDecl *getOuterLexicalRecordContext(); + const RecordDecl *getOuterLexicalRecordContext() const { + return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext(); + } + /// \brief Test if this context is part of the enclosing namespace set of /// the context NS, as defined in C++0x [namespace.def]p9. If either context /// isn't a namespace, this is equivalent to Equals(). @@ -1642,7 +1653,7 @@ public: void dumpDeclContext() const; void dumpLookups() const; - void dumpLookups(llvm::raw_ostream &OS) const; + void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const; private: void reconcileExternalVisibleStorage() const; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 72fad7c28e49..027b41e27da3 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -538,6 +538,12 @@ class CXXRecordDecl : public RecordDecl { ManglingNumber(0), ContextDecl(nullptr), Captures(nullptr), MethodTyInfo(Info) { IsLambda = true; + + // C++11 [expr.prim.lambda]p3: + // This class type is neither an aggregate nor a literal type. + Aggregate = false; + PlainOldData = false; + HasNonLiteralTypeFieldsOrBases = true; } /// \brief Whether this lambda is known to be dependent, even if its @@ -820,7 +826,11 @@ public: /// This value is used for lazy creation of default constructors. bool needsImplicitDefaultConstructor() const { return !data().UserDeclaredConstructor && - !(data().DeclaredSpecialMembers & SMF_DefaultConstructor); + !(data().DeclaredSpecialMembers & SMF_DefaultConstructor) && + // C++14 [expr.prim.lambda]p20: + // The closure type associated with a lambda-expression has no + // default constructor. + !isLambda(); } /// \brief Determine whether this class has any user-declared constructors. @@ -1371,6 +1381,15 @@ public: /// \brief Set the kind of specialization or template instantiation this is. void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + /// \brief Retrieve the record declaration from which this record could be + /// instantiated. Returns null if this class is not a template instantiation. + const CXXRecordDecl *getTemplateInstantiationPattern() const; + + CXXRecordDecl *getTemplateInstantiationPattern() { + return const_cast<CXXRecordDecl *>(const_cast<const CXXRecordDecl *>(this) + ->getTemplateInstantiationPattern()); + } + /// \brief Returns the destructor decl for this class. CXXDestructorDecl *getDestructor() const; @@ -2104,8 +2123,8 @@ public: } ArrayRef<VarDecl *> getArrayIndexes() { assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init"); - return ArrayRef<VarDecl *>(reinterpret_cast<VarDecl **>(this + 1), - getNumArrayIndices()); + return llvm::makeArrayRef(reinterpret_cast<VarDecl **>(this + 1), + getNumArrayIndices()); } /// \brief Get the initializer. @@ -2636,7 +2655,8 @@ public: /// \code /// namespace Foo = Bar; /// \endcode -class NamespaceAliasDecl : public NamedDecl { +class NamespaceAliasDecl : public NamedDecl, + public Redeclarable<NamespaceAliasDecl> { void anchor() override; /// \brief The location of the \c namespace keyword. @@ -2654,17 +2674,47 @@ class NamespaceAliasDecl : public NamedDecl { /// a NamespaceAliasDecl. NamedDecl *Namespace; - NamespaceAliasDecl(DeclContext *DC, SourceLocation NamespaceLoc, - SourceLocation AliasLoc, IdentifierInfo *Alias, - NestedNameSpecifierLoc QualifierLoc, + NamespaceAliasDecl(ASTContext &C, DeclContext *DC, + SourceLocation NamespaceLoc, SourceLocation AliasLoc, + IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, NamedDecl *Namespace) - : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), - NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), - QualifierLoc(QualifierLoc), Namespace(Namespace) { } + : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C), + NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), + QualifierLoc(QualifierLoc), Namespace(Namespace) {} + + typedef Redeclarable<NamespaceAliasDecl> redeclarable_base; + NamespaceAliasDecl *getNextRedeclarationImpl() override; + NamespaceAliasDecl *getPreviousDeclImpl() override; + NamespaceAliasDecl *getMostRecentDeclImpl() override; friend class ASTDeclReader; public: + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Namespace); + + static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef redeclarable_base::redecl_range redecl_range; + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + NamespaceAliasDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const NamespaceAliasDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + /// \brief Retrieve the nested-name-specifier that qualifies the /// name of the namespace, with source-location information. NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } @@ -2701,16 +2751,6 @@ public: /// may either be a NamespaceDecl or a NamespaceAliasDecl. NamedDecl *getAliasedNamespace() const { return Namespace; } - static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation IdentLoc, - NamedDecl *Namespace); - - static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); - SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(NamespaceLoc, IdentLoc); } @@ -2824,7 +2864,7 @@ public: /// \code /// using someNameSpace::someIdentifier; /// \endcode -class UsingDecl : public NamedDecl { +class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> { void anchor() override; /// \brief The source location of the 'using' keyword itself. @@ -2948,6 +2988,10 @@ public: SourceRange getSourceRange() const override LLVM_READONLY; + /// Retrieves the canonical declaration of this declaration. + UsingDecl *getCanonicalDecl() override { return getFirstDecl(); } + const UsingDecl *getCanonicalDecl() const { return getFirstDecl(); } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Using; } @@ -2966,7 +3010,8 @@ public: /// using Base<T>::foo; /// }; /// \endcode -class UnresolvedUsingValueDecl : public ValueDecl { +class UnresolvedUsingValueDecl : public ValueDecl, + public Mergeable<UnresolvedUsingValueDecl> { void anchor() override; /// \brief The source location of the 'using' keyword @@ -3022,6 +3067,14 @@ public: SourceRange getSourceRange() const override LLVM_READONLY; + /// Retrieves the canonical declaration of this declaration. + UnresolvedUsingValueDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const UnresolvedUsingValueDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == UnresolvedUsingValue; } @@ -3040,7 +3093,9 @@ public: /// /// The type associated with an unresolved using typename decl is /// currently always a typename type. -class UnresolvedUsingTypenameDecl : public TypeDecl { +class UnresolvedUsingTypenameDecl + : public TypeDecl, + public Mergeable<UnresolvedUsingTypenameDecl> { void anchor() override; /// \brief The source location of the 'typename' keyword @@ -3084,6 +3139,14 @@ public: static UnresolvedUsingTypenameDecl * CreateDeserialized(ASTContext &C, unsigned ID); + /// Retrieves the canonical declaration of this declaration. + UnresolvedUsingTypenameDecl *getCanonicalDecl() override { + return getFirstDecl(); + } + const UnresolvedUsingTypenameDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; } }; diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h index d2016af89f13..eba2266724fd 100644 --- a/include/clang/AST/DeclLookups.h +++ b/include/clang/AST/DeclLookups.h @@ -75,7 +75,10 @@ inline DeclContext::lookups_range DeclContext::lookups() const { if (StoredDeclsMap *Map = Primary->buildLookup()) return lookups_range(all_lookups_iterator(Map->begin(), Map->end()), all_lookups_iterator(Map->end(), Map->end())); - return lookups_range(); + + // Synthesize an empty range. This requires that two default constructed + // versions of these iterators form a valid empty range. + return lookups_range(all_lookups_iterator(), all_lookups_iterator()); } inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { @@ -91,7 +94,10 @@ inline DeclContext::lookups_range DeclContext::noload_lookups() const { if (StoredDeclsMap *Map = Primary->getLookupPtr()) return lookups_range(all_lookups_iterator(Map->begin(), Map->end()), all_lookups_iterator(Map->end(), Map->end())); - return lookups_range(); + + // Synthesize an empty range. This requires that two default constructed + // versions of these iterators form a valid empty range. + return lookups_range(all_lookups_iterator(), all_lookups_iterator()); } inline diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index db3b0849382a..55d4b0f16953 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -329,6 +329,7 @@ public: QualType getReturnType() const { return MethodDeclType; } void setReturnType(QualType T) { MethodDeclType = T; } + SourceRange getReturnTypeSourceRange() const; /// \brief Determine the type of an expression that sends a message to this /// function. @@ -378,8 +379,7 @@ public: /// ignored. void setMethodParams(ASTContext &C, ArrayRef<ParmVarDecl*> Params, - ArrayRef<SourceLocation> SelLocs = - ArrayRef<SourceLocation>()); + ArrayRef<SourceLocation> SelLocs = llvm::None); // Iterator access to parameter types. typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun; @@ -591,7 +591,8 @@ public: bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const; ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; - ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; + ObjCPropertyDecl * + FindPropertyDeclaration(const IdentifierInfo *PropertyId) const; typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap; @@ -2354,7 +2355,7 @@ public: /// Lookup a property by name in the specified DeclContext. static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC, - IdentifierInfo *propertyID); + const IdentifierInfo *propertyID); static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCProperty; } diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h index 1b329dcd0052..7f0616f1e603 100644 --- a/include/clang/AST/DeclOpenMP.h +++ b/include/clang/AST/DeclOpenMP.h @@ -12,13 +12,14 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_OPENMP_H -#define LLVM_CLANG_AST_OPENMP_H +#ifndef LLVM_CLANG_AST_DECLOPENMP_H +#define LLVM_CLANG_AST_DECLOPENMP_H #include "clang/AST/DeclBase.h" #include "llvm/ADT/ArrayRef.h" namespace clang { +class Expr; /// \brief This represents '#pragma omp threadprivate ...' directive. /// For example, in the following, both 'a' and 'A::b' are threadprivate: @@ -42,9 +43,8 @@ class OMPThreadPrivateDecl : public Decl { Decl(DK, DC, L), NumVars(0) { } ArrayRef<const Expr *> getVars() const { - return ArrayRef<const Expr *>( - reinterpret_cast<const Expr * const *>(this + 1), - NumVars); + return llvm::makeArrayRef(reinterpret_cast<const Expr * const *>(this + 1), + NumVars); } MutableArrayRef<Expr *> getVars() { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 980a06e35b70..9283d2dc4350 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -87,10 +87,10 @@ public: unsigned size() const { return NumParams; } ArrayRef<NamedDecl*> asArray() { - return ArrayRef<NamedDecl*>(begin(), size()); + return llvm::makeArrayRef(begin(), end()); } ArrayRef<const NamedDecl*> asArray() const { - return ArrayRef<const NamedDecl*>(begin(), size()); + return llvm::makeArrayRef(begin(), size()); } NamedDecl* getParam(unsigned Idx) { @@ -204,7 +204,7 @@ public: /// \brief Produce this as an array ref. ArrayRef<TemplateArgument> asArray() const { - return ArrayRef<TemplateArgument>(data(), size()); + return llvm::makeArrayRef(data(), size()); } /// \brief Retrieve the number of template arguments in this @@ -236,7 +236,7 @@ protected: TemplateParams(nullptr) {} // Construct a template decl with the given name and parameters. - // Used when there is not templated element (tt-params, alias?). + // Used when there is not templated element (tt-params). TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params) : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 3076b30cd377..49e51e09b830 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -59,6 +59,7 @@ public: CXXLiteralOperatorName, CXXUsingDirective }; + static const unsigned NumNameKinds = CXXUsingDirective + 1; private: /// StoredNameKind - The kind of name that is actually stored in the diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h index 63047ec4db84..8e038c83c989 100644 --- a/include/clang/AST/DependentDiagnostic.h +++ b/include/clang/AST/DependentDiagnostic.h @@ -15,8 +15,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H -#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H +#ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H +#define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H #include "clang/AST/DeclBase.h" #include "clang/AST/DeclContextInternals.h" @@ -178,7 +178,8 @@ inline DeclContext::ddiag_range DeclContext::ddiags() const { = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr()); if (!Map) - return ddiag_range(); + // Return an empty range using the always-end default constructor. + return ddiag_range(ddiag_iterator(), ddiag_iterator()); return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator()); } diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h index 12c4fcc49b01..59de104b83f9 100644 --- a/include/clang/AST/EvaluatedExprVisitor.h +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -56,6 +56,17 @@ public: return this->Visit(E->getChosenSubExpr()); } + void VisitGenericSelectionExpr(GenericSelectionExpr *E) { + // The controlling expression of a generic selection is not evaluated. + + // Don't visit either child expression if the condition is type-dependent. + if (E->isResultDependent()) + return; + // Only the selected subexpression matters; the other subexpressions and the + // controlling expression are not evaluated. + return this->Visit(E->getResultExpr()); + } + void VisitDesignatedInitExpr(DesignatedInitExpr *E) { // Only the actual initializer matters; the designators are all constant // expressions. diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index b4bb0b6b6440..c410f2358bc7 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -45,6 +45,7 @@ namespace clang { class ObjCPropertyRefExpr; class OpaqueValueExpr; class ParmVarDecl; + class StringLiteral; class TargetInfo; class ValueDecl; @@ -124,8 +125,7 @@ public: QualType getType() const { return TR; } void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it - // will not have reference type an expression will never have - // reference type (C++ [expr]p6). Use + // will not have reference type (C++ [expr]p6). Use // QualType::getNonReferenceType() to retrieve the non-reference // type. Additionally, inspect Expr::isLvalue to determine whether // an expression that is adjusted in this manner should be @@ -586,8 +586,13 @@ public: /// HasSideEffects - This routine returns true for all those expressions /// which have any effect other than producing a value. Example is a function - /// call, volatile variable read, or throwing an exception. - bool HasSideEffects(const ASTContext &Ctx) const; + /// call, volatile variable read, or throwing an exception. If + /// IncludePossibleEffects is false, this call treats certain expressions with + /// potential side effects (such as function call-like expressions, + /// instantiation-dependent expressions, or invocations from a macro) as not + /// having side effects. + bool HasSideEffects(const ASTContext &Ctx, + bool IncludePossibleEffects = true) const; /// \brief Determine whether this expression involves a call to any function /// that is not trivial. @@ -886,9 +891,9 @@ public: /// DeclRefExprBits.HasTemplateKWAndArgsInfo: /// Specifies when this declaration reference expression has an explicit /// C++ template keyword and/or template argument list. -/// DeclRefExprBits.RefersToEnclosingLocal +/// DeclRefExprBits.RefersToEnclosingVariableOrCapture /// Specifies when this declaration reference expression (validly) -/// refers to a local variable from a different function. +/// refers to an enclosed local or a captured variable. class DeclRefExpr : public Expr { /// \brief The declaration that we are referencing. ValueDecl *D; @@ -933,7 +938,7 @@ class DeclRefExpr : public Expr { DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - ValueDecl *D, bool refersToEnclosingLocal, + ValueDecl *D, bool RefersToEnlosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, @@ -948,7 +953,7 @@ class DeclRefExpr : public Expr { void computeDependence(const ASTContext &C); public: - DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T, + DeclRefExpr(ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), @@ -957,20 +962,22 @@ public: DeclRefExprBits.HasTemplateKWAndArgsInfo = 0; DeclRefExprBits.HasFoundDecl = 0; DeclRefExprBits.HadMultipleCandidates = 0; - DeclRefExprBits.RefersToEnclosingLocal = refersToEnclosingLocal; + DeclRefExprBits.RefersToEnclosingVariableOrCapture = + RefersToEnclosingVariableOrCapture; computeDependence(D->getASTContext()); } static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal, - SourceLocation NameLoc, QualType T, ExprValueKind VK, - NamedDecl *FoundD = nullptr, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, + QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *D, bool isEnclosingLocal, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); @@ -1144,10 +1151,10 @@ public: DeclRefExprBits.HadMultipleCandidates = V; } - /// Does this DeclRefExpr refer to a local declaration from an - /// enclosing function scope? - bool refersToEnclosingLocal() const { - return DeclRefExprBits.RefersToEnclosingLocal; + /// \brief Does this DeclRefExpr refer to an enclosing local or a captured + /// variable? + bool refersToEnclosingVariableOrCapture() const { + return DeclRefExprBits.RefersToEnclosingVariableOrCapture; } static bool classof(const Stmt *T) { @@ -1161,7 +1168,7 @@ public: friend class ASTStmtWriter; }; -/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__. +/// \brief [C99 6.4.2.2] - A predefined identifier such as __func__. class PredefinedExpr : public Expr { public: enum IdentType { @@ -1171,7 +1178,7 @@ public: FuncDName, FuncSig, PrettyFunction, - /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the + /// \brief The same as PrettyFunction, except that the /// 'virtual' keyword is omitted for virtual member functions. PrettyFunctionNoVirtual }; @@ -1179,24 +1186,27 @@ public: private: SourceLocation Loc; IdentType Type; + Stmt *FnName; + public: - PredefinedExpr(SourceLocation l, QualType type, IdentType IT) - : Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary, - type->isDependentType(), type->isDependentType(), - type->isInstantiationDependentType(), - /*ContainsUnexpandedParameterPack=*/false), - Loc(l), Type(IT) {} + PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, + StringLiteral *SL); /// \brief Construct an empty predefined expression. explicit PredefinedExpr(EmptyShell Empty) - : Expr(PredefinedExprClass, Empty) { } + : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {} IdentType getIdentType() const { return Type; } - void setIdentType(IdentType IT) { Type = IT; } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } + StringLiteral *getFunctionName(); + const StringLiteral *getFunctionName() const { + return const_cast<PredefinedExpr *>(this)->getFunctionName(); + } + + static StringRef getIdentTypeName(IdentType IT); static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); SourceLocation getLocStart() const LLVM_READONLY { return Loc; } @@ -1207,7 +1217,9 @@ public: } // Iterators - child_range children() { return child_range(); } + child_range children() { return child_range(&FnName, &FnName + 1); } + + friend class ASTStmtReader; }; /// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without @@ -2212,11 +2224,11 @@ public: /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]); + return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); } const Expr *getArg(unsigned Arg) const { assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]); + return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); } /// setArg - Set the specified argument. @@ -2256,8 +2268,8 @@ public: /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. ArrayRef<Stmt*> getRawSubExprs() { - return ArrayRef<Stmt*>(SubExprs, - getNumPreArgs() + PREARGS_START + getNumArgs()); + return llvm::makeArrayRef(SubExprs, + getNumPreArgs() + PREARGS_START + getNumArgs()); } /// getNumCommas - Return the number of commas that must have been present in @@ -2653,9 +2665,6 @@ public: /// representation in the source code (ExplicitCastExpr's derived /// classes). class CastExpr : public Expr { -public: - typedef clang::CastKind CastKind; - private: Stmt *Op; @@ -2673,20 +2682,23 @@ private: } protected: - CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, - const CastKind kind, Expr *op, unsigned BasePathSize) : - Expr(SC, ty, VK, OK_Ordinary, - // Cast expressions are type-dependent if the type is - // dependent (C++ [temp.dep.expr]p3). - ty->isDependentType(), - // Cast expressions are value-dependent if the type is - // dependent or if the subexpression is value-dependent. - ty->isDependentType() || (op && op->isValueDependent()), - (ty->isInstantiationDependentType() || - (op && op->isInstantiationDependent())), - (ty->containsUnexpandedParameterPack() || - (op && op->containsUnexpandedParameterPack()))), - Op(op) { + CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, + Expr *op, unsigned BasePathSize) + : Expr(SC, ty, VK, OK_Ordinary, + // Cast expressions are type-dependent if the type is + // dependent (C++ [temp.dep.expr]p3). + ty->isDependentType(), + // Cast expressions are value-dependent if the type is + // dependent or if the subexpression is value-dependent. + ty->isDependentType() || (op && op->isValueDependent()), + (ty->isInstantiationDependentType() || + (op && op->isInstantiationDependent())), + // An implicit cast expression doesn't (lexically) contain an + // unexpanded pack, even if its target type does. + ((SC != ImplicitCastExprClass && + ty->containsUnexpandedParameterPack()) || + (op && op->containsUnexpandedParameterPack()))), + Op(op) { assert(kind != CK_Invalid && "creating cast with invalid cast kind"); CastExprBits.Kind = kind; setBasePathSize(BasePathSize); @@ -4841,6 +4853,24 @@ public: return child_range(SubExprs, SubExprs+NumSubExprs); } }; + +/// TypoExpr - Internal placeholder for expressions where typo correction +/// still needs to be performed and/or an error diagnostic emitted. +class TypoExpr : public Expr { +public: + TypoExpr(QualType T) + : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary, + /*isTypeDependent*/ true, + /*isValueDependent*/ true, + /*isInstantiationDependent*/ true, + /*containsUnexpandedParameterPack*/ false) { + assert(T->isDependentType() && "TypoExpr given a non-dependent type"); + } + + child_range children() { return child_range(); } + SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } +}; } // end namespace clang #endif diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 3a43d6dac140..176817823ea9 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -17,10 +17,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/ExpressionTraits.h" -#include "clang/AST/LambdaCapture.h" #include "clang/Basic/TypeTraits.h" #include "llvm/Support/Compiler.h" @@ -967,8 +967,14 @@ public: const FieldDecl *getField() const { return Field; } /// \brief Get the initialization expression that will be used. - const Expr *getExpr() const { return Field->getInClassInitializer(); } - Expr *getExpr() { return Field->getInClassInitializer(); } + const Expr *getExpr() const { + assert(Field->getInClassInitializer() && "initializer hasn't been parsed"); + return Field->getInClassInitializer(); + } + Expr *getExpr() { + assert(Field->getInClassInitializer() && "initializer hasn't been parsed"); + return Field->getInClassInitializer(); + } SourceLocation getLocStart() const LLVM_READONLY { return Loc; } SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } @@ -1165,6 +1171,13 @@ public: 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; + + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } + arg_const_range arguments() const { + return arg_const_range(arg_begin(), arg_end()); + } arg_iterator arg_begin() { return Args; } arg_iterator arg_end() { return Args + NumArgs; } @@ -1569,12 +1582,12 @@ class CXXScalarValueInitExpr : public Expr { public: /// \brief Create an explicitly-written scalar-value initialization /// expression. - CXXScalarValueInitExpr(QualType Type, - TypeSourceInfo *TypeInfo, - SourceLocation rParenLoc ) : - Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, - false, false, Type->isInstantiationDependentType(), false), - RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} + CXXScalarValueInitExpr(QualType Type, TypeSourceInfo *TypeInfo, + SourceLocation rParenLoc) + : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, + false, false, Type->isInstantiationDependentType(), + Type->containsUnexpandedParameterPack()), + RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} explicit CXXScalarValueInitExpr(EmptyShell Shell) : Expr(CXXScalarValueInitExprClass, Shell) { } @@ -2113,7 +2126,7 @@ public: /// \brief Retrieve the argument types. ArrayRef<TypeSourceInfo *> getArgs() const { - return ArrayRef<TypeSourceInfo *>(getTypeSourceInfos(), getNumArgs()); + return llvm::makeArrayRef(getTypeSourceInfos(), getNumArgs()); } typedef TypeSourceInfo **arg_iterator; @@ -2767,7 +2780,7 @@ public: ArrayRef<CleanupObject> objects); ArrayRef<CleanupObject> getObjects() const { - return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects()); + return llvm::makeArrayRef(getObjectsBuffer(), getNumObjects()); } unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; } @@ -2902,8 +2915,9 @@ public: SourceLocation getLocStart() const LLVM_READONLY; SourceLocation getLocEnd() const LLVM_READONLY { - assert(RParenLoc.isValid() || NumArgs == 1); - return RParenLoc.isValid() ? RParenLoc : getArg(0)->getLocEnd(); + if (!RParenLoc.isValid() && NumArgs > 0) + return getArg(NumArgs - 1)->getLocEnd(); + return RParenLoc; } static bool classof(const Stmt *T) { @@ -3811,6 +3825,69 @@ public: } }; +/// \brief Represents a folding of a pack over an operator. +/// +/// This expression is always dependent and represents a pack expansion of the +/// forms: +/// +/// ( expr op ... ) +/// ( ... op expr ) +/// ( expr op ... op expr ) +class CXXFoldExpr : public Expr { + 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, + SourceLocation RParenLoc) + : Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary, + /*Dependent*/ true, true, true, + /*ContainsUnexpandedParameterPack*/ false), + LParenLoc(LParenLoc), EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc), + Opcode(Opcode) { + SubExprs[0] = LHS; + SubExprs[1] = RHS; + } + CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {} + + Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); } + Expr *getRHS() const { return static_cast<Expr*>(SubExprs[1]); } + + /// Does this produce a right-associated sequence of operators? + 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(); } + + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + BinaryOperatorKind getOperator() const { return Opcode; } + + SourceLocation getLocStart() const LLVM_READONLY { + return LParenLoc; + } + SourceLocation getLocEnd() const LLVM_READONLY { + return RParenLoc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFoldExprClass; + } + + // Iterators + child_range children() { return child_range(SubExprs, SubExprs + 2); } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 817c0cc43131..f296e8f71d30 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -124,6 +124,15 @@ public: // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } + + typedef ConstExprIterator const_arg_iterator; + + 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; }; diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 1e8eff38d3ec..ff1d180ee8c6 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -11,8 +11,8 @@ // construction of AST nodes from some external source. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H -#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H +#ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H +#define LLVM_CLANG_AST_EXTERNALASTSOURCE_H #include "clang/AST/CharUnits.h" #include "clang/AST/DeclBase.h" @@ -650,4 +650,4 @@ typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, } // end namespace clang -#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H +#endif diff --git a/include/clang/AST/LambdaCapture.h b/include/clang/AST/LambdaCapture.h index 8633c9796523..a7468a0fd53f 100644 --- a/include/clang/AST/LambdaCapture.h +++ b/include/clang/AST/LambdaCapture.h @@ -68,13 +68,23 @@ public: /// \brief Determine whether this capture handles the C++ \c this /// pointer. - bool capturesThis() const { return DeclAndBits.getPointer() == nullptr; } + bool capturesThis() const { + return (DeclAndBits.getPointer() == nullptr) && + !(DeclAndBits.getInt() & Capture_ByCopy); + } /// \brief Determine whether this capture handles a variable. bool capturesVariable() const { return dyn_cast_or_null<VarDecl>(DeclAndBits.getPointer()); } + /// \brief Determine whether this captures a variable length array bound + /// expression. + bool capturesVLAType() const { + return (DeclAndBits.getPointer() == nullptr) && + (DeclAndBits.getInt() & Capture_ByCopy); + } + /// \brief Determine whether this is an init-capture. bool isInitCapture() const { return capturesVariable() && getCapturedVar()->isInitCapture(); diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index a8d119971b33..cbe08a1a765e 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -156,6 +156,11 @@ public: virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &) = 0; + virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D, + raw_ostream &) = 0; + virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, + raw_ostream &) = 0; + static bool classof(const MangleContext *C) { return C->getKind() == MK_Itanium; } diff --git a/include/clang/AST/MangleNumberingContext.h b/include/clang/AST/MangleNumberingContext.h index 56c995264b32..7a818557fdb7 100644 --- a/include/clang/AST/MangleNumberingContext.h +++ b/include/clang/AST/MangleNumberingContext.h @@ -12,8 +12,8 @@ // literals. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H -#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H +#ifndef LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H +#define LLVM_CLANG_AST_MANGLENUMBERINGCONTEXT_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -30,23 +30,20 @@ class VarDecl; /// \brief Keeps track of the mangled names of lambda expressions and block /// literals within a particular context. -class MangleNumberingContext - : public RefCountedBase<MangleNumberingContext> { - llvm::DenseMap<const Type *, unsigned> ManglingNumbers; - +class MangleNumberingContext : public RefCountedBase<MangleNumberingContext> { public: virtual ~MangleNumberingContext() {} /// \brief Retrieve the mangling number of a new lambda expression with the /// given call operator within this context. - unsigned getManglingNumber(const CXXMethodDecl *CallOperator); + virtual unsigned getManglingNumber(const CXXMethodDecl *CallOperator) = 0; /// \brief Retrieve the mangling number of a new block literal within this /// context. - unsigned getManglingNumber(const BlockDecl *BD); + virtual unsigned getManglingNumber(const BlockDecl *BD) = 0; /// Static locals are numbered by source order. - unsigned getStaticLocalNumber(const VarDecl *VD); + virtual unsigned getStaticLocalNumber(const VarDecl *VD) = 0; /// \brief Retrieve the mangling number of a static local variable within /// this context. @@ -58,6 +55,6 @@ public: virtual unsigned getManglingNumber(const TagDecl *TD, unsigned MSLocalManglingNumber) = 0; }; - + } // end namespace clang #endif diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h index 0b21b0334812..33fcce2109aa 100644 --- a/include/clang/AST/NSAPI.h +++ b/include/clang/AST/NSAPI.h @@ -42,7 +42,8 @@ public: NSStr_stringWithUTF8String, NSStr_stringWithCStringEncoding, NSStr_stringWithCString, - NSStr_initWithString + NSStr_initWithString, + NSStr_initWithUTF8String }; static const unsigned NumNSStringMethods = 5; @@ -100,8 +101,8 @@ public: NSDict_objectForKey, NSMutableDict_setObjectForKey }; - static const unsigned NumNSDictionaryMethods = 11; - + static const unsigned NumNSDictionaryMethods = 12; + /// \brief The Objective-C NSDictionary selectors. Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const; @@ -184,6 +185,9 @@ public: bool isObjCNSIntegerType(QualType T) const; /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. bool isObjCNSUIntegerType(QualType T) const; + /// \brief Returns one of NSIntegral typedef names if \param T is a typedef + /// of that name in objective-c. + StringRef GetNSIntegralKind(QualType T) const; private: bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const; diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index fc719bdc16c3..518f1232fe8f 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -22,6 +22,7 @@ namespace clang { class ASTContext; +class CXXRecordDecl; class NamespaceAliasDecl; class NamespaceDecl; class IdentifierInfo; @@ -45,7 +46,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode { /// \brief Enumeration describing enum StoredSpecifierKind { StoredIdentifier = 0, - StoredNamespaceOrAlias = 1, + StoredDecl = 1, StoredTypeSpec = 2, StoredTypeSpecWithTemplate = 3 }; @@ -83,7 +84,10 @@ public: /// stored as a Type*. TypeSpecWithTemplate, /// \brief The global specifier '::'. There is no stored value. - Global + Global, + /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + Super }; private: @@ -143,6 +147,11 @@ public: /// scope. static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); + /// \brief Returns the nested name specifier representing the __super scope + /// for the given CXXRecordDecl. + static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, + CXXRecordDecl *RD); + /// \brief Return the prefix of this nested name specifier. /// /// The prefix contains all of the parts of the nested name @@ -172,6 +181,10 @@ public: /// specifier. NamespaceAliasDecl *getAsNamespaceAlias() const; + /// \brief Retrieve the record declaration stored in this nested name + /// specifier. + CXXRecordDecl *getAsRecordDecl() const; + /// \brief Retrieve the type stored in this nested name specifier. const Type *getAsType() const { if (Prefix.getInt() == StoredTypeSpec || @@ -421,7 +434,22 @@ public: /// \brief Turn this (empty) nested-name-specifier into the global /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - + + /// \brief Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \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. /// diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 3345959653a6..0c3002c103e2 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -61,7 +61,7 @@ public: ConstStmtRange children() const { return const_cast<OMPClause *>(this)->children(); } - static bool classof(const OMPClause *T) { return true; } + static bool classof(const OMPClause *) { return true; } }; /// \brief This represents clauses with the list of variables like 'private', @@ -135,10 +135,10 @@ public: /// \brief Fetches list of all variables in the clause. ArrayRef<const Expr *> getVarRefs() const { - return ArrayRef<const Expr *>( + return llvm::makeArrayRef( reinterpret_cast<const Expr *const *>( reinterpret_cast<const char *>(this) + - llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<Expr *>())), + llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<const Expr *>())), NumVars); } }; @@ -770,6 +770,153 @@ public: StmtRange children() { return StmtRange(); } }; +/// \brief This represents 'read' clause in the '#pragma omp atomic' directive. +/// +/// \code +/// #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; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'write' clause in the '#pragma omp atomic' directive. +/// +/// \code +/// #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; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'update' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #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; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'capture' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #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; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'seq_cst' clause in the '#pragma omp atomic' +/// directive. +/// +/// \code +/// #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; + } + + StmtRange children() { return StmtRange(); } +}; + /// \brief This represents clause 'private' in the '#pragma omp ...' directives. /// /// \code @@ -779,6 +926,7 @@ public: /// with the variables 'a' and 'b'. /// class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> { + friend class OMPClauseReader; /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. @@ -800,6 +948,20 @@ class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> { SourceLocation(), SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param VL List of references. + void setPrivateCopies(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef<Expr *> getPrivateCopies() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + public: /// \brief Creates clause with a list of variables \a VL. /// @@ -808,10 +970,12 @@ public: /// \param LParenLoc Location of '('. /// \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); + SourceLocation EndLoc, ArrayRef<Expr *> VL, + ArrayRef<Expr *> PrivateVL); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -819,6 +983,21 @@ public: /// 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; + + 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()); + } + StmtRange children() { return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()), reinterpret_cast<Stmt **>(varlist_end())); @@ -839,6 +1018,8 @@ public: /// with the variables 'a' and 'b'. /// class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> { + friend class OMPClauseReader; + /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. @@ -859,6 +1040,33 @@ class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> { : OMPVarListClause<OMPFirstprivateClause>( OMPC_firstprivate, SourceLocation(), SourceLocation(), SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param VL List of references. + void setPrivateCopies(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef<Expr *> getPrivateCopies() { + return MutableArrayRef<Expr *>(varlist_end(), varlist_size()); + } + ArrayRef<const Expr *> getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + + /// \brief Sets the list of references to initializer variables for new + /// private variables. + /// \param VL List of references. + void setInits(ArrayRef<Expr *> VL); + + /// \brief Gets the list of references to initializer variables for new + /// private variables. + MutableArrayRef<Expr *> getInits() { + return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size()); + } + ArrayRef<const Expr *> getInits() const { + return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size()); + } public: /// \brief Creates clause with a list of variables \a VL. @@ -867,11 +1075,16 @@ public: /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - /// \param VL List of references to the variables. + /// \param VL List of references to the original variables. + /// \param PrivateVL List of references to private copies with initializers. + /// \param InitVL List of references to auto generated variables used for + /// initialization of a single array element. Used if firstprivate variable is + /// of array type. /// static OMPFirstprivateClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef<Expr *> VL); + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL, + ArrayRef<Expr *> InitVL); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -879,6 +1092,33 @@ public: /// 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; + + 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; + + inits_range inits() { + return inits_range(getInits().begin(), getInits().end()); + } + inits_const_range inits() const { + return inits_const_range(getInits().begin(), getInits().end()); + } + StmtRange children() { return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()), reinterpret_cast<Stmt **>(varlist_end())); @@ -1390,13 +1630,17 @@ public: } }; -/// \brief This represents pseudo clause 'flush' for the '#pragma omp flush' +/// \brief This represents implicit clause 'flush' for the '#pragma omp flush' /// directive. +/// This clause does not exist by itself, it can be only as a part of 'omp +/// flush' directive. This clause is introduced to keep the original structure +/// of \a OMPExecutableDirective class and its derivatives and to use the +/// existing infrastructure of clauses with the list of variables. /// /// \code /// #pragma omp flush(a,b) /// \endcode -/// In this example directive '#pragma omp flush' has pseudo clause 'flush' +/// In this example directive '#pragma omp flush' has implicit clause 'flush' /// with the variables 'a' and 'b'. /// class OMPFlushClause : public OMPVarListClause<OMPFlushClause> { @@ -1453,3 +1697,4 @@ public: } // end namespace clang #endif + diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index aba88d6c5419..e3f012667727 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_OPERATION_KINDS_H -#define LLVM_CLANG_AST_OPERATION_KINDS_H +#ifndef LLVM_CLANG_AST_OPERATIONKINDS_H +#define LLVM_CLANG_AST_OPERATIONKINDS_H namespace clang { diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index eece8510e9c4..8945c413d268 100644 --- a/include/clang/AST/ParentMap.h +++ b/include/clang/AST/ParentMap.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_PARENTMAP_H -#define LLVM_CLANG_PARENTMAP_H +#ifndef LLVM_CLANG_AST_PARENTMAP_H +#define LLVM_CLANG_AST_PARENTMAP_H namespace clang { class Stmt; diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 349f4c44a4e0..35ceabbd6b71 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H -#define LLVM_CLANG_AST_PRETTY_PRINTER_H +#ifndef LLVM_CLANG_AST_PRETTYPRINTER_H +#define LLVM_CLANG_AST_PRETTYPRINTER_H #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h index 8ba85c43f657..2e005ddbd027 100644 --- a/include/clang/AST/RawCommentList.h +++ b/include/clang/AST/RawCommentList.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_RAW_COMMENT_LIST_H -#define LLVM_CLANG_AST_RAW_COMMENT_LIST_H +#ifndef LLVM_CLANG_AST_RAWCOMMENTLIST_H +#define LLVM_CLANG_AST_RAWCOMMENTLIST_H #include "clang/Basic/CommentOptions.h" #include "clang/Basic/SourceManager.h" diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 4befb4506212..7b7799884a3d 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_LAYOUTINFO_H -#define LLVM_CLANG_AST_LAYOUTINFO_H +#ifndef LLVM_CLANG_AST_RECORDLAYOUT_H +#define LLVM_CLANG_AST_RECORDLAYOUT_H #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index ff46ffb94e70..a1d36180d737 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -429,6 +429,7 @@ private: bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + bool TraverseOMPLoopDirective(OMPLoopDirective *S); bool TraverseOMPClause(OMPClause *C); #define OPENMP_CLAUSE(Name, Class) bool Visit##Class(Class *C); #include "clang/Basic/OpenMPKinds.def" @@ -689,6 +690,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier( case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -713,6 +715,7 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -940,6 +943,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) @@ -1148,6 +1154,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) @@ -2144,21 +2153,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - if (S->hasExplicitParameters() || S->hasExplicitResultType()) { - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - if (S->hasExplicitParameters() && S->hasExplicitResultType()) { - // Visit the whole type. - TRY_TO(TraverseTypeLoc(TL)); - } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { - if (S->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { - TRY_TO(TraverseDecl(Proto.getParam(I))); - } - } else { - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); + + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else { + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getParam(I))); } + } else if (S->hasExplicitResultType()) { + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + } + + auto *T = Proto.getTypePtr(); + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); } TRY_TO(TraverseLambdaBody(S)); @@ -2259,6 +2276,7 @@ DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); }) DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {}) DEF_TRAVERSE_STMT(OpaqueValueExpr, {}) +DEF_TRAVERSE_STMT(TypoExpr, {}) DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {}) // These operators (all of them) do not need any action except @@ -2275,6 +2293,7 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {}) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {}) DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) +DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) // These literals (all of them) do not need any action. @@ -2301,6 +2320,12 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPExecutableDirective( return true; } +template <typename Derived> +bool +RecursiveASTVisitor<Derived>::TraverseOMPLoopDirective(OMPLoopDirective *S) { + return TraverseOMPExecutableDirective(S); +} + DEF_TRAVERSE_STMT(OMPParallelDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2310,6 +2335,9 @@ DEF_TRAVERSE_STMT(OMPSimdDirective, DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPSectionsDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2330,6 +2358,9 @@ DEF_TRAVERSE_STMT(OMPCriticalDirective, { DEF_TRAVERSE_STMT(OMPParallelForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPParallelForSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPParallelSectionsDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -2348,6 +2379,18 @@ DEF_TRAVERSE_STMT(OMPTaskwaitDirective, DEF_TRAVERSE_STMT(OMPFlushDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPOrderedDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPAtomicDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTargetDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTeamsDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { @@ -2437,6 +2480,31 @@ RecursiveASTVisitor<Derived>::VisitOMPMergeableClause(OMPMergeableClause *) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPReadClause(OMPReadClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPWriteClause(OMPWriteClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) { + return true; +} + +template <typename Derived> template <typename T> bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { @@ -2448,6 +2516,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } @@ -2455,6 +2526,12 @@ template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause( OMPFirstprivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } + for (auto *E : C->inits()) { + TRY_TO(TraverseStmt(E)); + } return true; } diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index fb94097cfac7..eb6836f88699 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -212,7 +212,7 @@ protected: unsigned HasTemplateKWAndArgsInfo : 1; unsigned HasFoundDecl : 1; unsigned HadMultipleCandidates : 1; - unsigned RefersToEnclosingLocal : 1; + unsigned RefersToEnclosingVariableOrCapture : 1; }; class CastExprBitfields { @@ -393,6 +393,10 @@ public: /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes. Stmt *IgnoreImplicit(); + /// \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 *stripLabelLikeStatements() const; Stmt *stripLabelLikeStatements() { return const_cast<Stmt*>( @@ -548,14 +552,17 @@ public: /// class CompoundStmt : public Stmt { Stmt** Body; - SourceLocation LBracLoc, RBracLoc; + SourceLocation LBraceLoc, RBraceLoc; + + friend class ASTStmtReader; + 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), LBracLoc(Loc), RBracLoc(Loc) { + : Stmt(CompoundStmtClass), Body(nullptr), LBraceLoc(Loc), RBraceLoc(Loc) { CompoundStmtBits.NumStmts = 0; } @@ -614,13 +621,11 @@ public: return const_reverse_body_iterator(body_begin()); } - SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; } + SourceLocation getLocStart() const LLVM_READONLY { return LBraceLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RBraceLoc; } - SourceLocation getLBracLoc() const { return LBracLoc; } - void setLBracLoc(SourceLocation L) { LBracLoc = L; } - SourceLocation getRBracLoc() const { return RBracLoc; } - void setRBracLoc(SourceLocation L) { RBracLoc = L; } + SourceLocation getLBracLoc() const { return LBraceLoc; } + SourceLocation getRBracLoc() const { return RBraceLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundStmtClass; @@ -846,7 +851,7 @@ public: SourceLocation getAttrLoc() const { return AttrLoc; } ArrayRef<const Attr*> getAttrs() const { - return ArrayRef<const Attr*>(getAttrArrayPtr(), NumAttrs); + return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs); } Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } @@ -1010,7 +1015,7 @@ public: SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; } SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY]->getLocEnd(); + return SubExprs[BODY] ? SubExprs[BODY]->getLocEnd() : SubExprs[COND]->getLocEnd(); } // Iterators @@ -1580,18 +1585,21 @@ public: Kind MyKind; std::string Str; unsigned OperandNo; + + // Source range for operand references. + CharSourceRange Range; public: AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} - AsmStringPiece(unsigned OpNo, char Modifier) - : MyKind(Operand), Str(), OperandNo(OpNo) { - Str += Modifier; + AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation Begin, + SourceLocation End) + : MyKind(Operand), Str(S), OperandNo(OpNo), + Range(CharSourceRange::getCharRange(Begin, End)) { } bool isString() const { return MyKind == String; } bool isOperand() const { return MyKind == Operand; } const std::string &getString() const { - assert(isString()); return Str; } @@ -1600,12 +1608,14 @@ public: return OperandNo; } + CharSourceRange getRange() const { + assert(isOperand() && "Range is currently used only for Operands."); + return Range; + } + /// getModifier - Get the modifier for this operand, if present. This /// returns '\0' if there was no modifier. - char getModifier() const { - assert(isOperand()); - return Str[0]; - } + char getModifier() const; }; /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing @@ -1780,14 +1790,14 @@ public: //===--- Other ---===// ArrayRef<StringRef> getAllConstraints() const { - return ArrayRef<StringRef>(Constraints, NumInputs + NumOutputs); + return llvm::makeArrayRef(Constraints, NumInputs + NumOutputs); } ArrayRef<StringRef> getClobbers() const { - return ArrayRef<StringRef>(Clobbers, NumClobbers); + return llvm::makeArrayRef(Clobbers, NumClobbers); } ArrayRef<Expr*> getAllExprs() const { - return ArrayRef<Expr*>(reinterpret_cast<Expr**>(Exprs), - NumInputs + NumOutputs); + return llvm::makeArrayRef(reinterpret_cast<Expr**>(Exprs), + NumInputs + NumOutputs); } StringRef getClobber(unsigned i) const { return getClobbers()[i]; } @@ -1892,24 +1902,22 @@ class SEHTryStmt : public Stmt { bool IsCXXTry; SourceLocation TryLoc; Stmt *Children[2]; - int HandlerIndex; - int HandlerParentIndex; enum { TRY = 0, HANDLER = 1 }; SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try' - SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler, - int HandlerIndex, int HandlerParentIndex); + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler); friend class ASTReader; friend class ASTStmtReader; explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } public: - static SEHTryStmt *Create(const ASTContext &C, bool isCXXTry, + static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry, SourceLocation TryLoc, Stmt *TryBlock, - Stmt *Handler, int HandlerIndex, - int HandlerParentIndex); + Stmt *Handler); SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } @@ -1936,9 +1944,6 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == SEHTryStmtClass; } - - int getHandlerIndex() const { return HandlerIndex; } - int getHandlerParentIndex() const { return HandlerParentIndex; } }; /// Represents a __leave statement. @@ -1977,15 +1982,18 @@ public: /// @endcode class CapturedStmt : public Stmt { public: - /// \brief The different capture forms: by 'this' or by reference, etc. + /// \brief The different capture forms: by 'this', by reference, capture for + /// variable-length array type etc. enum VariableCaptureKind { VCK_This, - VCK_ByRef + VCK_ByRef, + VCK_VLAType, }; - /// \brief Describes the capture of either a variable or 'this'. + /// \brief Describes the capture of either a variable, or 'this', or + /// variable-length array type. class Capture { - llvm::PointerIntPair<VarDecl *, 1, VariableCaptureKind> VarAndKind; + llvm::PointerIntPair<VarDecl *, 2, VariableCaptureKind> VarAndKind; SourceLocation Loc; public: @@ -2007,6 +2015,10 @@ public: case VCK_ByRef: assert(Var && "capturing by reference must have a variable!"); break; + case VCK_VLAType: + assert(!Var && + "Variable-length array type capture cannot have a variable!"); + break; } } @@ -2021,13 +2033,20 @@ public: bool capturesThis() const { return getCaptureKind() == VCK_This; } /// \brief Determine whether this capture handles a variable. - bool capturesVariable() const { return getCaptureKind() != VCK_This; } + bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; } + + /// \brief Determine whether this capture handles a variable-length array + /// type. + bool capturesVariableArrayType() const { + return getCaptureKind() == VCK_VLAType; + } /// \brief Retrieve the declaration of the variable being captured. /// - /// This operation is only valid if this capture does not capture 'this'. + /// This operation is only valid if this capture captures a variable. VarDecl *getCapturedVar() const { - assert(!capturesThis() && "No variable available for 'this' capture"); + assert(capturesVariable() && + "No variable available for 'this' or VAT capture"); return VarAndKind.getPointer(); } friend class ASTStmtReader; diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h index a3e9e1e093f6..ab636a5ddc48 100644 --- a/include/clang/AST/StmtGraphTraits.h +++ b/include/clang/AST/StmtGraphTraits.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H -#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H +#ifndef LLVM_CLANG_AST_STMTGRAPHTRAITS_H +#define LLVM_CLANG_AST_STMTGRAPHTRAITS_H #include "clang/AST/Stmt.h" #include "llvm/ADT/DepthFirstIterator.h" diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index 18c55166beba..6ffe74f2d7fb 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_STMT_ITR_H -#define LLVM_CLANG_AST_STMT_ITR_H +#ifndef LLVM_CLANG_AST_STMTITERATOR_H +#define LLVM_CLANG_AST_STMTITERATOR_H #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index db02afe0568b..aed7691cf73a 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -128,6 +128,13 @@ public: operator bool() { return Current != End; } }; + /// \brief Gets a single clause of the specified kind \a K associated with the + /// current directive iff there is only one clause of this kind (and assertion + /// is fired if there is more than one clause is associated with the + /// directive). Returns nullptr if no clause of kind \a K is associated with + /// the directive. + const OMPClause *getSingleClause(OpenMPClauseKind K) const; + /// \brief Returns starting location of directive kind. SourceLocation getLocStart() const { return StartLoc; } /// \brief Returns ending location of directive. @@ -238,6 +245,353 @@ public: } }; +/// \brief This is a common base class for loop directives ('omp simd', 'omp +/// for', 'omp for simd' etc.). It is responsible for the loop code generation. +/// +class OMPLoopDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Number of collapsed loops as specified by 'collapse' clause. + unsigned CollapsedNum; + + /// \brief Offsets to the stored exprs. + /// This enumeration contains offsets to all the pointers to children + /// expressions stored in OMPLoopDirective. + /// The first 9 children are nesessary for all the loop directives, and + /// the next 7 are specific to the worksharing ones. + /// After the fixed children, three arrays of length CollapsedNum are + /// allocated: loop counters, their updates and final values. + /// + enum { + AssociatedStmtOffset = 0, + IterationVariableOffset = 1, + LastIterationOffset = 2, + CalcLastIterationOffset = 3, + PreConditionOffset = 4, + CondOffset = 5, + SeparatedCondOffset = 6, + InitOffset = 7, + IncOffset = 8, + // The '...End' enumerators do not correspond to child expressions - they + // specify the offset to the end (and start of the following counters/ + // updates/finals arrays). + DefaultEnd = 9, + // The following 7 exprs are used by worksharing loops only. + IsLastIterVariableOffset = 9, + LowerBoundVariableOffset = 10, + UpperBoundVariableOffset = 11, + StrideVariableOffset = 12, + EnsureUpperBoundOffset = 13, + NextLowerBoundOffset = 14, + NextUpperBoundOffset = 15, + // Offset to the end (and start of the following counters/updates/finals + // arrays) for worksharing loop directives. + WorksharingEnd = 16, + }; + + /// \brief Get the counters storage. + MutableArrayRef<Expr *> getCounters() { + Expr **Storage = reinterpret_cast<Expr **>( + &(*(std::next(child_begin(), getArraysOffset(getDirectiveKind()))))); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the updates storage. + MutableArrayRef<Expr *> getUpdates() { + Expr **Storage = reinterpret_cast<Expr **>( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + + /// \brief Get the final counter updates storage. + MutableArrayRef<Expr *> getFinals() { + Expr **Storage = reinterpret_cast<Expr **>( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 2 * CollapsedNum)); + return MutableArrayRef<Expr *>(Storage, CollapsedNum); + } + +protected: + /// \brief Build instance of loop directive of class \a Kind. + /// + /// \param SC Statement class. + /// \param Kind Kind of OpenMP directive. + /// \param StartLoc Starting location of the directive (directive keyword). + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed loops from 'collapse' clause. + /// \param NumClauses Number of clauses. + /// \param NumSpecialChildren Number of additional directive-specific stmts. + /// + template <typename T> + OMPLoopDirective(const T *That, StmtClass SC, OpenMPDirectiveKind Kind, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses, + unsigned NumSpecialChildren = 0) + : OMPExecutableDirective(That, SC, Kind, StartLoc, EndLoc, NumClauses, + numLoopChildren(CollapsedNum, Kind) + + NumSpecialChildren), + CollapsedNum(CollapsedNum) {} + + /// \brief Offset to the start of children expression arrays. + static unsigned getArraysOffset(OpenMPDirectiveKind Kind) { + return isOpenMPWorksharingDirective(Kind) ? WorksharingEnd + : DefaultEnd; + } + + /// \brief Children number. + static unsigned numLoopChildren(unsigned CollapsedNum, + OpenMPDirectiveKind Kind) { + return getArraysOffset(Kind) + + 3 * CollapsedNum; // Counters, Updates and Finals + } + + void setIterationVariable(Expr *IV) { + *std::next(child_begin(), IterationVariableOffset) = IV; + } + void setLastIteration(Expr *LI) { + *std::next(child_begin(), LastIterationOffset) = LI; + } + void setCalcLastIteration(Expr *CLI) { + *std::next(child_begin(), CalcLastIterationOffset) = CLI; + } + void setPreCond(Expr *PC) { + *std::next(child_begin(), PreConditionOffset) = PC; + } + void setCond(Expr *Cond, Expr *SeparatedCond) { + *std::next(child_begin(), CondOffset) = Cond; + *std::next(child_begin(), SeparatedCondOffset) = SeparatedCond; + } + void setInit(Expr *Init) { *std::next(child_begin(), InitOffset) = Init; } + void setInc(Expr *Inc) { *std::next(child_begin(), IncOffset) = Inc; } + void setIsLastIterVariable(Expr *IL) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), IsLastIterVariableOffset) = IL; + } + void setLowerBoundVariable(Expr *LB) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), LowerBoundVariableOffset) = LB; + } + void setUpperBoundVariable(Expr *UB) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), UpperBoundVariableOffset) = UB; + } + void setStrideVariable(Expr *ST) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), StrideVariableOffset) = ST; + } + void setEnsureUpperBound(Expr *EUB) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), EnsureUpperBoundOffset) = EUB; + } + void setNextLowerBound(Expr *NLB) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), NextLowerBoundOffset) = NLB; + } + void setNextUpperBound(Expr *NUB) { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + *std::next(child_begin(), NextUpperBoundOffset) = NUB; + } + void setCounters(ArrayRef<Expr *> A); + void setUpdates(ArrayRef<Expr *> A); + void setFinals(ArrayRef<Expr *> A); + +public: + /// \brief The expressions built for the OpenMP loop CodeGen for the + /// whole collapsed loop nest. + struct HelperExprs { + /// \brief Loop iteration variable. + Expr *IterationVarRef; + /// \brief Loop last iteration number. + Expr *LastIteration; + /// \brief Calculation of last iteration. + Expr *CalcLastIteration; + /// \brief Loop pre-condition. + Expr *PreCond; + /// \brief Loop condition. + Expr *Cond; + /// \brief A condition with 1 iteration separated. + Expr *SeparatedCond; + /// \brief Loop iteration variable init. + Expr *Init; + /// \brief Loop increment. + Expr *Inc; + /// \brief IsLastIteration - local flag variable passed to runtime. + Expr *IL; + /// \brief LowerBound - local variable passed to runtime. + Expr *LB; + /// \brief UpperBound - local variable passed to runtime. + Expr *UB; + /// \brief Stride - local variable passed to runtime. + Expr *ST; + /// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations). + Expr *EUB; + /// \brief Update of LowerBound for statically sheduled 'omp for' loops. + Expr *NLB; + /// \brief Update of UpperBound for statically sheduled 'omp for' loops. + Expr *NUB; + /// \brief Counters Loop counters. + SmallVector<Expr *, 4> Counters; + /// \brief Expressions for loop counters update for CodeGen. + SmallVector<Expr *, 4> Updates; + /// \brief Final loop counter values for GodeGen. + SmallVector<Expr *, 4> Finals; + + /// \brief Check if all the expressions are built (does not check the + /// worksharing ones). + bool builtAll() { + return IterationVarRef != nullptr && LastIteration != nullptr && + PreCond != nullptr && Cond != nullptr && + SeparatedCond != nullptr && Init != nullptr && Inc != nullptr; + } + + /// \brief Initialize all the fields to null. + /// \param Size Number of elements in the counters/finals/updates arrays. + void clear(unsigned Size) { + IterationVarRef = nullptr; + LastIteration = nullptr; + CalcLastIteration = nullptr; + PreCond = nullptr; + Cond = nullptr; + SeparatedCond = nullptr; + Init = nullptr; + Inc = nullptr; + IL = nullptr; + LB = nullptr; + UB = nullptr; + ST = nullptr; + EUB = nullptr; + NLB = nullptr; + NUB = nullptr; + Counters.resize(Size); + Updates.resize(Size); + Finals.resize(Size); + for (unsigned i = 0; i < Size; ++i) { + Counters[i] = nullptr; + Updates[i] = nullptr; + Finals[i] = nullptr; + } + } + }; + + /// \brief Get number of collapsed loops. + unsigned getCollapsedNumber() const { return CollapsedNum; } + + Expr *getIterationVariable() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), IterationVariableOffset))); + } + Expr *getLastIteration() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), LastIterationOffset))); + } + Expr *getCalcLastIteration() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CalcLastIterationOffset))); + } + Expr *getPreCond() const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), PreConditionOffset))); + } + Expr *getCond(bool SeparateIter) const { + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), + (SeparateIter ? SeparatedCondOffset : CondOffset)))); + } + Expr *getInit() const { + return const_cast<Expr *>( + reinterpret_cast<const Expr *>(*std::next(child_begin(), InitOffset))); + } + Expr *getInc() const { + return const_cast<Expr *>( + reinterpret_cast<const Expr *>(*std::next(child_begin(), IncOffset))); + } + Expr *getIsLastIterVariable() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), IsLastIterVariableOffset))); + } + Expr *getLowerBoundVariable() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), LowerBoundVariableOffset))); + } + Expr *getUpperBoundVariable() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), UpperBoundVariableOffset))); + } + Expr *getStrideVariable() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), StrideVariableOffset))); + } + Expr *getEnsureUpperBound() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), EnsureUpperBoundOffset))); + } + Expr *getNextLowerBound() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), NextLowerBoundOffset))); + } + Expr *getNextUpperBound() const { + assert(isOpenMPWorksharingDirective(getDirectiveKind()) && + "expected worksharing loop directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), NextUpperBoundOffset))); + } + const Stmt *getBody() const { + // This relies on the loop form is already checked by Sema. + Stmt *Body = getAssociatedStmt()->IgnoreContainers(true); + Body = cast<ForStmt>(Body)->getBody(); + for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { + Body = Body->IgnoreContainers(); + Body = cast<ForStmt>(Body)->getBody(); + } + return Body; + } + + ArrayRef<Expr *> counters() { return getCounters(); } + + ArrayRef<Expr *> counters() const { + return const_cast<OMPLoopDirective *>(this)->getCounters(); + } + + ArrayRef<Expr *> updates() { return getUpdates(); } + + ArrayRef<Expr *> updates() const { + return const_cast<OMPLoopDirective *>(this)->getUpdates(); + } + + ArrayRef<Expr *> finals() { return getFinals(); } + + ArrayRef<Expr *> finals() const { + return const_cast<OMPLoopDirective *>(this)->getFinals(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSimdDirectiveClass || + T->getStmtClass() == OMPForDirectiveClass || + T->getStmtClass() == OMPForSimdDirectiveClass || + T->getStmtClass() == OMPParallelForDirectiveClass || + T->getStmtClass() == OMPParallelForSimdDirectiveClass; + } +}; + /// \brief This represents '#pragma omp simd' directive. /// /// \code @@ -247,10 +601,8 @@ public: /// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and /// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. /// -class OMPSimdDirective : public OMPExecutableDirective { +class OMPSimdDirective : public OMPLoopDirective { friend class ASTStmtReader; - /// \brief Number of collapsed loops as specified by 'collapse' clause. - unsigned CollapsedNum; /// \brief Build directive with the given start and end location. /// /// \param StartLoc Starting location of the directive kind. @@ -260,9 +612,8 @@ class OMPSimdDirective : public OMPExecutableDirective { /// OMPSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd, StartLoc, - EndLoc, NumClauses, 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd, StartLoc, + EndLoc, CollapsedNum, NumClauses) {} /// \brief Build an empty directive. /// @@ -270,10 +621,9 @@ class OMPSimdDirective : public OMPExecutableDirective { /// \param NumClauses Number of clauses. /// explicit OMPSimdDirective(unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd, - SourceLocation(), SourceLocation(), NumClauses, - 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPSimdDirectiveClass, OMPD_simd, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -284,11 +634,13 @@ public: /// \param CollapsedNum Number of collapsed loops. /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. /// static OMPSimdDirective *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt); + Stmt *AssociatedStmt, + const HelperExprs &Exprs); /// \brief Creates an empty directive with the place /// for \a NumClauses clauses. @@ -300,8 +652,6 @@ public: static OMPSimdDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, EmptyShell); - unsigned getCollapsedNumber() const { return CollapsedNum; } - static bool classof(const Stmt *T) { return T->getStmtClass() == OMPSimdDirectiveClass; } @@ -316,10 +666,8 @@ public: /// variables 'a' and 'b' and 'reduction' with operator '+' and variables 'c' /// and 'd'. /// -class OMPForDirective : public OMPExecutableDirective { +class OMPForDirective : public OMPLoopDirective { friend class ASTStmtReader; - /// \brief Number of collapsed loops as specified by 'collapse' clause. - unsigned CollapsedNum; /// \brief Build directive with the given start and end location. /// /// \param StartLoc Starting location of the directive kind. @@ -329,9 +677,8 @@ class OMPForDirective : public OMPExecutableDirective { /// OMPForDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPForDirectiveClass, OMPD_for, StartLoc, - EndLoc, NumClauses, 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, StartLoc, EndLoc, + CollapsedNum, NumClauses) {} /// \brief Build an empty directive. /// @@ -339,10 +686,8 @@ class OMPForDirective : public OMPExecutableDirective { /// \param NumClauses Number of clauses. /// explicit OMPForDirective(unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPForDirectiveClass, OMPD_for, - SourceLocation(), SourceLocation(), NumClauses, - 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPForDirectiveClass, OMPD_for, SourceLocation(), + SourceLocation(), CollapsedNum, NumClauses) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -353,11 +698,13 @@ public: /// \param CollapsedNum Number of collapsed loops. /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. /// static OMPForDirective *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt); + Stmt *AssociatedStmt, + const HelperExprs &Exprs); /// \brief Creates an empty directive with the place /// for \a NumClauses clauses. @@ -369,13 +716,76 @@ public: static OMPForDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, EmptyShell); - unsigned getCollapsedNumber() const { return CollapsedNum; } - static bool classof(const Stmt *T) { return T->getStmtClass() == OMPForDirectiveClass; } }; +/// \brief This represents '#pragma omp for simd' directive. +/// +/// \code +/// #pragma omp for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp for simd' has clauses 'private' +/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and +/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPForSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd, + StartLoc, EndLoc, CollapsedNum, NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPForSimdDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPForSimdDirectiveClass, OMPD_for_simd, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPForSimdDirectiveClass; + } +}; + /// \brief This represents '#pragma omp sections' directive. /// /// \code @@ -657,10 +1067,8 @@ public: /// with the variables 'a' and 'b' and 'reduction' with operator '+' and /// variables 'c' and 'd'. /// -class OMPParallelForDirective : public OMPExecutableDirective { +class OMPParallelForDirective : public OMPLoopDirective { friend class ASTStmtReader; - /// \brief Number of collapsed loops as specified by 'collapse' clause. - unsigned CollapsedNum; /// \brief Build directive with the given start and end location. /// /// \param StartLoc Starting location of the directive kind. @@ -670,10 +1078,8 @@ class OMPParallelForDirective : public OMPExecutableDirective { /// OMPParallelForDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPParallelForDirectiveClass, - OMPD_parallel_for, StartLoc, EndLoc, NumClauses, - 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for, + StartLoc, EndLoc, CollapsedNum, NumClauses) {} /// \brief Build an empty directive. /// @@ -681,10 +1087,9 @@ class OMPParallelForDirective : public OMPExecutableDirective { /// \param NumClauses Number of clauses. /// explicit OMPParallelForDirective(unsigned CollapsedNum, unsigned NumClauses) - : OMPExecutableDirective(this, OMPParallelForDirectiveClass, - OMPD_parallel_for, SourceLocation(), - SourceLocation(), NumClauses, 1), - CollapsedNum(CollapsedNum) {} + : OMPLoopDirective(this, OMPParallelForDirectiveClass, OMPD_parallel_for, + SourceLocation(), SourceLocation(), CollapsedNum, + NumClauses) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -695,11 +1100,12 @@ public: /// \param CollapsedNum Number of collapsed loops. /// \param Clauses List of clauses. /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. /// static OMPParallelForDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt); + Stmt *AssociatedStmt, const HelperExprs &Exprs); /// \brief Creates an empty directive with the place /// for \a NumClauses clauses. @@ -713,13 +1119,80 @@ public: unsigned CollapsedNum, EmptyShell); - unsigned getCollapsedNumber() const { return CollapsedNum; } - static bool classof(const Stmt *T) { return T->getStmtClass() == OMPParallelForDirectiveClass; } }; +/// \brief This represents '#pragma omp parallel for simd' directive. +/// +/// \code +/// #pragma omp parallel for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp parallel for simd' has clauses +/// 'private' with the variables 'a' and 'b', 'linear' with variables 'i', 'j' +/// and linear step 's', 'reduction' with operator '+' and variables 'c' and +/// 'd'. +/// +class OMPParallelForSimdDirective : public OMPLoopDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPParallelForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass, + OMPD_parallel_for_simd, StartLoc, EndLoc, CollapsedNum, + NumClauses) {} + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPParallelForSimdDirective(unsigned CollapsedNum, + unsigned NumClauses) + : OMPLoopDirective(this, OMPParallelForSimdDirectiveClass, + OMPD_parallel_for_simd, SourceLocation(), + SourceLocation(), CollapsedNum, NumClauses) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPParallelForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPParallelForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelForSimdDirectiveClass; + } +}; + /// \brief This represents '#pragma omp parallel sections' directive. /// /// \code @@ -1028,6 +1501,253 @@ public: } }; +/// \brief This represents '#pragma omp ordered' directive. +/// +/// \code +/// #pragma omp ordered +/// \endcode +/// +class OMPOrderedDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPOrderedDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered, + StartLoc, EndLoc, 0, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPOrderedDirective() + : OMPExecutableDirective(this, OMPOrderedDirectiveClass, OMPD_ordered, + SourceLocation(), SourceLocation(), 0, 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPOrderedDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPOrderedDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPOrderedDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic capture +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'capture'. +/// +class OMPAtomicDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + StartLoc, EndLoc, NumClauses, 4) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPAtomicDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic, + SourceLocation(), SourceLocation(), NumClauses, + 4) {} + + /// \brief Set 'x' part of the associated expression/statement. + void setX(Expr *X) { *std::next(child_begin()) = X; } + /// \brief Set 'v' part of the associated expression/statement. + void setV(Expr *V) { *std::next(child_begin(), 2) = V; } + /// \brief Set 'expr' part of the associated expression/statement. + void setExpr(Expr *E) { *std::next(child_begin(), 3) = E; } + +public: + /// \brief Creates directive with a list of \a Clauses and 'x', 'v' and 'expr' + /// parts of the atomic construct (see Section 2.12.6, atomic Construct, for + /// detailed description of 'x', 'v' and 'expr'). + /// + /// \param C AST context. + /// \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. + /// \param X 'x' part of the associated expression/statement. + /// \param V 'v' part of the associated expression/statement. + /// \param E 'expr' part of the associated expression/statement. + /// + static OMPAtomicDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V, + Expr *E); + + /// \brief Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPAtomicDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// \brief Get 'x' part of the associated expression/statement. + Expr *getX() { return cast_or_null<Expr>(*std::next(child_begin())); } + const Expr *getX() const { + return cast_or_null<Expr>(*std::next(child_begin())); + } + /// \brief Get 'v' part of the associated expression/statement. + Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 2)); } + const Expr *getV() const { + return cast_or_null<Expr>(*std::next(child_begin(), 2)); + } + /// \brief Get 'expr' part of the associated expression/statement. + Expr *getExpr() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); } + const Expr *getExpr() const { + return cast_or_null<Expr>(*std::next(child_begin(), 3)); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPAtomicDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp target' directive. +/// +/// \code +/// #pragma omp target if(a) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'if' with +/// condition 'a'. +/// +class OMPTargetDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPTargetDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTargetDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTargetDirectiveClass, OMPD_target, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \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 OMPTargetDirective * + 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. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPTargetDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp teams' directive. +/// +/// \code +/// #pragma omp teams if(a) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'if' with +/// condition 'a'. +/// +class OMPTeamsDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param NumClauses Number of clauses. + /// + OMPTeamsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses) + : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams, + StartLoc, EndLoc, NumClauses, 1) {} + + /// \brief Build an empty directive. + /// + /// \param NumClauses Number of clauses. + /// + explicit OMPTeamsDirective(unsigned NumClauses) + : OMPExecutableDirective(this, OMPTeamsDirectiveClass, OMPD_teams, + SourceLocation(), SourceLocation(), NumClauses, + 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \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 OMPTeamsDirective *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. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPTeamsDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTeamsDirectiveClass; + } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 1026a7807a60..80b68bc0569b 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -18,8 +18,8 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -76,7 +76,7 @@ private: struct DA { unsigned Kind; - bool ForRefParam; + void *QT; ValueDecl *D; }; struct I { @@ -132,11 +132,11 @@ public: /// \brief Construct a template argument that refers to a /// declaration, which is either an external declaration or a /// template declaration. - TemplateArgument(ValueDecl *D, bool ForRefParam) { + TemplateArgument(ValueDecl *D, QualType QT) { assert(D && "Expected decl"); DeclArg.Kind = Declaration; + DeclArg.QT = QT.getAsOpaquePtr(); DeclArg.D = D; - DeclArg.ForRefParam = ForRefParam; } /// \brief Construct an integral constant template argument. The memory to @@ -249,11 +249,9 @@ public: return DeclArg.D; } - /// \brief Retrieve whether a declaration is binding to a - /// reference parameter in a declaration non-type template argument. - bool isDeclForReferenceParam() const { + QualType getParamTypeForDecl() const { assert(getKind() == Declaration && "Unexpected kind"); - return DeclArg.ForRefParam; + return QualType::getFromOpaquePtr(DeclArg.QT); } /// \brief Retrieve the type for null non-type template argument. @@ -344,7 +342,7 @@ public: /// \brief Return the array of arguments in this template argument pack. ArrayRef<TemplateArgument> getPackAsArray() const { assert(getKind() == Pack); - return ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs); + return llvm::makeArrayRef(Args.Args, Args.NumArgs); } /// \brief Determines whether two template arguments are superficially the diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 09862e4fb7f7..1bda01fee8ad 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -16,6 +16,7 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" @@ -25,11 +26,11 @@ #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/ErrorHandling.h" namespace clang { @@ -400,21 +401,36 @@ public: Mask |= qs.Mask; } + /// \brief Returns true if this address space is a superset of the other one. + /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of + /// overlapping address spaces. + /// CL1.1 or CL1.2: + /// every address space is a superset of itself. + /// CL2.0 adds: + /// __generic is a superset of any address space except for __constant. + bool isAddressSpaceSupersetOf(Qualifiers other) const { + return + // Address spaces must match exactly. + getAddressSpace() == other.getAddressSpace() || + // Otherwise in OpenCLC v2.0 s6.5.5: every address space except + // for __constant can be used as __generic. + (getAddressSpace() == LangAS::opencl_generic && + other.getAddressSpace() != LangAS::opencl_constant); + } + /// \brief Determines if these qualifiers compatibly include another set. /// Generally this answers the question of whether an object with the other /// qualifiers can be safely used as an object with these qualifiers. bool compatiblyIncludes(Qualifiers other) const { - return - // Address spaces must match exactly. - getAddressSpace() == other.getAddressSpace() && - // ObjC GC qualifiers can match, be added, or be removed, but can't be - // changed. - (getObjCGCAttr() == other.getObjCGCAttr() || - !hasObjCGCAttr() || !other.hasObjCGCAttr()) && - // ObjC lifetime qualifiers must match exactly. - getObjCLifetime() == other.getObjCLifetime() && - // CVR qualifiers may subset. - (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); + return isAddressSpaceSupersetOf(other) && + // ObjC GC qualifiers can match, be added, or be removed, but can't + // be changed. + (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || + !other.hasObjCGCAttr()) && + // ObjC lifetime qualifiers must match exactly. + getObjCLifetime() == other.getObjCLifetime() && + // CVR qualifiers may subset. + (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); } /// \brief Determines if these qualifiers compatibly include another set of @@ -1245,6 +1261,7 @@ protected: class FunctionTypeBitfields { friend class FunctionType; + friend class FunctionProtoType; unsigned : NumTypeBits; @@ -1259,6 +1276,11 @@ protected: /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. unsigned TypeQuals : 3; + + /// \brief The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; }; class ObjCObjectTypeBitfields { @@ -1685,6 +1707,11 @@ public: /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; + /// \brief Retrieves the TagDecl that this type refers to, either + /// because the type is a TagType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + TagDecl *getAsTagDecl() const; + /// If this is a pointer or reference to a RecordType, return the /// CXXRecordDecl that that type refers to. /// @@ -1982,6 +2009,22 @@ public: QualType getPointeeType() const { return PointeeType; } + /// \brief Returns true if address spaces of pointers overlap. + /// OpenCL v2.0 defines conversion rules for pointers to different + /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping + /// address spaces. + /// CL1.1 or CL1.2: + /// address spaces overlap iff they are they same. + /// CL2.0 adds: + /// __generic overlaps with any address space except for __constant. + bool isAddressSpaceOverlapping(const PointerType &other) const { + Qualifiers thisQuals = PointeeType.getQualifiers(); + Qualifiers otherQuals = other.getPointeeType().getQualifiers(); + // Address spaces overlap if at least one of them is a superset of another + return thisQuals.isAddressSpaceSupersetOf(otherQuals) || + otherQuals.isAddressSpaceSupersetOf(thisQuals); + } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2765,7 +2808,7 @@ class FunctionType : public Type { protected: FunctionType(TypeClass tc, QualType res, - unsigned typeQuals, QualType Canonical, bool Dependent, + QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) @@ -2773,7 +2816,6 @@ protected: ContainsUnexpandedParameterPack), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; - FunctionTypeBits.TypeQuals = typeQuals; } unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } @@ -2810,7 +2852,7 @@ public: /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) - : FunctionType(FunctionNoProto, Result, 0, Canonical, + : FunctionType(FunctionNoProto, Result, Canonical, /*Dependent=*/false, /*InstantiationDependent=*/false, Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} @@ -2844,33 +2886,51 @@ public: /// type. class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { 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; + /// Explicitly-specified list of exception types. + ArrayRef<QualType> Exceptions; + /// Noexcept expression, if this is EST_ComputedNoexcept. + Expr *NoexceptExpr; + /// The function whose exception specification this is, for + /// EST_Unevaluated and EST_Uninstantiated. + FunctionDecl *SourceDecl; + /// The function template whose exception specification this is instantiated + /// from, for EST_Uninstantiated. + FunctionDecl *SourceTemplate; + }; + /// ExtProtoInfo - Extra information about a function prototype. struct ExtProtoInfo { ExtProtoInfo() : Variadic(false), HasTrailingReturn(false), TypeQuals(0), - ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0), - Exceptions(nullptr), NoexceptExpr(nullptr), - ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr), - ConsumedParameters(nullptr) {} + RefQualifier(RQ_None), ConsumedParameters(nullptr) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0), - ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0), - Exceptions(nullptr), NoexceptExpr(nullptr), - ExceptionSpecDecl(nullptr), ExceptionSpecTemplate(nullptr), - ConsumedParameters(nullptr) {} + RefQualifier(RQ_None), ConsumedParameters(nullptr) {} + + 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; - ExceptionSpecificationType ExceptionSpecType; RefQualifierKind RefQualifier; - unsigned NumExceptions; - const QualType *Exceptions; - Expr *NoexceptExpr; - FunctionDecl *ExceptionSpecDecl; - FunctionDecl *ExceptionSpecTemplate; + ExceptionSpecInfo ExceptionSpec; const bool *ConsumedParameters; }; @@ -2896,7 +2956,7 @@ private: unsigned NumExceptions : 9; /// ExceptionSpecType - The type of exception specification this function has. - unsigned ExceptionSpecType : 3; + unsigned ExceptionSpecType : 4; /// HasAnyConsumedParams - Whether this function has any consumed parameters. unsigned HasAnyConsumedParams : 1; @@ -2907,11 +2967,6 @@ private: /// HasTrailingReturn - Whether this function has a trailing return type. unsigned HasTrailingReturn : 1; - /// \brief The ref-qualifier associated with a \c FunctionProtoType. - /// - /// This is a value of type \c RefQualifierKind. - unsigned RefQualifier : 2; - // ParamInfo - There is an variable size array after the class in memory that // holds the parameter types. @@ -2952,7 +3007,7 @@ public: return param_type_begin()[i]; } ArrayRef<QualType> getParamTypes() const { - return ArrayRef<QualType>(param_type_begin(), param_type_end()); + return llvm::makeArrayRef(param_type_begin(), param_type_end()); } ExtProtoInfo getExtProtoInfo() const { @@ -2960,19 +3015,18 @@ public: EPI.ExtInfo = getExtInfo(); EPI.Variadic = isVariadic(); EPI.HasTrailingReturn = hasTrailingReturn(); - EPI.ExceptionSpecType = getExceptionSpecType(); + EPI.ExceptionSpec.Type = getExceptionSpecType(); EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals()); EPI.RefQualifier = getRefQualifier(); - if (EPI.ExceptionSpecType == EST_Dynamic) { - EPI.NumExceptions = NumExceptions; - EPI.Exceptions = exception_begin(); - } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { - EPI.NoexceptExpr = getNoexceptExpr(); - } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { - EPI.ExceptionSpecDecl = getExceptionSpecDecl(); - EPI.ExceptionSpecTemplate = getExceptionSpecTemplate(); - } else if (EPI.ExceptionSpecType == EST_Unevaluated) { - EPI.ExceptionSpecDecl = getExceptionSpecDecl(); + if (EPI.ExceptionSpec.Type == EST_Dynamic) { + EPI.ExceptionSpec.Exceptions = exceptions(); + } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) { + EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr(); + } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { + EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); + EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate(); + } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { + EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } if (hasAnyConsumedParams()) EPI.ConsumedParameters = getConsumedParamsBuffer(); @@ -2995,6 +3049,8 @@ public: bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } + /// \brief Return whether this function has a dependent exception spec. + bool hasDependentExceptionSpec() const; /// \brief Result type of getNoexceptSpec(). enum NoexceptResult { NR_NoNoexcept, ///< There is no noexcept specifier. @@ -3057,7 +3113,7 @@ public: /// \brief Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { - return static_cast<RefQualifierKind>(RefQualifier); + return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); } typedef const QualType *param_type_iterator; @@ -3074,10 +3130,9 @@ public: } typedef const QualType *exception_iterator; - typedef llvm::iterator_range<exception_iterator> exception_range; - exception_range exceptions() const { - return exception_range(exception_begin(), exception_end()); + ArrayRef<QualType> exceptions() const { + return llvm::makeArrayRef(exception_begin(), exception_end()); } exception_iterator exception_begin() const { // exceptions begin where arguments end @@ -3416,6 +3471,7 @@ public: attr_stdcall, attr_thiscall, attr_pascal, + attr_vectorcall, attr_pnaclcall, attr_inteloclbicc, attr_ms_abi, @@ -5231,8 +5287,8 @@ template <typename T> const T *Type::castAs() const { ArrayType_cannot_be_used_with_getAs<T> at; (void) at; - assert(isa<T>(CanonicalType)); if (const T *ty = dyn_cast<T>(this)) return ty; + assert(isa<T>(CanonicalType)); return cast<T>(getUnqualifiedDesugaredType()); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 3648d2a5c259..4f3c811ce275 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1208,7 +1208,7 @@ public: } ArrayRef<ParmVarDecl *> getParams() const { - return ArrayRef<ParmVarDecl *>(getParmArray(), getNumParams()); + return llvm::makeArrayRef(getParmArray(), getNumParams()); } // ParmVarDecls* are stored after Info, one for each parameter. @@ -1567,6 +1567,8 @@ public: void setUnderlyingTInfo(TypeSourceInfo* TI) const { this->getLocalData()->UnderlyingTInfo = TI; } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); }; // FIXME: location of the 'decltype' and parens. diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h index 9c9f15e95323..392e544d90c1 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -16,8 +16,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TYPE_ORDERING_H -#define LLVM_CLANG_TYPE_ORDERING_H +#ifndef LLVM_CLANG_AST_TYPEORDERING_H +#define LLVM_CLANG_AST_TYPEORDERING_H #include "clang/AST/CanonicalType.h" #include "clang/AST/Type.h" diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h index 2ef5800c305f..a11f22d201b7 100644 --- a/include/clang/AST/UnresolvedSet.h +++ b/include/clang/AST/UnresolvedSet.h @@ -98,7 +98,7 @@ class UnresolvedSetImpl { private: template <unsigned N> friend class UnresolvedSet; UnresolvedSetImpl() {} - UnresolvedSetImpl(const UnresolvedSetImpl &) LLVM_DELETED_FUNCTION; + UnresolvedSetImpl(const UnresolvedSetImpl &) {} public: // We don't currently support assignment through this iterator, so we might diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 8af0546db57b..ce2674e442da 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -38,10 +38,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H #include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Timer.h" namespace clang { @@ -102,6 +104,12 @@ public: /// /// Optionally override to do per translation unit tasks. virtual void onEndOfTranslationUnit() {} + + /// \brief An id used to group the matchers. + /// + /// This id is used, for example, for the profiling output. + /// It defaults to "<unknown>". + virtual StringRef getID() const; }; /// \brief Called when parsing is finished. Intended for testing only. @@ -111,7 +119,22 @@ public: virtual void run() = 0; }; - MatchFinder(); + struct MatchFinderOptions { + struct Profiling { + Profiling(llvm::StringMap<llvm::TimeRecord> &Records) + : Records(Records) {} + + /// \brief Per bucket timing information. + llvm::StringMap<llvm::TimeRecord> &Records; + }; + + /// \brief Enables per-check timers. + /// + /// It prints a report after match. + llvm::Optional<Profiling> CheckProfiling; + }; + + MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); ~MatchFinder(); /// \brief Adds a matcher to execute when running over the AST. @@ -148,7 +171,7 @@ public: MatchCallback *Action); /// \brief Creates a clang ASTConsumer that finds all matches. - clang::ASTConsumer *newASTConsumer(); + std::unique_ptr<clang::ASTConsumer> newASTConsumer(); /// \brief Calls the registered callbacks on all matches on the given \p Node. /// @@ -173,11 +196,25 @@ public: /// Each call to FindAll(...) will call the closure once. void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone); -private: - /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called + /// \brief For each \c Matcher<> a \c MatchCallback that will be called /// when it matches. - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > - MatcherCallbackPairs; + struct MatchersByType { + std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>> + DeclOrStmt; + std::vector<std::pair<TypeMatcher, MatchCallback *>> Type; + std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>> + NestedNameSpecifier; + std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>> + NestedNameSpecifierLoc; + std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc; + /// \brief All the callbacks in one container to simplify iteration. + std::vector<MatchCallback *> AllCallbacks; + }; + +private: + MatchersByType Matchers; + + MatchFinderOptions Options; /// \brief Called when parsing is done. ParsingDoneTestCallback *ParsingDone; @@ -210,16 +247,14 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, /// /// This is useful in combanation with \c match(): /// \code -/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), -/// Node, Context)); +/// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), +/// Node, Context)); /// \endcode template <typename NodeT> -NodeT * +const NodeT * selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { - for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(), - E = Results.end(); - I != E; ++I) { - if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo)) + for (const BoundNodes &N : Results) { + if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo)) return Node; } return nullptr; @@ -243,7 +278,7 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, MatchFinder Finder; Finder.addMatcher(Matcher, &Callback); Finder.match(Node, Context); - return Callback.Nodes; + return std::move(Callback.Nodes); } template <typename MatcherT, typename NodeT> @@ -255,4 +290,4 @@ match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 1ff4ab367fd5..f002cb9cbaba 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -42,9 +42,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" @@ -140,9 +141,97 @@ typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher; /// \endcode /// /// Usable as: Any Matcher -inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher> -anything() { - return internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>(); +inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } + +/// \brief Matches typedef declarations. +/// +/// Given +/// \code +/// typedef int X; +/// \endcode +/// typedefDecl() +/// matches "typedef int X" +const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl; + +/// \brief Matches AST nodes that were expanded within the main-file. +/// +/// Example matches X but not Y (matcher = recordDecl(isExpansionInMainFile()) +/// \code +/// #include <Y.h> +/// class X {}; +/// \endcode +/// Y.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + return SourceManager.isInMainFile( + SourceManager.getExpansionLoc(Node.getLocStart())); +} + +/// \brief Matches AST nodes that were expanded within system-header-files. +/// +/// Example matches Y but not X +/// (matcher = recordDecl(isExpansionInSystemHeader()) +/// \code +/// #include <SystemHeader.h> +/// class X {}; +/// \endcode +/// SystemHeader.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + return SourceManager.isInSystemHeader(ExpansionLoc); +} + +/// \brief Matches AST nodes that were expanded within files whose name is +/// partially matching a given regex. +/// +/// Example matches Y but not X +/// (matcher = recordDecl(isExpansionInFileMatching("AST.*")) +/// \code +/// #include "ASTMatcher.h" +/// class X {}; +/// \endcode +/// ASTMatcher.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> +AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching, + AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt, + TypeLoc), + std::string, RegExp) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + auto FileEntry = + SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc)); + if (!FileEntry) { + return false; + } + + auto Filename = FileEntry->getName(); + llvm::Regex RE(RegExp); + return RE.match(Filename); } /// \brief Matches declarations. @@ -156,6 +245,17 @@ anything() { /// \endcode const internal::VariadicAllOfMatcher<Decl> decl; +/// \brief Matches a declaration of a linkage specification. +/// +/// Given +/// \code +/// extern "C" {} +/// \endcode +/// linkageSpecDecl() +/// matches "extern "C" {}" +const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl> + linkageSpecDecl; + /// \brief Matches a declaration of anything that could have a name. /// /// Example matches \c X, \c S, the anonymous union type, \c i, and \c U; @@ -263,6 +363,17 @@ const internal::VariadicDynCastAllOfMatcher< /// \endcode const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer; +/// \brief Matches template arguments. +/// +/// Given +/// \code +/// template <typename T> struct C {}; +/// C<int> c; +/// \endcode +/// templateArgument() +/// matches 'int' in C<int>. +const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; + /// \brief Matches public C++ declarations. /// /// Given @@ -441,6 +552,23 @@ AST_POLYMORPHIC_MATCHER_P2( return InnerMatcher.matches(List[N], Finder, Builder); } +/// \brief Matches if the number of template arguments equals \p N. +/// +/// Given +/// \code +/// template<typename T> struct C {}; +/// C<int> c; +/// \endcode +/// classTemplateSpecializationDecl(templateArgumentCountIs(1)) +/// matches C<int>. +AST_POLYMORPHIC_MATCHER_P( + templateArgumentCountIs, + AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl, + TemplateSpecializationType), + unsigned, N) { + return internal::getTemplateSpecializationArgs(Node).size() == N; +} + /// \brief Matches a TemplateArgument that refers to a certain type. /// /// Given @@ -497,6 +625,68 @@ AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher<Expr>, InnerMatcher) { return false; } +/// \brief Matches a TemplateArgument that is an integral value. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(isIntegral())) +/// matches the implicit instantiation of C in C<42> +/// with isIntegral() matching 42. +AST_MATCHER(TemplateArgument, isIntegral) { + return Node.getKind() == TemplateArgument::Integral; +} + +/// \brief Matches a TemplateArgument that referes to an integral type. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(refersToIntegralType(asString("int")))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, refersToIntegralType, + internal::Matcher<QualType>, InnerMatcher) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return InnerMatcher.matches(Node.getIntegralType(), Finder, Builder); +} + +/// \brief Matches a TemplateArgument of integral type with a given value. +/// +/// Note that 'Value' is a string as the template argument's value is +/// an arbitrary precision integer. 'Value' must be euqal to the canonical +/// representation of that integral value in base 10. +/// +/// Given +/// \code +/// template<int T> struct A {}; +/// C<42> c; +/// \endcode +/// classTemplateSpecializationDecl( +/// hasAnyTemplateArgument(equalsIntegralValue("42"))) +/// matches the implicit instantiation of C in C<42>. +AST_MATCHER_P(TemplateArgument, equalsIntegralValue, + std::string, Value) { + if (Node.getKind() != TemplateArgument::Integral) + return false; + return Node.getAsIntegral().toString(10) == Value; +} + +/// \brief Matches any value declaration. +/// +/// Example matches A, B, C and F +/// \code +/// enum X { A, B, C }; +/// void F(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl; + /// \brief Matches C++ constructor declarations. /// /// Example matches Foo::Foo() and Foo::Foo(int) @@ -1414,21 +1604,21 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc; /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { - internal::EachOfVariadicOperator + internal::DynTypedMatcher::VO_EachOf }; /// \brief Matches if any of the given matchers matches. /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = { - internal::AnyOfVariadicOperator + internal::DynTypedMatcher::VO_AnyOf }; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { - internal::AllOfVariadicOperator + internal::DynTypedMatcher::VO_AllOf }; /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) @@ -1502,16 +1692,8 @@ inline internal::Matcher<Stmt> sizeOfExpr( /// \code /// namespace a { namespace b { class X; } } /// \endcode -AST_MATCHER_P(NamedDecl, hasName, std::string, Name) { - assert(!Name.empty()); - const std::string FullNameString = "::" + Node.getQualifiedNameAsString(); - const StringRef FullName = FullNameString; - const StringRef Pattern = Name; - if (Pattern.startswith("::")) { - return FullName == Pattern; - } else { - return FullName.endswith(("::" + Pattern).str()); - } +inline internal::Matcher<NamedDecl> hasName(const std::string &Name) { + return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name)); } /// \brief Matches NamedDecl nodes whose fully qualified names contain @@ -1558,7 +1740,7 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { inline internal::PolymorphicMatcherWithParam1< internal::HasOverloadedOperatorNameMatcher, StringRef, AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)> -hasOverloadedOperatorName(const StringRef Name) { +hasOverloadedOperatorName(StringRef Name) { return internal::PolymorphicMatcherWithParam1< internal::HasOverloadedOperatorNameMatcher, StringRef, AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>( @@ -1592,7 +1774,7 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, } /// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). -AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) { assert(!BaseName.empty()); return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -1607,8 +1789,8 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, /// \brief Overloaded method as shortcut for /// \c isSameOrDerivedFrom(hasName(...)). -AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName, - 1) { +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string, + BaseName, 1) { assert(!BaseName.empty()); return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -1768,7 +1950,7 @@ const internal::ArgumentAdaptingMatcherFunc< /// /// Usable as: Any Matcher const internal::VariadicOperatorMatcherFunc<1, 1> unless = { - internal::NotUnaryOperator + internal::DynTypedMatcher::VO_UnaryNot }; /// \brief Matches a node if the declaration associated with that node @@ -1844,7 +2026,7 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>, /// Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x"))))) /// \code /// class Y { public: void x(); }; -/// void z() { Y y; y.x(); +/// void z() { Y y; y.x(); } /// \endcode AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, 1) { @@ -1952,6 +2134,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>, /// void a(X b) { /// X &x = b; /// const X &y = b; +/// } /// }; /// \endcode AST_MATCHER_P(QualType, references, internal::Matcher<QualType>, @@ -2280,11 +2463,10 @@ AST_MATCHER(CXXCtorInitializer, isWritten) { AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2( CallExpr, CXXConstructExpr), internal::Matcher<Expr>, InnerMatcher) { - for (unsigned I = 0; I < Node.getNumArgs(); ++I) { + for (const Expr *Arg : Node.arguments()) { BoundNodesTreeBuilder Result(*Builder); - if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder, - &Result)) { - *Builder = Result; + if (InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, &Result)) { + *Builder = std::move(Result); return true; } } @@ -2372,6 +2554,19 @@ AST_MATCHER(FunctionDecl, isExternC) { return Node.isExternC(); } +/// \brief Matches deleted function declarations. +/// +/// Given: +/// \code +/// void Func(); +/// void DeletedFunc() = delete; +/// \endcode +/// functionDecl(isDeleted()) +/// matches the declaration of DeletedFunc, but not Func. +AST_MATCHER(FunctionDecl, isDeleted) { + return Node.isDeleted(); +} + /// \brief Matches the condition expression of an if statement, for loop, /// or conditional operator. /// @@ -2953,6 +3148,43 @@ AST_POLYMORPHIC_MATCHER( TSK_ExplicitInstantiationDefinition); } +/// \brief Matches declarations that are template instantiations or are inside +/// template instantiations. +/// +/// Given +/// \code +/// template<typename T> void A(T t) { T i; } +/// A(0); +/// A(0U); +/// \endcode +/// functionDecl(isInstantiated()) +/// matches 'A(int) {...};' and 'A(unsigned) {...}'. +AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) { + auto IsInstantiation = decl(anyOf(recordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))); + return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation))); +} + +/// \brief Matches statements inside of a template instantiation. +/// +/// Given +/// \code +/// int j; +/// template<typename T> void A(T t) { T i; j += 42;} +/// A(0); +/// A(0U); +/// \endcode +/// declStmt(isInTemplateInstantiation()) +/// matches 'int i;' and 'unsigned i'. +/// unless(stmt(isInTemplateInstantiation())) +/// will NOT match j += 42; as it's shared between the template definition and +/// instantiation. +AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) { + return stmt( + hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()), + functionDecl(isTemplateInstantiation()))))); +} + /// \brief Matches explicit template specializations of function, class, or /// static member variable template instantiations. /// @@ -2979,6 +3211,18 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc, new internal::TypeLocTypeMatcher(InnerMatcher)); } +/// \brief Matches type \c void. +/// +/// Given +/// \code +/// struct S { void func(); }; +/// \endcode +/// functionDecl(returns(voidType())) +/// matches "void func();" +AST_MATCHER(Type, voidType) { + return Node.isVoidType(); +} + /// \brief Matches builtin Types. /// /// Given @@ -3094,6 +3338,7 @@ AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType); /// int a[] = { 2, 3 } /// int b[42]; /// int c[a[0]]; +/// } /// \endcode /// variableArrayType() /// matches "int c[a[0]]" @@ -3432,8 +3677,9 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, /// \c recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the /// declaration of \c class \c D. AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) { - return InnerMatcher.matches(*Decl::castFromDeclContext(Node.getDeclContext()), - Finder, Builder); + const DeclContext *DC = Node.getDeclContext(); + if (!DC) return false; + return InnerMatcher.matches(*Decl::castFromDeclContext(DC), Finder, Builder); } /// \brief Matches nested name specifiers. @@ -3599,7 +3845,7 @@ AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>, Result.addMatch(CaseBuilder); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -3622,7 +3868,7 @@ AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer, Result.addMatch(InitBuilder); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -3643,7 +3889,32 @@ AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>, return InnerMatcher.matches(*Node.getLHS(), Finder, Builder); } +/// \brief Matches declaration that has a given attribute. +/// +/// Given +/// \code +/// __attribute__((device)) void f() { ... } +/// \endcode +/// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of +/// f. +AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) { + for (const auto *Attr : Node.attrs()) { + if (Attr->getKind() == AttrKind) + return true; + } + return false; +} + +/// \brief Matches CUDA kernel call expression. +/// +/// Example matches, +/// \code +/// kernel<<<i,j>>>(); +/// \endcode +const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr> + CUDAKernelCallExpr; + } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 94435fd274eb..ebe5cddb622a 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -32,8 +32,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" @@ -44,6 +44,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/VariadicFunction.h" +#include "llvm/Support/ManagedStatic.h" #include <map> #include <string> #include <vector> @@ -61,9 +62,8 @@ public: /// \brief Adds \c Node to the map with key \c ID. /// /// The node's base type should be in NodeBaseType or it will be unaccessible. - template <typename T> - void addNode(StringRef ID, const T* Node) { - NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node); + void addNode(StringRef ID, const ast_type_traits::DynTypedNode& DynNode) { + NodeMap[ID] = DynNode; } /// \brief Returns the AST node bound to \c ID. @@ -103,6 +103,16 @@ public: return NodeMap; } + /// \brief Returns \c true if this \c BoundNodesMap can be compared, i.e. all + /// stored nodes have memoization data. + bool isComparable() const { + for (const auto &IDAndNode : NodeMap) { + if (!IDAndNode.second.getMemoizationData()) + return false; + } + return true; + } + private: IDToNodeMap NodeMap; }; @@ -126,11 +136,12 @@ public: }; /// \brief Add a binding from an id to a node. - template <typename T> void setBinding(const std::string &Id, const T *Node) { + void setBinding(const std::string &Id, + const ast_type_traits::DynTypedNode &DynNode) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); - for (unsigned i = 0, e = Bindings.size(); i != e; ++i) - Bindings[i].addNode(Id, Node); + for (BoundNodesMap &Binding : Bindings) + Binding.addNode(Id, DynNode); } /// \brief Adds a branch in the tree. @@ -153,12 +164,38 @@ public: return Bindings < Other.Bindings; } + /// \brief Returns \c true if this \c BoundNodesTreeBuilder can be compared, + /// i.e. all stored node maps have memoization data. + bool isComparable() const { + for (const BoundNodesMap &NodesMap : Bindings) { + if (!NodesMap.isComparable()) + return false; + } + return true; + } + private: SmallVector<BoundNodesMap, 16> Bindings; }; class ASTMatchFinder; +/// \brief Generic interface for all matchers. +/// +/// Used by the implementation of Matcher<T> and DynTypedMatcher. +/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T> +/// instead. +class DynMatcherInterface : public RefCountedBaseVPTR { +public: + /// \brief Returns true if \p DynNode can be matched. + /// + /// May bind \p DynNode to an ID via \p Builder, or recurse into + /// the AST via \p Finder. + virtual bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const = 0; +}; + /// \brief Generic interface for matchers on an AST node of type T. /// /// Implement this if your matcher may need to inspect the children or @@ -167,7 +204,7 @@ class ASTMatchFinder; /// current node and doesn't care about its children or descendants, /// implement SingleNodeMatcherInterface instead. template <typename T> -class MatcherInterface : public RefCountedBaseVPTR { +class MatcherInterface : public DynMatcherInterface { public: virtual ~MatcherInterface() {} @@ -178,6 +215,12 @@ public: virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const = 0; + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return matches(DynNode.getUnchecked<T>(), Finder, Builder); + } }; /// \brief Interface for matchers that only evaluate properties on a single @@ -199,6 +242,145 @@ private: } }; +template <typename> class Matcher; + +/// \brief Matcher that works on a \c DynTypedNode. +/// +/// It is constructed from a \c Matcher<T> object and redirects most calls to +/// underlying matcher. +/// It checks whether the \c DynTypedNode is convertible into the type of the +/// underlying matcher and then do the actual match on the actual node, or +/// return false if it is not convertible. +class DynTypedMatcher { +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>()), + 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, + std::vector<DynTypedMatcher> InnerMatchers); + + /// \brief Get a "true" matcher for \p NodeKind. + /// + /// It only checks that the node is of the right kind. + static DynTypedMatcher trueMatcher(ast_type_traits::ASTNodeKind NodeKind); + + void setAllowBind(bool AB) { AllowBind = AB; } + + /// \brief Check whether this matcher could ever match a node of kind \p Kind. + /// \return \c false if this matcher will never match such a node. Otherwise, + /// return \c true. + bool canMatchNodesOfKind(ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Return a matcher that points to the same implementation, but + /// restricts the node types for \p Kind. + DynTypedMatcher dynCastTo(const ast_type_traits::ASTNodeKind Kind) const; + + /// \brief Returns true if the matcher matches the given \c DynNode. + bool matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; + + /// \brief Same as matches(), but skips the kind check. + /// + /// It is faster, but the caller must ensure the node is valid for the + /// kind of this matcher. + bool matchesNoKindCheck(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const; + + /// \brief Bind the specified \p ID to the matcher. + /// \return A new matcher with the \p ID bound to it if this matcher supports + /// binding. Otherwise, returns an empty \c Optional<>. + llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const; + + /// \brief Returns a unique \p ID for the matcher. + /// + /// Casting a Matcher<T> to Matcher<U> creates a matcher that has the + /// same \c Implementation pointer, but different \c RestrictKind. We need to + /// 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; + MatcherIDType getID() const { + /// FIXME: Document the requirements this imposes on matcher + /// implementations (no new() implementation_ during a Matches()). + return std::make_pair(RestrictKind, + reinterpret_cast<uint64_t>(Implementation.get())); + } + + /// \brief Returns the type this matcher works on. + /// + /// \c matches() will always return false unless the node passed is of this + /// or a derived type. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return SupportedKind; + } + + /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted + /// to a \c Matcher<T>. + /// + /// This method verifies that the underlying matcher in \c Other can process + /// nodes of types T. + template <typename T> bool canConvertTo() const { + return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } + bool canConvertTo(ast_type_traits::ASTNodeKind To) const; + + /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. + /// + /// This method asserts that \c canConvertTo() is \c true. Callers + /// should call \c canConvertTo() first to make sure that \c this is + /// compatible with T. + template <typename T> Matcher<T> convertTo() const { + assert(canConvertTo<T>()); + return unconditionalConvertTo<T>(); + } + + /// \brief Same as \c convertTo(), but does not check that the underlying + /// matcher can handle a value of T. + /// + /// If it is not compatible, then this matcher will never match anything. + template <typename T> Matcher<T> unconditionalConvertTo() const; + +private: + DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind, + ast_type_traits::ASTNodeKind RestrictKind, + IntrusiveRefCntPtr<DynMatcherInterface> Implementation) + : AllowBind(false), + SupportedKind(SupportedKind), + RestrictKind(RestrictKind), + Implementation(std::move(Implementation)) {} + + bool AllowBind; + ast_type_traits::ASTNodeKind SupportedKind; + /// \brief A potentially stricter node kind. + /// + /// It allows to perform implicit and dynamic cast of matchers without + /// needing to change \c Implementation. + ast_type_traits::ASTNodeKind RestrictKind; + IntrusiveRefCntPtr<DynMatcherInterface> Implementation; +}; + /// \brief Wrapper of a MatcherInterface<T> *that allows copying. /// /// A Matcher<Base> can be used anywhere a Matcher<Derived> is @@ -221,7 +403,10 @@ public: Matcher(const Matcher<From> &Other, typename std::enable_if<std::is_base_of<From, T>::value && !std::is_same<From, T>::value>::type * = 0) - : Implementation(new ImplicitCastMatcher<From>(Other)) {} + : Implementation(restrictMatcher(Other.Implementation)) { + assert(Implementation.getSupportedKind().isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } /// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>. /// @@ -233,26 +418,34 @@ public: std::is_same<TypeT, Type>::value>::type* = 0) : Implementation(new TypeToQualType<TypeT>(Other)) {} + /// \brief Convert \c this into a \c Matcher<T> by applying dyn_cast<> to the + /// argument. + /// \c To must be a base class of \c T. + template <typename To> + Matcher<To> dynCastTo() const { + static_assert(std::is_base_of<To, T>::value, "Invalid dynCast call."); + return Matcher<To>(Implementation); + } + /// \brief Forwards the call to the underlying MatcherInterface<T> pointer. bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - if (Implementation->matches(Node, Finder, Builder)) - return true; - // Delete all bindings when a matcher does not match. - // This prevents unexpected exposure of bound nodes in unmatches - // branches of the match tree. - *Builder = BoundNodesTreeBuilder(); - return false; + return Implementation.matches(ast_type_traits::DynTypedNode::create(Node), + Finder, Builder); } /// \brief Returns an ID that uniquely identifies the matcher. - uint64_t getID() const { - /// FIXME: Document the requirements this imposes on matcher - /// implementations (no new() implementation_ during a Matches()). - return reinterpret_cast<uint64_t>(Implementation.get()); + DynTypedMatcher::MatcherIDType getID() const { + return Implementation.getID(); } + /// \brief Extract the dynamic matcher. + /// + /// The returned matcher keeps the same restrictions as \c this and remembers + /// that it is meant to support nodes of type \c T. + operator DynTypedMatcher() const { return Implementation; } + /// \brief Allows the conversion of a \c Matcher<Type> to a \c /// Matcher<QualType>. /// @@ -276,24 +469,22 @@ public: }; private: - /// \brief Allows conversion from Matcher<Base> to Matcher<T> if T - /// is derived from Base. - template <typename Base> - class ImplicitCastMatcher : public MatcherInterface<T> { - public: - explicit ImplicitCastMatcher(const Matcher<Base> &From) - : From(From) {} + // For Matcher<T> <=> Matcher<U> conversions. + template <typename U> friend class Matcher; + // For DynTypedMatcher::unconditionalConvertTo<T>. + friend class DynTypedMatcher; - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - return From.matches(Node, Finder, Builder); - } + static DynTypedMatcher restrictMatcher(const DynTypedMatcher &Other) { + return Other.dynCastTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); + } - private: - const Matcher<Base> From; - }; + explicit Matcher(const DynTypedMatcher &Implementation) + : Implementation(restrictMatcher(Implementation)) { + assert(this->Implementation.getSupportedKind() + .isSame(ast_type_traits::ASTNodeKind::getFromNodeKind<T>())); + } - IntrusiveRefCntPtr< MatcherInterface<T> > Implementation; + DynTypedMatcher Implementation; }; // class Matcher /// \brief A convenient helper for creating a Matcher<T> without specifying @@ -303,153 +494,10 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) { return Matcher<T>(Implementation); } -template <typename T> class BindableMatcher; - -/// \brief Matcher that works on a \c DynTypedNode. -/// -/// It is constructed from a \c Matcher<T> object and redirects most calls to -/// underlying matcher. -/// It checks whether the \c DynTypedNode is convertible into the type of the -/// underlying matcher and then do the actual match on the actual node, or -/// return false if it is not convertible. -class DynTypedMatcher { -public: - /// \brief Construct from a \c Matcher<T>. Copies the matcher. - template <typename T> inline DynTypedMatcher(const Matcher<T> &M); - - /// \brief Construct from a bindable \c Matcher<T>. Copies the matcher. - /// - /// This version enables \c tryBind() on the \c DynTypedMatcher. - template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M); - - /// \brief Returns true if the matcher matches the given \c DynNode. - bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - return Storage->matches(DynNode, Finder, Builder); - } - - /// \brief Bind the specified \p ID to the matcher. - /// \return A new matcher with the \p ID bound to it if this matcher supports - /// binding. Otherwise, returns an empty \c Optional<>. - llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const { - return Storage->tryBind(ID); - } - - /// \brief Returns a unique \p ID for the matcher. - uint64_t getID() const { return Storage->getID(); } - - /// \brief Returns the type this matcher works on. - /// - /// \c matches() will always return false unless the node passed is of this - /// or a derived type. - ast_type_traits::ASTNodeKind getSupportedKind() const { - return Storage->getSupportedKind(); - } - - /// \brief Returns \c true if the passed \c DynTypedMatcher can be converted - /// to a \c Matcher<T>. - /// - /// This method verifies that the underlying matcher in \c Other can process - /// nodes of types T. - template <typename T> bool canConvertTo() const { - return getSupportedKind().isBaseOf( - ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); - } - - /// \brief Construct a \c Matcher<T> interface around the dynamic matcher. - /// - /// This method asserts that \c canConvertTo() is \c true. Callers - /// should call \c canConvertTo() first to make sure that \c this is - /// compatible with T. - template <typename T> Matcher<T> convertTo() const { - assert(canConvertTo<T>()); - return unconditionalConvertTo<T>(); - } - - /// \brief Same as \c convertTo(), but does not check that the underlying - /// matcher can handle a value of T. - /// - /// If it is not compatible, then this matcher will never match anything. - template <typename T> Matcher<T> unconditionalConvertTo() const; - -private: - class MatcherStorage : public RefCountedBaseVPTR { - public: - MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID) - : SupportedKind(SupportedKind), ID(ID) {} - virtual ~MatcherStorage(); - - virtual bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const = 0; - - virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0; - - ast_type_traits::ASTNodeKind getSupportedKind() const { - return SupportedKind; - } - - uint64_t getID() const { return ID; } - - private: - const ast_type_traits::ASTNodeKind SupportedKind; - const uint64_t ID; - }; - - /// \brief Typed implementation of \c MatcherStorage. - template <typename T> class TypedMatcherStorage; - - IntrusiveRefCntPtr<const MatcherStorage> Storage; -}; - -template <typename T> -class DynTypedMatcher::TypedMatcherStorage : public MatcherStorage { -public: - TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind) - : MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(), - Other.getID()), - InnerMatcher(Other), AllowBind(AllowBind) {} - - bool matches(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - if (const T *Node = DynNode.get<T>()) { - return InnerMatcher.matches(*Node, Finder, Builder); - } - return false; - } - - llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const override { - if (!AllowBind) - return llvm::Optional<DynTypedMatcher>(); - return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID)); - } - -private: - const Matcher<T> InnerMatcher; - const bool AllowBind; -}; - -template <typename T> -inline DynTypedMatcher::DynTypedMatcher(const Matcher<T> &M) - : Storage(new TypedMatcherStorage<T>(M, false)) {} - -template <typename T> -inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M) - : Storage(new TypedMatcherStorage<T>(M, true)) {} - /// \brief Specialization of the conversion functions for QualType. /// -/// These specializations provide the Matcher<Type>->Matcher<QualType> +/// This specialization provides the Matcher<Type>->Matcher<QualType> /// conversion that the static API does. -template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const { - const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); - return SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) || - SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>()); -} - template <> inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const { assert(canConvertTo<QualType>()); @@ -470,7 +518,7 @@ bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(*I, Finder, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } } @@ -486,7 +534,7 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(**I, Finder, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } } @@ -549,6 +597,33 @@ private: std::string Name; }; +/// \brief Matches named declarations with a specific name. +/// +/// See \c hasName() in ASTMatchers.h for details. +class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> { + public: + explicit HasNameMatcher(StringRef Name); + + bool matchesNode(const NamedDecl &Node) const override; + + private: + /// \brief Unqualified match routine. + /// + /// It is much faster than the full match, but it only works for unqualified + /// matches. + bool matchesNodeUnqualified(const NamedDecl &Node) const; + + /// \brief Full match routine + /// + /// It generates the fully qualified name of the declaration (which is + /// expensive) before trying to match. + /// It is slower but simple and works on all cases. + bool matchesNodeFull(const NamedDecl &Node) const; + + const bool UseUnqualifiedMatch; + const std::string Name; +}; + /// \brief Matches declarations for QualType and CallExpr. /// /// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but @@ -973,46 +1048,16 @@ private: /// /// This is useful when a matcher syntactically requires a child matcher, /// but the context doesn't care. See for example: anything(). -/// -/// FIXME: Alternatively we could also create a IsAMatcher or something -/// that checks that a dyn_cast is possible. This is purely needed for the -/// difference between calling for example: -/// record() -/// and -/// record(SomeMatcher) -/// In the second case we need the correct type we were dyn_cast'ed to in order -/// to get the right type for the inner matcher. In the first case we don't need -/// that, but we use the type conversion anyway and insert a TrueMatcher. -template <typename T> -class TrueMatcher : public SingleNodeMatcherInterface<T> { -public: - bool matchesNode(const T &Node) const override { - return true; - } -}; - -/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node -/// to an ID if the inner matcher matches on the node. -template <typename T> -class IdMatcher : public MatcherInterface<T> { -public: - /// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches - /// the node. - IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher) - : ID(ID), InnerMatcher(InnerMatcher) {} +class TrueMatcher { + public: + typedef AllNodeBaseTypes ReturnTypes; - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - bool Result = InnerMatcher.matches(Node, Finder, Builder); - if (Result) { - Builder->setBinding(ID, &Node); - } - return Result; + template <typename T> + operator Matcher<T>() const { + return DynTypedMatcher::trueMatcher( + ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) + .template unconditionalConvertTo<T>(); } - -private: - const std::string ID; - const Matcher<T> InnerMatcher; }; /// \brief A Matcher that allows binding the node it matches to an id. @@ -1031,7 +1076,17 @@ public: /// The returned matcher is equivalent to this matcher, but will /// bind the matched node on a match. Matcher<T> bind(StringRef ID) const { - return Matcher<T>(new IdMatcher<T>(ID, *this)); + return DynTypedMatcher(*this) + .tryBind(ID) + ->template unconditionalConvertTo<T>(); + } + + /// \brief Same as Matcher<T>'s conversion operator, but enables binding on + /// the returned matcher. + operator DynTypedMatcher() const { + DynTypedMatcher Result = static_cast<const Matcher<T>&>(*this); + Result.setAllowBind(true); + return Result; } }; @@ -1089,36 +1144,11 @@ private: /// \brief VariadicOperatorMatcher related types. /// @{ -/// \brief Function signature for any variadic operator. It takes the inner -/// matchers as an array of DynTypedMatcher. -typedef bool (*VariadicOperatorFunction)( - const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief \c MatcherInterface<T> implementation for an variadic operator. -template <typename T> -class VariadicOperatorMatcherInterface : public MatcherInterface<T> { -public: - VariadicOperatorMatcherInterface(VariadicOperatorFunction Func, - std::vector<DynTypedMatcher> InnerMatchers) - : Func(Func), InnerMatchers(std::move(InnerMatchers)) {} - - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const override { - return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder, - InnerMatchers); - } - -private: - const VariadicOperatorFunction Func; - const std::vector<DynTypedMatcher> InnerMatchers; -}; - /// \brief "No argument" placeholder to use as template paratemers. struct VariadicOperatorNoArg {}; -/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction -/// operator. +/// \brief Polymorphic matcher object that uses a \c +/// DynTypedMatcher::VariadicOperator operator. /// /// Input matchers can have any type (including other polymorphic matcher /// types), and the actual Matcher<T> is generated on demand with an implicit @@ -1133,7 +1163,8 @@ template <typename P1, typename P2 = VariadicOperatorNoArg, typename P9 = VariadicOperatorNoArg> class VariadicOperatorMatcher { public: - VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1, + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + const P1 &Param1, const P2 &Param2 = VariadicOperatorNoArg(), const P3 &Param3 = VariadicOperatorNoArg(), const P4 &Param4 = VariadicOperatorNoArg(), @@ -1142,7 +1173,7 @@ public: const P7 &Param7 = VariadicOperatorNoArg(), const P8 &Param8 = VariadicOperatorNoArg(), const P9 &Param9 = VariadicOperatorNoArg()) - : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3), + : Op(Op), Param1(Param1), Param2(Param2), Param3(Param3), Param4(Param4), Param5(Param5), Param6(Param6), Param7(Param7), Param8(Param8), Param9(Param9) {} @@ -1157,8 +1188,8 @@ public: addMatcher<T>(Param7, Matchers); addMatcher<T>(Param8, Matchers); addMatcher<T>(Param9, Matchers); - return Matcher<T>( - new VariadicOperatorMatcherInterface<T>(Func, std::move(Matchers))); + return DynTypedMatcher::constructVariadic(Op, std::move(Matchers)) + .template unconditionalConvertTo<T>(); } private: @@ -1173,7 +1204,7 @@ private: static void addMatcher(VariadicOperatorNoArg, std::vector<DynTypedMatcher> &Matchers) {} - const VariadicOperatorFunction Func; + const DynTypedMatcher::VariadicOperator Op; const P1 Param1; const P2 Param2; const P3 Param3; @@ -1191,7 +1222,7 @@ private: /// It supports 1-9 argument overloaded operator(). More can be added if needed. template <unsigned MinCount, unsigned MaxCount> struct VariadicOperatorMatcherFunc { - VariadicOperatorFunction Func; + DynTypedMatcher::VariadicOperator Op; template <unsigned Count, typename T> struct EnableIfValidArity @@ -1200,30 +1231,29 @@ struct VariadicOperatorMatcherFunc { template <typename M1> typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type operator()(const M1 &P1) const { - return VariadicOperatorMatcher<M1>(Func, P1); + return VariadicOperatorMatcher<M1>(Op, P1); } template <typename M1, typename M2> typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type operator()(const M1 &P1, const M2 &P2) const { - return VariadicOperatorMatcher<M1, M2>(Func, P1, P2); + return VariadicOperatorMatcher<M1, M2>(Op, P1, P2); } template <typename M1, typename M2, typename M3> typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3) const { - return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3); + return VariadicOperatorMatcher<M1, M2, M3>(Op, P1, P2, P3); } template <typename M1, typename M2, typename M3, typename M4> typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const { - return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4); + return VariadicOperatorMatcher<M1, M2, M3, M4>(Op, P1, P2, P3, P4); } template <typename M1, typename M2, typename M3, typename M4, typename M5> typename EnableIfValidArity< 5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) const { - return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4, - P5); + return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Op, P1, P2, P3, P4, P5); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6> @@ -1232,7 +1262,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6>( - Func, P1, P2, P3, P4, P5, P6); + Op, P1, P2, P3, P4, P5, P6); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7> @@ -1241,7 +1271,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6, const M7 &P7) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7>( - Func, P1, P2, P3, P4, P5, P6, P7); + Op, P1, P2, P3, P4, P5, P6, P7); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7, typename M8> @@ -1250,7 +1280,7 @@ struct VariadicOperatorMatcherFunc { operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8>( - Func, P1, P2, P3, P4, P5, P6, P7, P8); + Op, P1, P2, P3, P4, P5, P6, P7, P8); } template <typename M1, typename M2, typename M3, typename M4, typename M5, typename M6, typename M7, typename M8, typename M9> @@ -1260,55 +1290,40 @@ struct VariadicOperatorMatcherFunc { const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8, const M9 &P9) const { return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9>( - Func, P1, P2, P3, P4, P5, P6, P7, P8, P9); + Op, P1, P2, P3, P4, P5, P6, P7, P8, P9); } }; /// @} -/// \brief Matches nodes that do not match the provided matcher. -/// -/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1. -bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which all provided matchers match. -bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which at least one of the provided matchers -/// matches, but doesn't stop at the first match. -bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - -/// \brief Matches nodes for which at least one of the provided matchers -/// matches. -bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder, - ArrayRef<DynTypedMatcher> InnerMatchers); - template <typename T> inline Matcher<T> DynTypedMatcher::unconditionalConvertTo() const { - return Matcher<T>(new VariadicOperatorMatcherInterface<T>( - AllOfVariadicOperator, llvm::makeArrayRef(*this))); + return Matcher<T>(*this); } /// \brief Creates a Matcher<T> that matches if all inner matchers match. template<typename T> BindableMatcher<T> makeAllOfComposite( ArrayRef<const Matcher<T> *> InnerMatchers) { - std::vector<DynTypedMatcher> DynMatchers; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - DynMatchers.push_back(*InnerMatchers[i]); + // For the size() == 0 case, we return a "true" matcher. + if (InnerMatchers.size() == 0) { + return BindableMatcher<T>(TrueMatcher()); + } + // For the size() == 1 case, we simply return that one matcher. + // No need to wrap it in a variadic operation. + if (InnerMatchers.size() == 1) { + return BindableMatcher<T>(*InnerMatchers[0]); } - return BindableMatcher<T>(new VariadicOperatorMatcherInterface<T>( - AllOfVariadicOperator, std::move(DynMatchers))); + + std::vector<DynTypedMatcher> DynMatchers; + DynMatchers.reserve(InnerMatchers.size()); + for (const auto *InnerMatcher : InnerMatchers) { + DynMatchers.push_back(*InnerMatcher); + } + return BindableMatcher<T>( + DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, + std::move(DynMatchers)) + .template unconditionalConvertTo<T>()); } /// \brief Creates a Matcher<T> that matches if @@ -1320,8 +1335,8 @@ BindableMatcher<T> makeAllOfComposite( template<typename T, typename InnerT> BindableMatcher<T> makeDynCastAllOfComposite( ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers)) - .unconditionalConvertTo<T>()); + return BindableMatcher<T>( + makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); } /// \brief Matches nodes of type T that have at least one descendant node of @@ -1606,6 +1621,23 @@ private: const Matcher<InnerTBase> InnerMatcher; }; +/// \brief A simple memoizer of T(*)() functions. +/// +/// It will call the passed 'Func' template parameter at most once. +/// Used to support AST_MATCHER_FUNCTION() macro. +template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher { + struct Wrapper { + Wrapper() : M(Func()) {} + Matcher M; + }; + +public: + static const Matcher &getInstance() { + static llvm::ManagedStatic<Wrapper> Instance; + return Instance->M; + } +}; + // Define the create() method out of line to silence a GCC warning about // the struct "Func" having greater visibility than its base, which comes from // using the flag -fvisibility-inlines-hidden. @@ -1627,7 +1659,7 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) { inline ArrayRef<TemplateArgument> getTemplateSpecializationArgs(const TemplateSpecializationType &T) { - return ArrayRef<TemplateArgument>(T.getArgs(), T.getNumArgs()); + return llvm::makeArrayRef(T.getArgs(), T.getNumArgs()); } struct NotEqualsBoundNodePredicate { @@ -1642,4 +1674,4 @@ struct NotEqualsBoundNodePredicate { } // end namespace ast_matchers } // end namespace clang -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H +#endif diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h index 563372a50609..b7888be7c176 100644 --- a/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -34,8 +34,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H -#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H +#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H +#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H + +/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { +/// defines a zero parameter function named DefineMatcher() that returns a +/// ReturnType object. +#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \ + inline ReturnType DefineMatcher##_getInstance(); \ + inline ReturnType DefineMatcher() { \ + return internal::MemoizedMatcher< \ + ReturnType, DefineMatcher##_getInstance>::getInstance(); \ + } \ + inline ReturnType DefineMatcher##_getInstance() /// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) { /// defines a single-parameter function named DefineMatcher() that returns a @@ -352,4 +363,4 @@ internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \ AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF) -#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H +#endif diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h index 82a14f1929be..ef93ac54508d 100644 --- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/LLVM.h" diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h index 4045f57d1b36..bd006b6e1290 100644 --- a/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -31,8 +31,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/Registry.h" @@ -63,17 +63,6 @@ public: public: virtual ~Sema(); - /// \brief Lookup a value by name. - /// - /// This can be used in the Sema layer to declare known constants or to - /// allow to split an expression in pieces. - /// - /// \param Name The name of the value to lookup. - /// - /// \return The named value. It could be any type that VariantValue - /// supports. An empty value means that the name is not recognized. - virtual VariantValue getNamedValue(StringRef Name); - /// \brief Process a matcher expression. /// /// All the arguments passed here have already been processed. @@ -105,6 +94,29 @@ public: /// found. virtual llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) = 0; + + /// \brief Compute the list of completion types for \p Context. + /// + /// Each element of \p Context represents a matcher invocation, going from + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + virtual std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. + /// + /// \param AcceptedTypes All types accepted for this completion. + /// + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. + virtual std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes); }; /// \brief Sema implementation that uses the matcher registry to process the @@ -121,58 +133,91 @@ public: StringRef BindID, ArrayRef<ParserValue> Args, Diagnostics *Error) override; + + std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override; + + std::vector<MatcherCompletion> + getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override; }; - /// \brief Parse a matcher expression, creating matchers from the registry. - /// - /// This overload creates matchers calling directly into the registry. If the - /// caller needs more control over how the matchers are created, then it can - /// use the overload below that takes a Sema. - /// - /// \param MatcherCode The matcher expression to parse. - /// - /// \return The matcher object constructed, or an empty Optional if an error - /// occurred. - /// In that case, \c Error will contain a description of the error. - /// The caller takes ownership of the DynTypedMatcher object returned. - static llvm::Optional<DynTypedMatcher> - parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error); + typedef llvm::StringMap<VariantValue> NamedValueMap; /// \brief Parse a matcher expression. /// /// \param MatcherCode The matcher expression to parse. /// /// \param S The Sema instance that will help the parser - /// construct the matchers. + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// /// \return The matcher object constructed by the processor, or an empty /// Optional if an error occurred. In that case, \c Error will contain a /// description of the error. /// The caller takes ownership of the DynTypedMatcher object returned. static llvm::Optional<DynTypedMatcher> - parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error); - - /// \brief Parse an expression, creating matchers from the registry. - /// - /// Parses any expression supported by this parser. In general, the - /// \c parseMatcherExpression function is a better approach to get a matcher - /// object. - static bool parseExpression(StringRef Code, VariantValue *Value, - Diagnostics *Error); + parseMatcherExpression(StringRef MatcherCode, Sema *S, + const NamedValueMap *NamedValues, + Diagnostics *Error); + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Sema *S, + Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, S, nullptr, Error); + } + static llvm::Optional<DynTypedMatcher> + parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) { + return parseMatcherExpression(MatcherCode, nullptr, Error); + } /// \brief Parse an expression. /// /// Parses any expression supported by this parser. In general, the /// \c parseMatcherExpression function is a better approach to get a matcher /// object. + /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. static bool parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error); + static bool parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + return parseExpression(Code, S, nullptr, Value, Error); + } + static bool parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + return parseExpression(Code, nullptr, Value, Error); + } /// \brief Complete an expression at the given offset. /// + /// \param S The Sema instance that will help the parser + /// construct the matchers. If null, it uses the default registry. + /// + /// \param NamedValues A map of precomputed named values. This provides + /// the dictionary for the <NamedValue> rule of the grammar. + /// If null, it is ignored. + /// /// \return The list of completions, which may be empty if there are no /// available completions or if an error occurred. static std::vector<MatcherCompletion> - completeExpression(StringRef Code, unsigned CompletionOffset); + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues); + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) { + return completeExpression(Code, CompletionOffset, S, nullptr); + } + static std::vector<MatcherCompletion> + completeExpression(StringRef Code, unsigned CompletionOffset) { + return completeExpression(Code, CompletionOffset, nullptr); + } private: class CodeTokenizer; @@ -180,6 +225,7 @@ private: struct TokenInfo; Parser(CodeTokenizer *Tokenizer, Sema *S, + const NamedValueMap *NamedValues, Diagnostics *Error); bool parseExpressionImpl(VariantValue *Value); @@ -187,12 +233,16 @@ private: VariantValue *Value); bool parseIdentifierPrefixImpl(VariantValue *Value); - void addCompletion(const TokenInfo &CompToken, StringRef TypedText, - StringRef Decl); + void addCompletion(const TokenInfo &CompToken, + const MatcherCompletion &Completion); void addExpressionCompletions(); + std::vector<MatcherCompletion> + getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes); + CodeTokenizer *const Tokenizer; Sema *const S; + const NamedValueMap *const NamedValues; Diagnostics *const Error; typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy; diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h index faa9254bc2e7..ad24a8d1b794 100644 --- a/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -14,8 +14,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" @@ -36,8 +36,10 @@ typedef const internal::MatcherDescriptor *MatcherCtor; struct MatcherCompletion { MatcherCompletion() {} - MatcherCompletion(StringRef TypedText, StringRef MatcherDecl) - : TypedText(TypedText), MatcherDecl(MatcherDecl) {} + MatcherCompletion(StringRef TypedText, StringRef MatcherDecl, + unsigned Specificity) + : TypedText(TypedText), MatcherDecl(MatcherDecl), + Specificity(Specificity) {} /// \brief The text to type to select this matcher. std::string TypedText; @@ -45,6 +47,13 @@ struct MatcherCompletion { /// \brief The "declaration" of the matcher, with type information. std::string MatcherDecl; + /// \brief Value corresponding to the "specificity" of the converted matcher. + /// + /// Zero specificity indicates that this conversion would produce a trivial + /// matcher that will either always or never match. + /// Such matchers are excluded from code completion results. + unsigned Specificity; + bool operator==(const MatcherCompletion &Other) const { return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl; } @@ -58,28 +67,28 @@ public: /// constructor, or Optional<MatcherCtor>() if not found. static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName); - /// \brief Compute the list of completions for \p Context. + /// \brief Compute the list of completion types for \p Context. /// /// Each element of \p Context represents a matcher invocation, going from - /// outermost to innermost. Elements are pairs consisting of a reference to the - /// matcher constructor and the index of the next element in the argument list - /// of that matcher (or for the last element, the index of the completion - /// point in the argument list). An empty list requests completion for the - /// root matcher. + /// outermost to innermost. Elements are pairs consisting of a reference to + /// the matcher constructor and the index of the next element in the + /// argument list of that matcher (or for the last element, the index of + /// the completion point in the argument list). An empty list requests + /// completion for the root matcher. + static std::vector<ArgKind> getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); + + /// \brief Compute the list of completions that match any of + /// \p AcceptedTypes. /// - /// The completions are ordered first by decreasing relevance, then - /// alphabetically. Relevance is determined by how closely the matcher's - /// type matches that of the context. For example, if the innermost matcher - /// takes a FunctionDecl matcher, the FunctionDecl matchers are returned - /// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then - /// polymorphic matchers. + /// \param AcceptedTypes All types accepted for this completion. /// - /// Matchers which are technically convertible to the innermost context but - /// which would match either all or no nodes are excluded. For example, - /// namedDecl and varDecl are excluded in a FunctionDecl context, because - /// those matchers would match respectively all or no nodes in such a context. + /// \return All completions for the specified types. + /// Completions should be valid when used in \c lookupMatcherCtor(). + /// The matcher constructed from the return of \c lookupMatcherCtor() + /// should be convertible to some type in \p AcceptedTypes. static std::vector<MatcherCompletion> - getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context); + getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes); /// \brief Construct a matcher from the registry. /// diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index b25267b1c54b..a9bd3d50115a 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -14,8 +14,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H +#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H +#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" @@ -29,6 +29,51 @@ namespace clang { namespace ast_matchers { namespace dynamic { +/// \brief Kind identifier. +/// +/// It supports all types that VariantValue can contain. +class ArgKind { + public: + enum Kind { + AK_Matcher, + AK_Unsigned, + AK_String + }; + /// \brief Constructor for non-matcher types. + ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); } + + /// \brief Constructor for matcher types. + ArgKind(ast_type_traits::ASTNodeKind MatcherKind) + : K(AK_Matcher), MatcherKind(MatcherKind) {} + + Kind getArgKind() const { return K; } + ast_type_traits::ASTNodeKind getMatcherKind() const { + assert(K == AK_Matcher); + return MatcherKind; + } + + /// \brief Determines if this type can be converted to \p To. + /// + /// \param To the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind To, unsigned *Specificity) const; + + bool operator<(const ArgKind &Other) const { + if (K == AK_Matcher && Other.K == AK_Matcher) + return MatcherKind < Other.MatcherKind; + return K < Other.K; + } + + /// \brief String representation of the type. + std::string asString() const; + +private: + Kind K; + ast_type_traits::ASTNodeKind MatcherKind; +}; + using ast_matchers::internal::DynTypedMatcher; /// \brief A variant matcher object. @@ -48,13 +93,28 @@ class VariantMatcher { /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. class MatcherOps { public: - virtual ~MatcherOps(); - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const = 0; - virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; - virtual void constructVariadicOperator( - ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef<VariantMatcher> InnerMatchers) = 0; + MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + + /// \brief Convert \p Matcher the destination type and return it as a new + /// DynTypedMatcher. + virtual DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const = 0; + + /// \brief Constructs a variadic typed matcher from \p InnerMatchers. + /// Will try to convert each inner matcher to the destination type and + /// return llvm::None if it fails to do so. + llvm::Optional<DynTypedMatcher> + constructVariadicOperator(DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const; + + protected: + ~MatcherOps() {} + + private: + ast_type_traits::ASTNodeKind NodeKind; }; /// \brief Payload interface to be specialized by each matcher type. @@ -65,7 +125,10 @@ class VariantMatcher { virtual ~Payload(); virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0; virtual std::string getTypeAsString() const = 0; - virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; + virtual llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const = 0; + virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const = 0; }; public: @@ -84,9 +147,9 @@ public: /// \brief Creates a 'variadic' operator matcher. /// /// It will bind to the appropriate type on getTypedMatcher<T>(). - static VariantMatcher VariadicOperatorMatcher( - ast_matchers::internal::VariadicOperatorFunction Func, - std::vector<VariantMatcher> Args); + static VariantMatcher + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, + std::vector<VariantMatcher> Args); /// \brief Makes the matcher the "null" matcher. void reset(); @@ -111,9 +174,21 @@ public: /// that can, the result would be ambiguous and false is returned. template <class T> bool hasTypedMatcher() const { - TypedMatcherOps<T> Ops; - if (Value) Value->makeTypedMatcher(Ops); - return Ops.hasMatcher(); + if (!Value) return false; + return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue(); + } + + /// \brief Determines if the contained matcher can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const { + if (Value) + return Value->isConvertibleTo(Kind, Specificity); + return false; } /// \brief Return this matcher as a \c Matcher<T>. @@ -122,10 +197,9 @@ public: /// Asserts that \c hasTypedMatcher<T>() is true. template <class T> ast_matchers::internal::Matcher<T> getTypedMatcher() const { - TypedMatcherOps<T> Ops; - Value->makeTypedMatcher(Ops); - assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false"); - return Ops.matcher(); + assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false"); + return Value->getTypedMatcher(TypedMatcherOps<T>()) + ->template convertTo<T>(); } /// \brief String representation of the type of the value. @@ -137,51 +211,25 @@ public: private: explicit VariantMatcher(Payload *Value) : Value(Value) {} + template <typename T> struct TypedMatcherOps; + class SinglePayload; class PolymorphicPayload; class VariadicOpPayload; - template <typename T> - class TypedMatcherOps : public MatcherOps { - public: - typedef ast_matchers::internal::Matcher<T> MatcherT; - - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const { - IsExactMatch = Matcher.getSupportedKind().isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind<T>()); - return Matcher.canConvertTo<T>(); - } - - virtual void constructFrom(const DynTypedMatcher& Matcher) { - Out.reset(new MatcherT(Matcher.convertTo<T>())); - } - - virtual void constructVariadicOperator( - ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef<VariantMatcher> InnerMatchers) { - std::vector<DynTypedMatcher> DynMatchers; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - // Abort if any of the inner matchers can't be converted to - // Matcher<T>. - if (!InnerMatchers[i].hasTypedMatcher<T>()) { - return; - } - DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>()); - } - Out.reset(new MatcherT( - new ast_matchers::internal::VariadicOperatorMatcherInterface<T>( - Func, DynMatchers))); - } - - bool hasMatcher() const { return Out.get() != nullptr; } - const MatcherT &matcher() const { return *Out; } + IntrusiveRefCntPtr<const Payload> Value; +}; - private: - std::unique_ptr<MatcherT> Out; - }; +template <typename T> +struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {} + typedef ast_matchers::internal::Matcher<T> MatcherT; - IntrusiveRefCntPtr<const Payload> Value; + DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const override { + return DynTypedMatcher(Matcher.convertTo<T>()); + } }; /// \brief Variant value class. @@ -228,6 +276,24 @@ public: const VariantMatcher &getMatcher() const; void setMatcher(const VariantMatcher &Matcher); + /// \brief Determines if the contained value can be converted to \p Kind. + /// + /// \param Kind the requested destination type. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. + bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const; + + /// \brief Determines if the contained value can be converted to any kind + /// in \p Kinds. + /// + /// \param Kinds the requested destination types. + /// + /// \param Specificity value corresponding to the "specificity" of the + /// convertion. It is the maximum specificity of all the possible + /// conversions. + bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const; + /// \brief String representation of the type of the value. std::string getTypeAsString() const; diff --git a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h index a61d9e47881d..cc14c7bd33db 100644 --- a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h +++ b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#ifndef CLANG_ANALYSIS_CFG_REACHABILITY -#define CLANG_ANALYSIS_CFG_REACHABILITY +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h index 36e07c21907b..a7109233987c 100644 --- a/include/clang/Analysis/Analyses/Consumed.h +++ b/include/clang/Analysis/Analyses/Consumed.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CONSUMED_H -#define LLVM_CLANG_CONSUMED_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h index 6c6d9238e5a9..fcef0fc10ac8 100644 --- a/include/clang/Analysis/Analyses/Dominators.h +++ b/include/clang/Analysis/Analyses/Dominators.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DOMINATORS_H -#define LLVM_CLANG_DOMINATORS_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 76fe9ddca6f8..174cce4f363c 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -16,8 +16,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_FORMAT_H -#define LLVM_CLANG_FORMAT_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H #include "clang/AST/CanonicalType.h" @@ -79,6 +79,7 @@ public: AsLongDouble, // 'L' AsAllocate, // for '%as', GNU extension to C90 scanf AsMAllocate, // for '%ms', GNU extension to scanf + AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z AsWideChar = AsLong // for '%ls', only makes sense for printf }; @@ -154,6 +155,8 @@ public: // ** Printf-specific ** + ZArg, // MS extension + // Objective-C specific specifiers. ObjCObjArg, // '@' ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, @@ -644,6 +647,9 @@ public: bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target); + +bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target); bool ParseScanfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 784227108ead..c29dd409e56c 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIVEVARIABLES_H -#define LLVM_CLANG_LIVEVARIABLES_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H #include "clang/AST/Decl.h" #include "clang/Analysis/AnalysisContext.h" diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h index 91bf51cd613f..a1c650427588 100644 --- a/include/clang/Analysis/Analyses/PostOrderCFGView.h +++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_POSTORDER_CFGVIEW -#define LLVM_CLANG_POSTORDER_CFGVIEW +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H #include <vector> //#include <algorithm> @@ -47,17 +47,17 @@ public: /// \brief Set the bit associated with a particular CFGBlock. /// This is the important method for the SetType template parameter. - bool insert(const CFGBlock *Block) { + std::pair<llvm::NoneType, bool> insert(const CFGBlock *Block) { // Note that insert() is called by po_iterator, which doesn't check to // make sure that Block is non-null. Moreover, the CFGBlock iterator will // occasionally hand out null pointers for pruned edges, so we catch those // here. if (!Block) - return false; // if an edge is trivially false. + return std::make_pair(None, false); // if an edge is trivially false. if (VisitedBlockIDs.test(Block->getBlockID())) - return false; + return std::make_pair(None, false); VisitedBlockIDs.set(Block->getBlockID()); - return true; + return std::make_pair(None, true); } /// \brief Check if the bit for a CFGBlock has been already set. diff --git a/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h b/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h index cb73850b08c7..c4ec2f22eca0 100644 --- a/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h +++ b/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS -#define LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_PSEUDOCONSTANTANALYSIS_H #include "clang/AST/Stmt.h" diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h index 90a6d014f58d..4c523bfc8b56 100644 --- a/include/clang/Analysis/Analyses/ReachableCode.h +++ b/include/clang/Analysis/Analyses/ReachableCode.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_REACHABLECODE_H -#define LLVM_CLANG_REACHABLECODE_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H #include "clang/Basic/SourceLocation.h" diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index b533c1db492e..458bb576f459 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -16,31 +16,33 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREADSAFETY_H -#define LLVM_CLANG_THREADSAFETY_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringRef.h" namespace clang { -namespace thread_safety { +namespace threadSafety { /// This enum distinguishes between different kinds of operations that may /// need to be protected by locks. We use this enum in error handling. enum ProtectedOperationKind { POK_VarDereference, ///< Dereferencing a variable (e.g. p in *p = 5;) POK_VarAccess, ///< Reading or writing a variable (e.g. x in x = 5;) - POK_FunctionCall ///< Making a function call (e.g. fool()) + POK_FunctionCall, ///< Making a function call (e.g. fool()) + POK_PassByRef, ///< Passing a guarded variable by reference. + POK_PtPassByRef, ///< Passing a pt-guarded variable by reference. }; /// This enum distinguishes between different kinds of lock actions. For /// example, it is an error to write a variable protected by shared version of a /// mutex. enum LockKind { - LK_Shared, ///< Shared/reader lock of a mutex. + LK_Shared, ///< Shared/reader lock of a mutex. LK_Exclusive, ///< Exclusive/writer lock of a mutex. - LK_Generic ///< Can be either Shared or Exclusive + LK_Generic ///< Can be either Shared or Exclusive }; /// This enum distinguishes between different ways to access (read or write) a @@ -161,6 +163,16 @@ public: LockKind LK, SourceLocation Loc, Name *PossibleMatch = nullptr) {} + /// Warn when acquiring a lock that the negative capability is not held. + /// \param Kind -- the capability's name parameter (role, mutex, etc). + /// \param LockName -- The name for the lock expression, to be printed in the + /// diagnostic. + /// \param Neg -- The name of the negative capability to be printed in the + /// diagnostic. + /// \param Loc -- The location of the protected operation. + virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, + SourceLocation Loc) {} + /// Warn when a function is called while an excluded mutex is locked. For /// example, the mutex may be locked inside the function. /// \param Kind -- the capability's name parameter (role, mutex, etc). @@ -171,6 +183,13 @@ public: virtual void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, SourceLocation Loc) {} + /// Called by the analysis when starting analysis of a function. + /// Used to issue suggestions for changes to annotations. + virtual void enterFunction(const FunctionDecl *FD) {} + + /// Called by the analysis when finishing analysis of a function. + virtual void leaveFunction(const FunctionDecl *FD) {} + bool issueBetaWarnings() { return IssueBetaWarnings; } void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; } @@ -190,5 +209,5 @@ void runThreadSafetyAnalysis(AnalysisDeclContext &AC, /// of access. LockKind getLockKindFromAccessKind(AccessKind AK); -}} // end namespace clang::thread_safety +}} // end namespace clang::threadSafety #endif diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 09c614ca3e36..be81121c102b 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -19,21 +19,63 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_COMMON_H -#define LLVM_CLANG_THREAD_SAFETY_COMMON_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H #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/Basic/OperatorKinds.h" - #include <memory> +#include <ostream> +#include <sstream> #include <vector> namespace clang { namespace threadSafety { + +// Various helper functions on til::SExpr +namespace sx { + +inline bool equals(const til::SExpr *E1, const til::SExpr *E2) { + return til::EqualsComparator::compareExprs(E1, E2); +} + +inline bool matches(const til::SExpr *E1, const til::SExpr *E2) { + // We treat a top-level wildcard as the "univsersal" lock. + // It matches everything for the purpose of checking locks, but not + // for unlocking them. + if (isa<til::Wildcard>(E1)) + return isa<til::Wildcard>(E2); + if (isa<til::Wildcard>(E2)) + return isa<til::Wildcard>(E1); + + return til::MatchComparator::compareExprs(E1, E2); +} + +inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) { + const auto *PE1 = dyn_cast_or_null<til::Project>(E1); + if (!PE1) + return false; + const auto *PE2 = dyn_cast_or_null<til::Project>(E2); + if (!PE2) + return false; + return PE1->clangDecl() == PE2->clangDecl(); +} + +inline std::string toString(const til::SExpr *E) { + std::stringstream ss; + til::StdPrinter::print(E, ss); + return ss.str(); +} + +} // end namespace sx + + + // This class defines the interface of a clang CFG Visitor. // CFGWalker will invoke the following methods. // Note that methods are not virtual; the visitor is templatized. @@ -206,6 +248,59 @@ private: }; + + +class CapabilityExpr { + // TODO: move this back into ThreadSafety.cpp + // This is specific to thread safety. It is here because + // translateAttrExpr needs it, but that should be moved too. + +private: + const til::SExpr* CapExpr; ///< The capability expression. + bool Negated; ///< True if this is a negative capability + +public: + CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {} + + const til::SExpr* sexpr() const { return CapExpr; } + bool negative() const { return Negated; } + + CapabilityExpr operator!() const { + return CapabilityExpr(CapExpr, !Negated); + } + + bool equals(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr); + } + + bool matches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr); + } + + bool matchesUniv(const CapabilityExpr &CapE) const { + return isUniversal() || matches(CapE); + } + + bool partiallyMatches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && + sx::partiallyMatches(CapExpr, other.CapExpr); + } + + std::string toString() const { + if (Negated) + return "!" + sx::toString(CapExpr); + return sx::toString(CapExpr); + } + + bool shouldIgnore() const { return CapExpr == nullptr; } + + bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); } + + bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); } +}; + + + // Translate clang::Expr to til::SExpr. class SExprBuilder { public: @@ -219,18 +314,16 @@ public: /// should be evaluated; multiple calling contexts can be chained together /// by the lock_returned attribute. struct CallingContext { + CallingContext *Prev; // The previous context; or 0 if none. const NamedDecl *AttrDecl; // The decl to which the attr is attached. const Expr *SelfArg; // Implicit object argument -- e.g. 'this' unsigned NumArgs; // Number of funArgs const Expr *const *FunArgs; // Function arguments - CallingContext *Prev; // The previous context; or 0 if none. bool SelfArrow; // is Self referred to with -> or .? - CallingContext(const NamedDecl *D = nullptr, const Expr *S = nullptr, - unsigned N = 0, const Expr *const *A = nullptr, - CallingContext *P = nullptr) - : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P), - SelfArrow(false) + CallingContext(CallingContext *P, const NamedDecl *D = nullptr) + : Prev(P), AttrDecl(D), SelfArg(nullptr), + NumArgs(0), FunArgs(nullptr), SelfArrow(false) {} }; @@ -242,6 +335,13 @@ public: SelfVar->setKind(til::Variable::VK_SFun); } + // Translate a clang expression in an attribute to a til::SExpr. + // Constructs the context from D, DeclExp, and SelfDecl. + CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D, + const Expr *DeclExp, VarDecl *SelfD=nullptr); + + CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx); + // Translate a clang statement or expression to a TIL expression. // Also performs substitution of variables; Ctx provides the context. // Dispatches on the type of S. @@ -262,7 +362,8 @@ private: CallingContext *Ctx) ; til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx); til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx); - til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx); + til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx, + const Expr *SelfE = nullptr); til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME, CallingContext *Ctx); til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE, @@ -280,10 +381,8 @@ private: til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx); til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E, CallingContext *Ctx); - til::SExpr *translateConditionalOperator(const ConditionalOperator *C, - CallingContext *Ctx); - til::SExpr *translateBinaryConditionalOperator( - const BinaryConditionalOperator *C, CallingContext *Ctx); + til::SExpr *translateAbstractConditionalOperator( + const AbstractConditionalOperator *C, CallingContext *Ctx); til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx); @@ -362,21 +461,24 @@ private: void mergePhiNodesBackEdge(const CFGBlock *Blk); private: + // Set to true when parsing capability expressions, which get translated + // inaccurately in order to hack around smart pointers etc. + static const bool CapabilityExprMode = true; + til::MemRegionRef Arena; til::Variable *SelfVar; // Variable to use for 'this'. May be null. - til::SCFG *Scfg; + til::SCFG *Scfg; StatementMap SMap; // Map from Stmt to TIL Variables LVarIndexMap LVarIdxMap; // Indices of clang local vars. std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs. std::vector<BlockInfo> BBInfo; // Extra information per BB. // Indexed by clang BlockID. - std::unique_ptr<SExprBuilder::CallingContext> CallCtx; // Root calling context LVarDefinitionMap CurrentLVarMap; - std::vector<til::Variable*> CurrentArguments; - std::vector<til::Variable*> CurrentInstructions; - std::vector<til::Variable*> IncompleteArgs; + std::vector<til::Phi*> CurrentArguments; + std::vector<til::SExpr*> CurrentInstructions; + std::vector<til::Phi*> IncompleteArgs; til::BasicBlock *CurrentBB; BlockInfo *CurrentBlockInfo; }; diff --git a/include/clang/Analysis/Analyses/ThreadSafetyLogical.h b/include/clang/Analysis/Analyses/ThreadSafetyLogical.h index c4f4b21aab12..bc78021343a4 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyLogical.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyLogical.h @@ -10,8 +10,8 @@ // that are used as part of fact-checking capability expressions. //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_LOGICAL_H -#define LLVM_CLANG_THREAD_SAFETY_LOGICAL_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" @@ -41,13 +41,13 @@ private: }; class Terminal : public LExpr { - til::SExprRef Expr; + til::SExpr *Expr; public: Terminal(til::SExpr *Expr) : LExpr(LExpr::Terminal), Expr(Expr) {} - const til::SExpr *expr() const { return Expr.get(); } - til::SExpr *expr() { return Expr.get(); } + const til::SExpr *expr() const { return Expr; } + til::SExpr *expr() { return Expr; } static bool classof(const LExpr *E) { return E->kind() == LExpr::Terminal; } }; @@ -104,5 +104,5 @@ bool LExpr::implies(const LExpr *RHS) const { } } -#endif // LLVM_CLANG_THREAD_SAFETY_LOGICAL_H +#endif diff --git a/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/include/clang/Analysis/Analyses/ThreadSafetyOps.def index 6ebc95dbe9a7..0d2458b0c893 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyOps.def +++ b/include/clang/Analysis/Analyses/ThreadSafetyOps.def @@ -44,8 +44,11 @@ TIL_OPCODE_DEF(Cast) TIL_OPCODE_DEF(SCFG) TIL_OPCODE_DEF(BasicBlock) TIL_OPCODE_DEF(Phi) + +// Terminator instructions TIL_OPCODE_DEF(Goto) TIL_OPCODE_DEF(Branch) +TIL_OPCODE_DEF(Return) // pseudo-terms TIL_OPCODE_DEF(Identifier) diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 8e4299ea70e8..2cd8c6d6d2d6 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -44,17 +44,16 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H -#define LLVM_CLANG_THREAD_SAFETY_TIL_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H // All clang include dependencies for this file must be put in // ThreadSafetyUtil.h. #include "ThreadSafetyUtil.h" - -#include <stdint.h> #include <algorithm> #include <cassert> #include <cstddef> +#include <stdint.h> #include <utility> @@ -63,24 +62,27 @@ namespace threadSafety { namespace til { +/// Enum for the different distinct classes of SExpr enum TIL_Opcode { #define TIL_OPCODE_DEF(X) COP_##X, #include "ThreadSafetyOps.def" #undef TIL_OPCODE_DEF }; +/// Opcode for unary arithmetic operations. enum TIL_UnaryOpcode : unsigned char { UOP_Minus, // - UOP_BitNot, // ~ UOP_LogicNot // ! }; +/// Opcode for binary arithmetic operations. enum TIL_BinaryOpcode : unsigned char { + BOP_Add, // + + BOP_Sub, // - BOP_Mul, // * BOP_Div, // / BOP_Rem, // % - BOP_Add, // + - BOP_Sub, // - BOP_Shl, // << BOP_Shr, // >> BOP_BitAnd, // & @@ -90,37 +92,42 @@ enum TIL_BinaryOpcode : unsigned char { BOP_Neq, // != BOP_Lt, // < BOP_Leq, // <= - BOP_LogicAnd, // && - BOP_LogicOr // || + BOP_LogicAnd, // && (no short-circuit) + BOP_LogicOr // || (no short-circuit) }; +/// Opcode for cast operations. enum TIL_CastOpcode : unsigned char { CAST_none = 0, CAST_extendNum, // extend precision of numeric type CAST_truncNum, // truncate precision of numeric type CAST_toFloat, // convert to floating point type CAST_toInt, // convert to integer type + CAST_objToPtr // convert smart pointer to pointer (C++ only) }; const TIL_Opcode COP_Min = COP_Future; const TIL_Opcode COP_Max = COP_Branch; const TIL_UnaryOpcode UOP_Min = UOP_Minus; const TIL_UnaryOpcode UOP_Max = UOP_LogicNot; -const TIL_BinaryOpcode BOP_Min = BOP_Mul; +const TIL_BinaryOpcode BOP_Min = BOP_Add; const TIL_BinaryOpcode BOP_Max = BOP_LogicOr; const TIL_CastOpcode CAST_Min = CAST_none; const TIL_CastOpcode CAST_Max = CAST_toInt; +/// Return the name of a unary opcode. StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op); + +/// Return the name of a binary opcode. StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op); -// ValueTypes are data types that can actually be held in registers. -// All variables and expressions must have a vBNF_Nonealue type. -// Pointer types are further subdivided into the various heap-allocated -// types, such as functions, records, etc. -// Structured types that are passed by value (e.g. complex numbers) -// require special handling; they use BT_ValueRef, and size ST_0. +/// ValueTypes are data types that can actually be held in registers. +/// All variables and expressions must have a value type. +/// Pointer types are further subdivided into the various heap-allocated +/// types, such as functions, records, etc. +/// Structured types that are passed by value (e.g. complex numbers) +/// require special handling; they use BT_ValueRef, and size ST_0. struct ValueType { enum BaseType : unsigned char { BT_Void = 0, @@ -246,8 +253,10 @@ inline ValueType ValueType::getValueType<void*>() { } +class BasicBlock; + -// Base class for AST nodes in the typed intermediate language. +/// Base class for AST nodes in the typed intermediate language. class SExpr { public: TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); } @@ -266,71 +275,47 @@ public: // template <class C> typename C::CType compare(CType* E, C& Cmp) { // compare all subexpressions, following the comparator interface // } - void *operator new(size_t S, MemRegionRef &R) { return ::operator new(S, R); } - // SExpr objects cannot be deleted. + /// SExpr objects cannot be deleted. // This declaration is public to workaround a gcc bug that breaks building // with REQUIRES_EH=1. void operator delete(void *) LLVM_DELETED_FUNCTION; + /// Returns the instruction ID for this expression. + /// All basic block instructions have a unique ID (i.e. virtual register). + unsigned id() const { return SExprID; } + + /// Returns the block, if this is an instruction in a basic block, + /// otherwise returns null. + BasicBlock* block() const { return Block; } + + /// Set the basic block and instruction ID for this expression. + void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; } + protected: - SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {} - SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {} + SExpr(TIL_Opcode Op) + : Opcode(Op), Reserved(0), Flags(0), SExprID(0), Block(nullptr) {} + SExpr(const SExpr &E) + : Opcode(E.Opcode), Reserved(0), Flags(E.Flags), SExprID(0), + Block(nullptr) {} const unsigned char Opcode; unsigned char Reserved; unsigned short Flags; + unsigned SExprID; + BasicBlock* Block; private: SExpr() LLVM_DELETED_FUNCTION; - // SExpr objects must be created in an arena. + /// SExpr objects must be created in an arena. void *operator new(size_t) LLVM_DELETED_FUNCTION; }; -// Class for owning references to SExprs. -// Includes attach/detach logic for counting variable references and lazy -// rewriting strategies. -class SExprRef { -public: - SExprRef() : Ptr(nullptr) { } - SExprRef(std::nullptr_t P) : Ptr(nullptr) { } - SExprRef(SExprRef &&R) : Ptr(R.Ptr) { R.Ptr = nullptr; } - - // Defined after Variable and Future, below. - inline SExprRef(SExpr *P); - inline ~SExprRef(); - - SExpr *get() { return Ptr; } - const SExpr *get() const { return Ptr; } - - SExpr *operator->() { return get(); } - const SExpr *operator->() const { return get(); } - - SExpr &operator*() { return *Ptr; } - const SExpr &operator*() const { return *Ptr; } - - bool operator==(const SExprRef &R) const { return Ptr == R.Ptr; } - bool operator!=(const SExprRef &R) const { return !operator==(R); } - bool operator==(const SExpr *P) const { return Ptr == P; } - bool operator!=(const SExpr *P) const { return !operator==(P); } - bool operator==(std::nullptr_t) const { return Ptr == nullptr; } - bool operator!=(std::nullptr_t) const { return Ptr != nullptr; } - - inline void reset(SExpr *E); - -private: - inline void attach(); - inline void detach(); - - SExpr *Ptr; -}; - - // Contains various helper functions for SExprs. namespace ThreadSafetyTIL { inline bool isTrivial(const SExpr *E) { @@ -342,62 +327,64 @@ namespace ThreadSafetyTIL { // Nodes which declare variables class Function; class SFunction; -class BasicBlock; class Let; -// A named variable, e.g. "x". -// -// There are two distinct places in which a Variable can appear in the AST. -// A variable declaration introduces a new variable, and can occur in 3 places: -// Let-expressions: (Let (x = t) u) -// Functions: (Function (x : t) u) -// Self-applicable functions (SFunction (x) t) -// -// If a variable occurs in any other location, it is a reference to an existing -// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't -// allocate a separate AST node for variable references; a reference is just a -// pointer to the original declaration. +/// A named variable, e.g. "x". +/// +/// There are two distinct places in which a Variable can appear in the AST. +/// A variable declaration introduces a new variable, and can occur in 3 places: +/// Let-expressions: (Let (x = t) u) +/// Functions: (Function (x : t) u) +/// Self-applicable functions (SFunction (x) t) +/// +/// If a variable occurs in any other location, it is a reference to an existing +/// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't +/// allocate a separate AST node for variable references; a reference is just a +/// pointer to the original declaration. class Variable : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; } - // Let-variable, function parameter, or self-variable enum VariableKind { - VK_Let, - VK_LetBB, - VK_Fun, - VK_SFun + VK_Let, ///< Let-variable + VK_Fun, ///< Function parameter + VK_SFun ///< SFunction (self) parameter }; - // These are defined after SExprRef contructor, below - inline Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr); - inline Variable(StringRef s, SExpr *D = nullptr); - inline Variable(const Variable &Vd, SExpr *D); + Variable(StringRef s, SExpr *D = nullptr) + : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr) { + Flags = VK_Let; + } + Variable(SExpr *D, const clang::ValueDecl *Cvd = nullptr) + : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"), + Definition(D), Cvdecl(Cvd) { + Flags = VK_Let; + } + Variable(const Variable &Vd, SExpr *D) // rewrite constructor + : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) { + Flags = Vd.kind(); + } + /// Return the kind of variable (let, function param, or self) VariableKind kind() const { return static_cast<VariableKind>(Flags); } - const StringRef name() const { return Name; } - const clang::ValueDecl *clangDecl() const { return Cvdecl; } - - // Returns the definition (for let vars) or type (for parameter & self vars) - SExpr *definition() { return Definition.get(); } - const SExpr *definition() const { return Definition.get(); } + /// Return the name of the variable, if any. + StringRef name() const { return Name; } - void attachVar() const { ++NumUses; } - void detachVar() const { assert(NumUses > 0); --NumUses; } + /// Return the clang declaration for this variable, if any. + const clang::ValueDecl *clangDecl() const { return Cvdecl; } - unsigned getID() const { return Id; } - unsigned getBlockID() const { return BlockID; } + /// Return the definition of the variable. + /// For let-vars, this is the setting expression. + /// For function and self parameters, it is the type of the variable. + SExpr *definition() { return Definition; } + const SExpr *definition() const { return Definition; } - void setName(StringRef S) { Name = S; } - void setID(unsigned Bid, unsigned I) { - BlockID = static_cast<unsigned short>(Bid); - Id = static_cast<unsigned short>(I); - } - void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; } - void setDefinition(SExpr *E); + void setName(StringRef S) { Name = S; } void setKind(VariableKind K) { Flags = K; } + void setDefinition(SExpr *E) { Definition = E; } + void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -405,7 +392,8 @@ public: return Vs.reduceVariableRef(this); } - template <class C> typename C::CType compare(Variable* E, C& Cmp) { + template <class C> + typename C::CType compare(const Variable* E, C& Cmp) const { return Cmp.compareVariableRefs(this, E); } @@ -416,17 +404,13 @@ private: friend class Let; StringRef Name; // The name of the variable. - SExprRef Definition; // The TIL type or definition + SExpr* Definition; // The TIL type or definition const clang::ValueDecl *Cvdecl; // The clang declaration for this variable. - - unsigned short BlockID; - unsigned short Id; - mutable unsigned NumUses; }; -// Placeholder for an expression that has not yet been created. -// Used to implement lazy copy and rewriting strategies. +/// Placeholder for an expression that has not yet been created. +/// Used to implement lazy copy and rewriting strategies. class Future : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Future; } @@ -437,25 +421,17 @@ public: FS_done }; - Future() : - SExpr(COP_Future), Status(FS_pending), Result(nullptr), Location(nullptr) - {} + Future() : SExpr(COP_Future), Status(FS_pending), Result(nullptr) {} + private: virtual ~Future() LLVM_DELETED_FUNCTION; -public: - - // Registers the location in the AST where this future is stored. - // Forcing the future will automatically update the AST. - static inline void registerLocation(SExprRef *Member) { - if (Future *F = dyn_cast_or_null<Future>(Member->get())) - F->Location = Member; - } +public: // A lazy rewriting strategy should subclass Future and override this method. - virtual SExpr *create() { return nullptr; } + virtual SExpr *compute() { return nullptr; } // Return the result of this future if it exists, otherwise return null. - SExpr *maybeGetResult() { + SExpr *maybeGetResult() const { return Result; } @@ -463,8 +439,7 @@ public: SExpr *result() { switch (Status) { case FS_pending: - force(); - return Result; + return force(); case FS_evaluating: return nullptr; // infinite loop; illegal recursion. case FS_done: @@ -478,88 +453,22 @@ public: return Vs.traverse(Result, Ctx); } - template <class C> typename C::CType compare(Future* E, C& Cmp) { + template <class C> + typename C::CType compare(const Future* E, C& Cmp) const { if (!Result || !E->Result) return Cmp.comparePointers(this, E); return Cmp.compare(Result, E->Result); } private: - // Force the future. - inline void force(); + SExpr* force(); FutureStatus Status; SExpr *Result; - SExprRef *Location; }; -inline void SExprRef::attach() { - if (!Ptr) - return; - - TIL_Opcode Op = Ptr->opcode(); - if (Op == COP_Variable) { - cast<Variable>(Ptr)->attachVar(); - } else if (Op == COP_Future) { - cast<Future>(Ptr)->registerLocation(this); - } -} - -inline void SExprRef::detach() { - if (Ptr && Ptr->opcode() == COP_Variable) { - cast<Variable>(Ptr)->detachVar(); - } -} - -inline SExprRef::SExprRef(SExpr *P) : Ptr(P) { - attach(); -} - -inline SExprRef::~SExprRef() { - detach(); -} - -inline void SExprRef::reset(SExpr *P) { - detach(); - Ptr = P; - attach(); -} - - -inline Variable::Variable(StringRef s, SExpr *D) - : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr), - BlockID(0), Id(0), NumUses(0) { - Flags = VK_Let; -} - -inline Variable::Variable(SExpr *D, const clang::ValueDecl *Cvd) - : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"), - Definition(D), Cvdecl(Cvd), BlockID(0), Id(0), NumUses(0) { - Flags = VK_Let; -} - -inline Variable::Variable(const Variable &Vd, SExpr *D) // rewrite constructor - : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl), - BlockID(0), Id(0), NumUses(0) { - Flags = Vd.kind(); -} - -inline void Variable::setDefinition(SExpr *E) { - Definition.reset(E); -} - -void Future::force() { - Status = FS_evaluating; - SExpr *R = create(); - Result = R; - if (Location) - Location->reset(R); - Status = FS_done; -} - - -// Placeholder for C++ expressions that cannot be represented in the TIL. +/// Placeholder for expressions that cannot be represented in the TIL. class Undefined : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; } @@ -572,8 +481,9 @@ public: return Vs.reduceUndefined(*this); } - template <class C> typename C::CType compare(Undefined* E, C& Cmp) { - return Cmp.comparePointers(Cstmt, E->Cstmt); + template <class C> + typename C::CType compare(const Undefined* E, C& Cmp) const { + return Cmp.trueResult(); } private: @@ -581,7 +491,7 @@ private: }; -// Placeholder for a wildcard that matches any other expression. +/// Placeholder for a wildcard that matches any other expression. class Wildcard : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; } @@ -593,7 +503,8 @@ public: return Vs.reduceWildcard(*this); } - template <class C> typename C::CType compare(Wildcard* E, C& Cmp) { + template <class C> + typename C::CType compare(const Wildcard* E, C& Cmp) const { return Cmp.trueResult(); } }; @@ -626,9 +537,10 @@ public: template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx); - template <class C> typename C::CType compare(Literal* E, C& Cmp) { - // TODO -- use value, not pointer equality - return Cmp.comparePointers(Cexpr, E->Cexpr); + template <class C> + typename C::CType compare(const Literal* E, C& Cmp) const { + // TODO: defer actual comparison to LiteralT + return Cmp.trueResult(); } private: @@ -710,8 +622,8 @@ typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) { } -// Literal pointer to an object allocated in memory. -// At compile time, pointer literals are represented by symbolic names. +/// A Literal pointer to an object allocated in memory. +/// At compile time, pointer literals are represented by symbolic names. class LiteralPtr : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; } @@ -727,7 +639,8 @@ public: return Vs.reduceLiteralPtr(*this); } - template <class C> typename C::CType compare(LiteralPtr* E, C& Cmp) { + template <class C> + typename C::CType compare(const LiteralPtr* E, C& Cmp) const { return Cmp.comparePointers(Cvdecl, E->Cvdecl); } @@ -736,9 +649,9 @@ private: }; -// A function -- a.k.a. lambda abstraction. -// Functions with multiple arguments are created by currying, -// e.g. (function (x: Int) (function (y: Int) (add x y))) +/// A function -- a.k.a. lambda abstraction. +/// Functions with multiple arguments are created by currying, +/// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y }))) class Function : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Function; } @@ -755,8 +668,8 @@ public: Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } - SExpr *body() { return Body.get(); } - const SExpr *body() const { return Body.get(); } + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -769,7 +682,8 @@ public: return Vs.reduceFunction(*this, Nvd, E1); } - template <class C> typename C::CType compare(Function* E, C& Cmp) { + template <class C> + typename C::CType compare(const Function* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(VarDecl->definition(), E->VarDecl->definition()); if (Cmp.notTrue(Ct)) @@ -782,13 +696,13 @@ public: private: Variable *VarDecl; - SExprRef Body; + SExpr* Body; }; -// A self-applicable function. -// A self-applicable function can be applied to itself. It's useful for -// implementing objects and late binding +/// A self-applicable function. +/// A self-applicable function can be applied to itself. It's useful for +/// implementing objects and late binding. class SFunction : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; } @@ -797,20 +711,20 @@ public: : SExpr(COP_SFunction), VarDecl(Vd), Body(B) { assert(Vd->Definition == nullptr); Vd->setKind(Variable::VK_SFun); - Vd->Definition.reset(this); + Vd->Definition = this; } SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor : SExpr(F), VarDecl(Vd), Body(B) { assert(Vd->Definition == nullptr); Vd->setKind(Variable::VK_SFun); - Vd->Definition.reset(this); + Vd->Definition = this; } Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } - SExpr *body() { return Body.get(); } - const SExpr *body() const { return Body.get(); } + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -824,7 +738,8 @@ public: return Vs.reduceSFunction(*this, Nvd, E1); } - template <class C> typename C::CType compare(SFunction* E, C& Cmp) { + template <class C> + typename C::CType compare(const SFunction* E, C& Cmp) const { Cmp.enterScope(variableDecl(), E->variableDecl()); typename C::CType Ct = Cmp.compare(body(), E->body()); Cmp.leaveScope(); @@ -833,11 +748,11 @@ public: private: Variable *VarDecl; - SExprRef Body; + SExpr* Body; }; -// A block of code -- e.g. the body of a function. +/// A block of code -- e.g. the body of a function. class Code : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Code; } @@ -846,11 +761,11 @@ public: Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor : SExpr(C), ReturnType(T), Body(B) {} - SExpr *returnType() { return ReturnType.get(); } - const SExpr *returnType() const { return ReturnType.get(); } + SExpr *returnType() { return ReturnType; } + const SExpr *returnType() const { return ReturnType; } - SExpr *body() { return Body.get(); } - const SExpr *body() const { return Body.get(); } + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -859,7 +774,8 @@ public: return Vs.reduceCode(*this, Nt, Nb); } - template <class C> typename C::CType compare(Code* E, C& Cmp) { + template <class C> + typename C::CType compare(const Code* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(returnType(), E->returnType()); if (Cmp.notTrue(Ct)) return Ct; @@ -867,12 +783,12 @@ public: } private: - SExprRef ReturnType; - SExprRef Body; + SExpr* ReturnType; + SExpr* Body; }; -// A typed, writable location in memory +/// A typed, writable location in memory class Field : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Field; } @@ -881,11 +797,11 @@ public: Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor : SExpr(C), Range(R), Body(B) {} - SExpr *range() { return Range.get(); } - const SExpr *range() const { return Range.get(); } + SExpr *range() { return Range; } + const SExpr *range() const { return Range; } - SExpr *body() { return Body.get(); } - const SExpr *body() const { return Body.get(); } + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -894,7 +810,8 @@ public: return Vs.reduceField(*this, Nr, Nb); } - template <class C> typename C::CType compare(Field* E, C& Cmp) { + template <class C> + typename C::CType compare(const Field* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(range(), E->range()); if (Cmp.notTrue(Ct)) return Ct; @@ -902,12 +819,16 @@ public: } private: - SExprRef Range; - SExprRef Body; + SExpr* Range; + SExpr* Body; }; -// Apply an argument to a function +/// Apply an argument to a function. +/// Note that this does not actually call the function. Functions are curried, +/// so this returns a closure in which the first parameter has been applied. +/// Once all parameters have been applied, Call can be used to invoke the +/// function. class Apply : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; } @@ -917,11 +838,11 @@ public: : SExpr(A), Fun(F), Arg(Ar) {} - SExpr *fun() { return Fun.get(); } - const SExpr *fun() const { return Fun.get(); } + SExpr *fun() { return Fun; } + const SExpr *fun() const { return Fun; } - SExpr *arg() { return Arg.get(); } - const SExpr *arg() const { return Arg.get(); } + SExpr *arg() { return Arg; } + const SExpr *arg() const { return Arg; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -930,7 +851,8 @@ public: return Vs.reduceApply(*this, Nf, Na); } - template <class C> typename C::CType compare(Apply* E, C& Cmp) { + template <class C> + typename C::CType compare(const Apply* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(fun(), E->fun()); if (Cmp.notTrue(Ct)) return Ct; @@ -938,12 +860,12 @@ public: } private: - SExprRef Fun; - SExprRef Arg; + SExpr* Fun; + SExpr* Arg; }; -// Apply a self-argument to a self-applicable function +/// Apply a self-argument to a self-applicable function. class SApply : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; } @@ -952,23 +874,24 @@ public: SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor : SExpr(A), Sfun(Sf), Arg(Ar) {} - SExpr *sfun() { return Sfun.get(); } - const SExpr *sfun() const { return Sfun.get(); } + SExpr *sfun() { return Sfun; } + const SExpr *sfun() const { return Sfun; } - SExpr *arg() { return Arg.get() ? Arg.get() : Sfun.get(); } - const SExpr *arg() const { return Arg.get() ? Arg.get() : Sfun.get(); } + SExpr *arg() { return Arg ? Arg : Sfun; } + const SExpr *arg() const { return Arg ? Arg : Sfun; } - bool isDelegation() const { return Arg == nullptr; } + bool isDelegation() const { return Arg != nullptr; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx)); - typename V::R_SExpr Na = Arg.get() ? Vs.traverse(Arg, Vs.subExprCtx(Ctx)) + typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx)) : nullptr; return Vs.reduceSApply(*this, Nf, Na); } - template <class C> typename C::CType compare(SApply* E, C& Cmp) { + template <class C> + typename C::CType compare(const SApply* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(sfun(), E->sfun()); if (Cmp.notTrue(Ct) || (!arg() && !E->arg())) return Ct; @@ -976,12 +899,12 @@ public: } private: - SExprRef Sfun; - SExprRef Arg; + SExpr* Sfun; + SExpr* Arg; }; -// Project a named slot from a C++ struct or class. +/// Project a named slot from a C++ struct or class. class Project : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Project; } @@ -989,17 +912,23 @@ public: Project(SExpr *R, StringRef SName) : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr) { } - Project(SExpr *R, clang::ValueDecl *Cvd) + 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 *record() { return Rec.get(); } - const SExpr *record() const { return Rec.get(); } + SExpr *record() { return Rec; } + const SExpr *record() const { return Rec; } + + const clang::ValueDecl *clangDecl() const { return Cvdecl; } - const clang::ValueDecl *clangValueDecl() const { return Cvdecl; } + bool isArrow() const { return (Flags & 0x01) != 0; } + void setArrow(bool b) { + if (b) Flags |= 0x01; + else Flags &= 0xFFFE; + } StringRef slotName() const { if (Cvdecl) @@ -1014,7 +943,8 @@ public: return Vs.reduceProject(*this, Nr); } - template <class C> typename C::CType compare(Project* E, C& Cmp) { + template <class C> + typename C::CType compare(const Project* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(record(), E->record()); if (Cmp.notTrue(Ct)) return Ct; @@ -1022,13 +952,13 @@ public: } private: - SExprRef Rec; + SExpr* Rec; StringRef SlotName; - clang::ValueDecl *Cvdecl; + const clang::ValueDecl *Cvdecl; }; -// Call a function (after all arguments have been applied). +/// Call a function (after all arguments have been applied). class Call : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } @@ -1037,8 +967,8 @@ public: : SExpr(COP_Call), Target(T), Cexpr(Ce) {} Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {} - SExpr *target() { return Target.get(); } - const SExpr *target() const { return Target.get(); } + SExpr *target() { return Target; } + const SExpr *target() const { return Target; } const clang::CallExpr *clangCallExpr() const { return Cexpr; } @@ -1048,17 +978,18 @@ public: return Vs.reduceCall(*this, Nt); } - template <class C> typename C::CType compare(Call* E, C& Cmp) { + template <class C> + typename C::CType compare(const Call* E, C& Cmp) const { return Cmp.compare(target(), E->target()); } private: - SExprRef Target; + SExpr* Target; const clang::CallExpr *Cexpr; }; -// Allocate memory for a new value on the heap or stack. +/// Allocate memory for a new value on the heap or stack. class Alloc : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Call; } @@ -1073,8 +1004,8 @@ public: AllocKind kind() const { return static_cast<AllocKind>(Flags); } - SExpr *dataType() { return Dtype.get(); } - const SExpr *dataType() const { return Dtype.get(); } + SExpr *dataType() { return Dtype; } + const SExpr *dataType() const { return Dtype; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1082,7 +1013,8 @@ public: return Vs.reduceAlloc(*this, Nd); } - template <class C> typename C::CType compare(Alloc* E, C& Cmp) { + template <class C> + typename C::CType compare(const Alloc* E, C& Cmp) const { typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind()); if (Cmp.notTrue(Ct)) return Ct; @@ -1090,11 +1022,11 @@ public: } private: - SExprRef Dtype; + SExpr* Dtype; }; -// Load a value from memory. +/// Load a value from memory. class Load : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Load; } @@ -1102,8 +1034,8 @@ public: Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {} Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {} - SExpr *pointer() { return Ptr.get(); } - const SExpr *pointer() const { return Ptr.get(); } + SExpr *pointer() { return Ptr; } + const SExpr *pointer() const { return Ptr; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1111,17 +1043,18 @@ public: return Vs.reduceLoad(*this, Np); } - template <class C> typename C::CType compare(Load* E, C& Cmp) { + template <class C> + typename C::CType compare(const Load* E, C& Cmp) const { return Cmp.compare(pointer(), E->pointer()); } private: - SExprRef Ptr; + SExpr* Ptr; }; -// Store a value to memory. -// Source is a pointer, destination is the value to store. +/// Store a value to memory. +/// The destination is a pointer to a field, the source is the value to store. class Store : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Store; } @@ -1129,11 +1062,11 @@ public: Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {} Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {} - SExpr *destination() { return Dest.get(); } // Address to store to - const SExpr *destination() const { return Dest.get(); } + SExpr *destination() { return Dest; } // Address to store to + const SExpr *destination() const { return Dest; } - SExpr *source() { return Source.get(); } // Value to store - const SExpr *source() const { return Source.get(); } + SExpr *source() { return Source; } // Value to store + const SExpr *source() const { return Source; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1142,7 +1075,8 @@ public: return Vs.reduceStore(*this, Np, Nv); } - template <class C> typename C::CType compare(Store* E, C& Cmp) { + template <class C> + typename C::CType compare(const Store* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(destination(), E->destination()); if (Cmp.notTrue(Ct)) return Ct; @@ -1150,13 +1084,13 @@ public: } private: - SExprRef Dest; - SExprRef Source; + SExpr* Dest; + SExpr* Source; }; -// If p is a reference to an array, then first(p) is a reference to the first -// element. The usual array notation p[i] becomes first(p + i). +/// If p is a reference to an array, then p[i] is a reference to the i'th +/// element of the array. class ArrayIndex : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; } @@ -1165,11 +1099,11 @@ public: ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N) : SExpr(E), Array(A), Index(N) {} - SExpr *array() { return Array.get(); } - const SExpr *array() const { return Array.get(); } + SExpr *array() { return Array; } + const SExpr *array() const { return Array; } - SExpr *index() { return Index.get(); } - const SExpr *index() const { return Index.get(); } + SExpr *index() { return Index; } + const SExpr *index() const { return Index; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1178,7 +1112,8 @@ public: return Vs.reduceArrayIndex(*this, Na, Ni); } - template <class C> typename C::CType compare(ArrayIndex* E, C& Cmp) { + template <class C> + typename C::CType compare(const ArrayIndex* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(array(), E->array()); if (Cmp.notTrue(Ct)) return Ct; @@ -1186,14 +1121,14 @@ public: } private: - SExprRef Array; - SExprRef Index; + SExpr* Array; + SExpr* Index; }; -// Pointer arithmetic, restricted to arrays only. -// If p is a reference to an array, then p + n, where n is an integer, is -// a reference to a subarray. +/// Pointer arithmetic, restricted to arrays only. +/// If p is a reference to an array, then p + n, where n is an integer, is +/// a reference to a subarray. class ArrayAdd : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; } @@ -1202,11 +1137,11 @@ public: ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N) : SExpr(E), Array(A), Index(N) {} - SExpr *array() { return Array.get(); } - const SExpr *array() const { return Array.get(); } + SExpr *array() { return Array; } + const SExpr *array() const { return Array; } - SExpr *index() { return Index.get(); } - const SExpr *index() const { return Index.get(); } + SExpr *index() { return Index; } + const SExpr *index() const { return Index; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1215,7 +1150,8 @@ public: return Vs.reduceArrayAdd(*this, Na, Ni); } - template <class C> typename C::CType compare(ArrayAdd* E, C& Cmp) { + template <class C> + typename C::CType compare(const ArrayAdd* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(array(), E->array()); if (Cmp.notTrue(Ct)) return Ct; @@ -1223,12 +1159,13 @@ public: } private: - SExprRef Array; - SExprRef Index; + SExpr* Array; + SExpr* Index; }; -// Simple unary operation -- e.g. !, ~, etc. +/// Simple arithmetic unary operations, e.g. negate and not. +/// These operations have no side-effects. class UnaryOp : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; } @@ -1242,8 +1179,8 @@ public: return static_cast<TIL_UnaryOpcode>(Flags); } - SExpr *expr() { return Expr0.get(); } - const SExpr *expr() const { return Expr0.get(); } + SExpr *expr() { return Expr0; } + const SExpr *expr() const { return Expr0; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1251,7 +1188,8 @@ public: return Vs.reduceUnaryOp(*this, Ne); } - template <class C> typename C::CType compare(UnaryOp* E, C& Cmp) { + template <class C> + typename C::CType compare(const UnaryOp* E, C& Cmp) const { typename C::CType Ct = Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode()); if (Cmp.notTrue(Ct)) @@ -1260,11 +1198,12 @@ public: } private: - SExprRef Expr0; + SExpr* Expr0; }; -// Simple binary operation -- e.g. +, -, etc. +/// Simple arithmetic binary operations, e.g. +, -, etc. +/// These operations have no side effects. class BinaryOp : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; } @@ -1282,11 +1221,11 @@ public: return static_cast<TIL_BinaryOpcode>(Flags); } - SExpr *expr0() { return Expr0.get(); } - const SExpr *expr0() const { return Expr0.get(); } + SExpr *expr0() { return Expr0; } + const SExpr *expr0() const { return Expr0; } - SExpr *expr1() { return Expr1.get(); } - const SExpr *expr1() const { return Expr1.get(); } + SExpr *expr1() { return Expr1; } + const SExpr *expr1() const { return Expr1; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1295,7 +1234,8 @@ public: return Vs.reduceBinaryOp(*this, Ne0, Ne1); } - template <class C> typename C::CType compare(BinaryOp* E, C& Cmp) { + template <class C> + typename C::CType compare(const BinaryOp* E, C& Cmp) const { typename C::CType Ct = Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode()); if (Cmp.notTrue(Ct)) @@ -1307,12 +1247,14 @@ public: } private: - SExprRef Expr0; - SExprRef Expr1; + SExpr* Expr0; + SExpr* Expr1; }; -// Cast expression +/// Cast expressions. +/// Cast expressions are essentially unary operations, but we treat them +/// as a distinct AST node because they only change the type of the result. class Cast : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; } @@ -1324,8 +1266,8 @@ public: return static_cast<TIL_CastOpcode>(Flags); } - SExpr *expr() { return Expr0.get(); } - const SExpr *expr() const { return Expr0.get(); } + SExpr *expr() { return Expr0; } + const SExpr *expr() const { return Expr0; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1333,7 +1275,8 @@ public: return Vs.reduceCast(*this, Ne); } - template <class C> typename C::CType compare(Cast* E, C& Cmp) { + template <class C> + typename C::CType compare(const Cast* E, C& Cmp) const { typename C::CType Ct = Cmp.compareIntegers(castOpcode(), E->castOpcode()); if (Cmp.notTrue(Ct)) @@ -1342,16 +1285,18 @@ public: } private: - SExprRef Expr0; + SExpr* Expr0; }; class SCFG; +/// Phi Node, for code in SSA form. +/// Each Phi node has an array of possible values that it can take, +/// depending on where control flow comes from. class Phi : public SExpr { public: - // TODO: change to SExprRef typedef SimpleArray<SExpr *> ValArray; // In minimal SSA form, all Phi nodes are MultiVal. @@ -1365,9 +1310,12 @@ public: static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; } - Phi() : SExpr(COP_Phi) {} - Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {} - Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {} + Phi() + : SExpr(COP_Phi), Cvdecl(nullptr) {} + Phi(MemRegionRef A, unsigned Nvals) + : SExpr(COP_Phi), Values(A, Nvals), Cvdecl(nullptr) {} + Phi(const Phi &P, ValArray &&Vs) + : SExpr(P), Values(std::move(Vs)), Cvdecl(nullptr) {} const ValArray &values() const { return Values; } ValArray &values() { return Values; } @@ -1375,6 +1323,12 @@ public: Status status() const { return static_cast<Status>(Flags); } void setStatus(Status s) { Flags = s; } + /// Return the clang declaration of the variable for this Phi node, if any. + const clang::ValueDecl *clangDecl() const { return Cvdecl; } + + /// Set the clang variable associated with this Phi node. + void setClangDecl(const clang::ValueDecl *Cvd) { Cvdecl = Cvd; } + template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { typename V::template Container<typename V::R_SExpr> @@ -1386,72 +1340,268 @@ public: return Vs.reducePhi(*this, Nvs); } - template <class C> typename C::CType compare(Phi *E, C &Cmp) { + template <class C> + typename C::CType compare(const Phi *E, C &Cmp) const { // TODO: implement CFG comparisons return Cmp.comparePointers(this, E); } private: ValArray Values; + const clang::ValueDecl* Cvdecl; +}; + + +/// Base class for basic block terminators: Branch, Goto, and Return. +class Terminator : public SExpr { +public: + static bool classof(const SExpr *E) { + return E->opcode() >= COP_Goto && E->opcode() <= COP_Return; + } + +protected: + Terminator(TIL_Opcode Op) : SExpr(Op) {} + Terminator(const SExpr &E) : SExpr(E) {} + +public: + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors(); + + ArrayRef<BasicBlock*> successors() const { + return const_cast<Terminator*>(this)->successors(); + } }; -// A basic block is part of an SCFG, and can be treated as a function in -// continuation passing style. It consists of a sequence of phi nodes, which -// are "arguments" to the function, followed by a sequence of instructions. -// Both arguments and instructions define new variables. It ends with a -// branch or goto to another basic block in the same SCFG. +/// Jump to another basic block. +/// A goto instruction is essentially a tail-recursive call into another +/// block. In addition to the block pointer, it specifies an index into the +/// phi nodes of that block. The index can be used to retrieve the "arguments" +/// of the call. +class Goto : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; } + + Goto(BasicBlock *B, unsigned I) + : Terminator(COP_Goto), TargetBlock(B), Index(I) {} + Goto(const Goto &G, BasicBlock *B, unsigned I) + : Terminator(COP_Goto), TargetBlock(B), Index(I) {} + + const BasicBlock *targetBlock() const { return TargetBlock; } + BasicBlock *targetBlock() { return TargetBlock; } + + /// Returns the index into the + unsigned index() const { return Index; } + + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors() { + return ArrayRef<BasicBlock*>(&TargetBlock, 1); + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock); + return Vs.reduceGoto(*this, Ntb); + } + + template <class C> + typename C::CType compare(const Goto *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + BasicBlock *TargetBlock; + unsigned Index; +}; + + +/// A conditional branch to two other blocks. +/// Note that unlike Goto, Branch does not have an index. The target blocks +/// must be child-blocks, and cannot have Phi nodes. +class Branch : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; } + + Branch(SExpr *C, BasicBlock *T, BasicBlock *E) + : Terminator(COP_Branch), Condition(C) { + Branches[0] = T; + Branches[1] = E; + } + Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E) + : Terminator(Br), Condition(C) { + Branches[0] = T; + Branches[1] = E; + } + + const SExpr *condition() const { return Condition; } + SExpr *condition() { return Condition; } + + const BasicBlock *thenBlock() const { return Branches[0]; } + BasicBlock *thenBlock() { return Branches[0]; } + + const BasicBlock *elseBlock() const { return Branches[1]; } + BasicBlock *elseBlock() { return Branches[1]; } + + /// Return the list of basic blocks that this terminator can branch to. + ArrayRef<BasicBlock*> successors() { + return ArrayRef<BasicBlock*>(Branches, 2); + } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx)); + BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]); + BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]); + return Vs.reduceBranch(*this, Nc, Ntb, Nte); + } + + template <class C> + typename C::CType compare(const Branch *E, C &Cmp) const { + // TODO: implement CFG comparisons + return Cmp.comparePointers(this, E); + } + +private: + SExpr* Condition; + BasicBlock *Branches[2]; +}; + + +/// Return from the enclosing function, passing the return value to the caller. +/// Only the exit block should end with a return statement. +class Return : public Terminator { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_Return; } + + Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {} + Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {} + + /// Return an empty list. + ArrayRef<BasicBlock*> successors() { + return ArrayRef<BasicBlock*>(); + } + + SExpr *returnValue() { return Retval; } + const SExpr *returnValue() const { return Retval; } + + template <class V> + typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { + auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx)); + return Vs.reduceReturn(*this, Ne); + } + + template <class C> + typename C::CType compare(const Return *E, C &Cmp) const { + return Cmp.compare(Retval, E->Retval); + } + +private: + SExpr* Retval; +}; + + +inline ArrayRef<BasicBlock*> Terminator::successors() { + switch (opcode()) { + case COP_Goto: return cast<Goto>(this)->successors(); + case COP_Branch: return cast<Branch>(this)->successors(); + case COP_Return: return cast<Return>(this)->successors(); + default: + return ArrayRef<BasicBlock*>(); + } +} + + +/// A basic block is part of an SCFG. It can be treated as a function in +/// continuation passing style. A block consists of a sequence of phi nodes, +/// which are "arguments" to the function, followed by a sequence of +/// instructions. It ends with a Terminator, which is a Branch or Goto to +/// another basic block in the same SCFG. class BasicBlock : public SExpr { public: - typedef SimpleArray<Variable*> VarArray; + typedef SimpleArray<SExpr*> InstrArray; typedef SimpleArray<BasicBlock*> BlockArray; + // TopologyNodes are used to overlay tree structures on top of the CFG, + // such as dominator and postdominator trees. Each block is assigned an + // ID in the tree according to a depth-first search. Tree traversals are + // always up, towards the parents. + struct TopologyNode { + TopologyNode() : NodeID(0), SizeOfSubTree(0), Parent(nullptr) {} + + bool isParentOf(const TopologyNode& OtherNode) { + return OtherNode.NodeID > NodeID && + OtherNode.NodeID < NodeID + SizeOfSubTree; + } + + bool isParentOfOrEqual(const TopologyNode& OtherNode) { + return OtherNode.NodeID >= NodeID && + OtherNode.NodeID < NodeID + SizeOfSubTree; + } + + int NodeID; + int SizeOfSubTree; // Includes this node, so must be > 1. + BasicBlock *Parent; // Pointer to parent. + }; + static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; } - explicit BasicBlock(MemRegionRef A, BasicBlock* P = nullptr) + explicit BasicBlock(MemRegionRef A) : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0), - Parent(P), Terminator(nullptr) - { } - BasicBlock(BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T) - : SExpr(COP_BasicBlock), Arena(B.Arena), CFGPtr(nullptr), BlockID(0), - Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)), - Terminator(T) - { } + Visited(0), TermInstr(nullptr) {} + BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is, + Terminator *T) + : SExpr(COP_BasicBlock), Arena(A), CFGPtr(nullptr), BlockID(0),Visited(0), + Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {} + + /// Returns the block ID. Every block has a unique ID in the CFG. + int blockID() const { return BlockID; } - unsigned blockID() const { return BlockID; } - unsigned numPredecessors() const { return Predecessors.size(); } + /// Returns the number of predecessors. + size_t numPredecessors() const { return Predecessors.size(); } + size_t numSuccessors() const { return successors().size(); } const SCFG* cfg() const { return CFGPtr; } SCFG* cfg() { return CFGPtr; } - const BasicBlock *parent() const { return Parent; } - BasicBlock *parent() { return Parent; } + const BasicBlock *parent() const { return DominatorNode.Parent; } + BasicBlock *parent() { return DominatorNode.Parent; } - const VarArray &arguments() const { return Args; } - VarArray &arguments() { return Args; } + const InstrArray &arguments() const { return Args; } + InstrArray &arguments() { return Args; } - const VarArray &instructions() const { return Instrs; } - VarArray &instructions() { return Instrs; } + InstrArray &instructions() { return Instrs; } + const InstrArray &instructions() const { return Instrs; } - const BlockArray &predecessors() const { return Predecessors; } + /// Returns a list of predecessors. + /// The order of predecessors in the list is important; each phi node has + /// exactly one argument for each precessor, in the same order. BlockArray &predecessors() { return Predecessors; } + const BlockArray &predecessors() const { return Predecessors; } + + ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); } + ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); } + + const Terminator *terminator() const { return TermInstr; } + Terminator *terminator() { return TermInstr; } - const SExpr *terminator() const { return Terminator.get(); } - SExpr *terminator() { return Terminator.get(); } + void setTerminator(Terminator *E) { TermInstr = E; } - void setBlockID(unsigned i) { BlockID = i; } - void setParent(BasicBlock *P) { Parent = P; } - void setTerminator(SExpr *E) { Terminator.reset(E); } + bool Dominates(const BasicBlock &Other) { + return DominatorNode.isParentOfOrEqual(Other.DominatorNode); + } + + bool PostDominates(const BasicBlock &Other) { + return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode); + } - // Add a new argument. V must define a phi-node. - void addArgument(Variable *V) { - V->setKind(Variable::VK_LetBB); + /// Add a new argument. + void addArgument(Phi *V) { Args.reserveCheck(1, Arena); Args.push_back(V); } - // Add a new instruction. - void addInstruction(Variable *V) { - V->setKind(Variable::VK_LetBB); + /// Add a new instruction. + void addInstruction(SExpr *V) { Instrs.reserveCheck(1, Arena); Instrs.push_back(V); } @@ -1468,34 +1618,29 @@ public: // Reserve space for NumPreds predecessors, including space in phi nodes. void reservePredecessors(unsigned NumPreds); - // Return the index of BB, or Predecessors.size if BB is not a predecessor. + /// Return the index of BB, or Predecessors.size if BB is not a predecessor. unsigned findPredecessorIndex(const BasicBlock *BB) const { auto I = std::find(Predecessors.cbegin(), Predecessors.cend(), BB); return std::distance(Predecessors.cbegin(), I); } - // Set id numbers for variables. - void renumberVars(); - template <class V> typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) { - typename V::template Container<Variable*> Nas(Vs, Args.size()); - typename V::template Container<Variable*> Nis(Vs, Instrs.size()); + typename V::template Container<SExpr*> Nas(Vs, Args.size()); + typename V::template Container<SExpr*> Nis(Vs, Instrs.size()); // Entering the basic block should do any scope initialization. Vs.enterBasicBlock(*this); - for (auto *A : Args) { - auto Ne = Vs.traverse(A->Definition, Vs.subExprCtx(Ctx)); - Variable *Nvd = Vs.enterScope(*A, Ne); - Nas.push_back(Nvd); + for (auto *E : Args) { + auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); + Nas.push_back(Ne); } - for (auto *I : Instrs) { - auto Ne = Vs.traverse(I->Definition, Vs.subExprCtx(Ctx)); - Variable *Nvd = Vs.enterScope(*I, Ne); - Nis.push_back(Nvd); + for (auto *E : Instrs) { + auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx)); + Nis.push_back(Ne); } - auto Nt = Vs.traverse(Terminator, Ctx); + auto Nt = Vs.traverse(TermInstr, Ctx); // Exiting the basic block should handle any scope cleanup. Vs.exitBasicBlock(*this); @@ -1503,7 +1648,8 @@ public: return Vs.reduceBasicBlock(*this, Nas, Nis, Nt); } - template <class C> typename C::CType compare(BasicBlock *E, C &Cmp) { + template <class C> + typename C::CType compare(const BasicBlock *E, C &Cmp) const { // TODO: implement CFG comparisons return Cmp.comparePointers(this, E); } @@ -1511,22 +1657,32 @@ public: private: friend class SCFG; - MemRegionRef Arena; + int renumberInstrs(int id); // assign unique ids to all instructions + int topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID); + int topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID); + void computeDominator(); + void computePostDominator(); - SCFG *CFGPtr; // The CFG that contains this block. - unsigned BlockID; // unique id for this BB in the containing CFG - BasicBlock *Parent; // The parent block is the enclosing lexical scope. - // The parent dominates this block. - BlockArray Predecessors; // Predecessor blocks in the CFG. - VarArray Args; // Phi nodes. One argument per predecessor. - VarArray Instrs; // Instructions. - SExprRef Terminator; // Branch or Goto +private: + MemRegionRef Arena; // The arena used to allocate this block. + SCFG *CFGPtr; // The CFG that contains this block. + int BlockID : 31; // unique id for this BB in the containing CFG. + // IDs are in topological order. + bool Visited : 1; // Bit to determine if a block has been visited + // during a traversal. + BlockArray Predecessors; // Predecessor blocks in the CFG. + InstrArray Args; // Phi nodes. One argument per predecessor. + InstrArray Instrs; // Instructions. + Terminator* TermInstr; // Terminating instruction + + TopologyNode DominatorNode; // The dominator tree + TopologyNode PostDominatorNode; // The post-dominator tree }; -// An SCFG is a control-flow graph. It consists of a set of basic blocks, each -// of which terminates in a branch to another basic block. There is one -// entry point, and one exit point. +/// An SCFG is a control-flow graph. It consists of a set of basic blocks, +/// each of which terminates in a branch to another basic block. There is one +/// entry point, and one exit point. class SCFG : public SExpr { public: typedef SimpleArray<BasicBlock *> BlockArray; @@ -1537,20 +1693,29 @@ public: SCFG(MemRegionRef A, unsigned Nblocks) : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks), - Entry(nullptr), Exit(nullptr) { - Entry = new (A) BasicBlock(A, nullptr); - Exit = new (A) BasicBlock(A, Entry); - auto *V = new (A) Variable(new (A) Phi()); + Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { + Entry = new (A) BasicBlock(A); + Exit = new (A) BasicBlock(A); + auto *V = new (A) Phi(); Exit->addArgument(V); + Exit->setTerminator(new (A) Return(V)); add(Entry); add(Exit); } SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)), - Entry(nullptr), Exit(nullptr) { + Entry(nullptr), Exit(nullptr), NumInstructions(0), Normal(false) { // TODO: set entry and exit! } + /// Return true if this CFG is valid. + bool valid() const { return Entry && Exit && Blocks.size() > 0; } + + /// Return true if this CFG has been normalized. + /// After normalization, blocks are in topological order, and block and + /// instruction IDs have been assigned. + bool normal() const { return Normal; } + iterator begin() { return Blocks.begin(); } iterator end() { return Blocks.end(); } @@ -1565,9 +1730,17 @@ public: const BasicBlock *exit() const { return Exit; } BasicBlock *exit() { return Exit; } + /// Return the number of blocks in the CFG. + /// Block::blockID() will return a number less than numBlocks(); + size_t numBlocks() const { return Blocks.size(); } + + /// Return the total number of instructions in the CFG. + /// This is useful for building instruction side-tables; + /// A call to SExpr::id() will return a number less than numInstructions(). + unsigned numInstructions() { return NumInstructions; } + inline void add(BasicBlock *BB) { - assert(BB->CFGPtr == nullptr || BB->CFGPtr == this); - BB->setBlockID(Blocks.size()); + assert(BB->CFGPtr == nullptr); BB->CFGPtr = this; Blocks.reserveCheck(1, Arena); Blocks.push_back(BB); @@ -1576,13 +1749,13 @@ public: void setEntry(BasicBlock *BB) { Entry = BB; } void setExit(BasicBlock *BB) { Exit = BB; } - // Set varable ids in all blocks. - void renumberVars(); + void computeNormalForm(); template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { Vs.enterCFG(*this); typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size()); + for (auto *B : Blocks) { Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) ); } @@ -1590,100 +1763,28 @@ public: return Vs.reduceSCFG(*this, Bbs); } - template <class C> typename C::CType compare(SCFG *E, C &Cmp) { - // TODO -- implement CFG comparisons + template <class C> + typename C::CType compare(const SCFG *E, C &Cmp) const { + // TODO: implement CFG comparisons return Cmp.comparePointers(this, E); } private: + void renumberInstrs(); // assign unique ids to all instructions + +private: MemRegionRef Arena; BlockArray Blocks; BasicBlock *Entry; BasicBlock *Exit; + unsigned NumInstructions; + bool Normal; }; -class Goto : public SExpr { -public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; } - - Goto(BasicBlock *B, unsigned I) - : SExpr(COP_Goto), TargetBlock(B), Index(I) {} - Goto(const Goto &G, BasicBlock *B, unsigned I) - : SExpr(COP_Goto), TargetBlock(B), Index(I) {} - const BasicBlock *targetBlock() const { return TargetBlock; } - BasicBlock *targetBlock() { return TargetBlock; } - - unsigned index() const { return Index; } - - template <class V> - typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { - BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock); - return Vs.reduceGoto(*this, Ntb); - } - - template <class C> typename C::CType compare(Goto *E, C &Cmp) { - // TODO -- implement CFG comparisons - return Cmp.comparePointers(this, E); - } - -private: - BasicBlock *TargetBlock; - unsigned Index; // Index into Phi nodes of target block. -}; - - -class Branch : public SExpr { -public: - static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; } - - Branch(SExpr *C, BasicBlock *T, BasicBlock *E, unsigned TI, unsigned EI) - : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E), - ThenIndex(TI), ElseIndex(EI) - {} - Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E, - unsigned TI, unsigned EI) - : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E), - ThenIndex(TI), ElseIndex(EI) - {} - - const SExpr *condition() const { return Condition; } - SExpr *condition() { return Condition; } - - const BasicBlock *thenBlock() const { return ThenBlock; } - BasicBlock *thenBlock() { return ThenBlock; } - - const BasicBlock *elseBlock() const { return ElseBlock; } - BasicBlock *elseBlock() { return ElseBlock; } - - unsigned thenIndex() const { return ThenIndex; } - unsigned elseIndex() const { return ElseIndex; } - - template <class V> - typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { - auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx)); - BasicBlock *Ntb = Vs.reduceBasicBlockRef(ThenBlock); - BasicBlock *Nte = Vs.reduceBasicBlockRef(ElseBlock); - return Vs.reduceBranch(*this, Nc, Ntb, Nte); - } - - template <class C> typename C::CType compare(Branch *E, C &Cmp) { - // TODO -- implement CFG comparisons - return Cmp.comparePointers(this, E); - } - -private: - SExpr *Condition; - BasicBlock *ThenBlock; - BasicBlock *ElseBlock; - unsigned ThenIndex; - unsigned ElseIndex; -}; - - -// An identifier, e.g. 'foo' or 'x'. -// This is a pseduo-term; it will be lowered to a variable or projection. +/// An identifier, e.g. 'foo' or 'x'. +/// This is a pseduo-term; it will be lowered to a variable or projection. class Identifier : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; } @@ -1698,7 +1799,8 @@ public: return Vs.reduceIdentifier(*this); } - template <class C> typename C::CType compare(Identifier* E, C& Cmp) { + template <class C> + typename C::CType compare(const Identifier* E, C& Cmp) const { return Cmp.compareStrings(name(), E->name()); } @@ -1707,8 +1809,8 @@ private: }; -// An if-then-else expression. -// This is a pseduo-term; it will be lowered to a branch in a CFG. +/// An if-then-else expression. +/// This is a pseduo-term; it will be lowered to a branch in a CFG. class IfThenElse : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; } @@ -1720,14 +1822,14 @@ public: : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) { } - SExpr *condition() { return Condition.get(); } // Address to store to - const SExpr *condition() const { return Condition.get(); } + SExpr *condition() { return Condition; } // Address to store to + const SExpr *condition() const { return Condition; } - SExpr *thenExpr() { return ThenExpr.get(); } // Value to store - const SExpr *thenExpr() const { return ThenExpr.get(); } + SExpr *thenExpr() { return ThenExpr; } // Value to store + const SExpr *thenExpr() const { return ThenExpr; } - SExpr *elseExpr() { return ElseExpr.get(); } // Value to store - const SExpr *elseExpr() const { return ElseExpr.get(); } + SExpr *elseExpr() { return ElseExpr; } // Value to store + const SExpr *elseExpr() const { return ElseExpr; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1737,7 +1839,8 @@ public: return Vs.reduceIfThenElse(*this, Nc, Nt, Ne); } - template <class C> typename C::CType compare(IfThenElse* E, C& Cmp) { + template <class C> + typename C::CType compare(const IfThenElse* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(condition(), E->condition()); if (Cmp.notTrue(Ct)) return Ct; @@ -1748,14 +1851,14 @@ public: } private: - SExprRef Condition; - SExprRef ThenExpr; - SExprRef ElseExpr; + SExpr* Condition; + SExpr* ThenExpr; + SExpr* ElseExpr; }; -// A let-expression, e.g. let x=t; u. -// This is a pseduo-term; it will be lowered to instructions in a CFG. +/// A let-expression, e.g. let x=t; u. +/// This is a pseduo-term; it will be lowered to instructions in a CFG. class Let : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Let; } @@ -1770,8 +1873,8 @@ public: Variable *variableDecl() { return VarDecl; } const Variable *variableDecl() const { return VarDecl; } - SExpr *body() { return Body.get(); } - const SExpr *body() const { return Body.get(); } + SExpr *body() { return Body; } + const SExpr *body() const { return Body; } template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) { @@ -1784,7 +1887,8 @@ public: return Vs.reduceLet(*this, Nvd, E1); } - template <class C> typename C::CType compare(Let* E, C& Cmp) { + template <class C> + typename C::CType compare(const Let* E, C& Cmp) const { typename C::CType Ct = Cmp.compare(VarDecl->definition(), E->VarDecl->definition()); if (Cmp.notTrue(Ct)) @@ -1797,17 +1901,18 @@ public: private: Variable *VarDecl; - SExprRef Body; + SExpr* Body; }; -SExpr *getCanonicalVal(SExpr *E); -void simplifyIncompleteArg(Variable *V, til::Phi *Ph); +const SExpr *getCanonicalVal(const SExpr *E); +SExpr* simplifyToCanonicalVal(SExpr *E); +void simplifyIncompleteArg(til::Phi *Ph); } // end namespace til } // end namespace threadSafety } // end namespace clang -#endif // LLVM_CLANG_THREAD_SAFETY_TIL_H +#endif diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h index bc1490b4a448..705fe910d092 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -14,10 +14,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H -#define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H #include "ThreadSafetyTIL.h" +#include <ostream> namespace clang { namespace threadSafety { @@ -56,11 +57,16 @@ public: // Traverse an expression -- returning a result of type R_SExpr. // Override this method to do something for every expression, regardless // of which kind it is. - typename R::R_SExpr traverse(SExprRef &E, typename R::R_Ctx Ctx) { - return traverse(E.get(), Ctx); + // E is a reference, so this can be use for in-place updates. + // The type T must be a subclass of SExpr. + template <class T> + typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) { + return traverseSExpr(E, Ctx); } - typename R::R_SExpr traverse(SExpr *E, typename R::R_Ctx Ctx) { + // Override this method to do something for every expression. + // Does not allow in-place updates. + typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) { return traverseByCase(E, Ctx); } @@ -73,6 +79,7 @@ public: #include "ThreadSafetyOps.def" #undef TIL_OPCODE_DEF } + return self()->reduceNull(); } // Traverse e, by static dispatch on the type "X" of e. @@ -90,10 +97,10 @@ public: class SimpleReducerBase { public: enum TraversalKind { - TRV_Normal, - TRV_Decl, - TRV_Lazy, - TRV_Type + TRV_Normal, // ordinary subexpressions + TRV_Decl, // declarations (e.g. function bodies) + TRV_Lazy, // expressions that require lazy evaluation + TRV_Type // type expressions }; // R_Ctx defines a "context" for the traversal, which encodes information @@ -145,153 +152,6 @@ protected: }; -// Implements a traversal that makes a deep copy of an SExpr. -// The default behavior of reduce##X(...) is to create a copy of the original. -// Subclasses can override reduce##X to implement non-destructive rewriting -// passes. -template<class Self> -class CopyReducer : public Traversal<Self, CopyReducerBase>, - public CopyReducerBase { -public: - CopyReducer(MemRegionRef A) : CopyReducerBase(A) {} - -public: - R_SExpr reduceNull() { - return nullptr; - } - // R_SExpr reduceFuture(...) is never used. - - R_SExpr reduceUndefined(Undefined &Orig) { - return new (Arena) Undefined(Orig); - } - R_SExpr reduceWildcard(Wildcard &Orig) { - return new (Arena) Wildcard(Orig); - } - - R_SExpr reduceLiteral(Literal &Orig) { - return new (Arena) Literal(Orig); - } - template<class T> - R_SExpr reduceLiteralT(LiteralT<T> &Orig) { - return new (Arena) LiteralT<T>(Orig); - } - R_SExpr reduceLiteralPtr(LiteralPtr &Orig) { - return new (Arena) LiteralPtr(Orig); - } - - R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { - return new (Arena) Function(Orig, Nvd, E0); - } - R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { - return new (Arena) SFunction(Orig, Nvd, E0); - } - R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Code(Orig, E0, E1); - } - R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Field(Orig, E0, E1); - } - - R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Apply(Orig, E0, E1); - } - R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) SApply(Orig, E0, E1); - } - R_SExpr reduceProject(Project &Orig, R_SExpr E0) { - return new (Arena) Project(Orig, E0); - } - R_SExpr reduceCall(Call &Orig, R_SExpr E0) { - return new (Arena) Call(Orig, E0); - } - - R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { - return new (Arena) Alloc(Orig, E0); - } - R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { - return new (Arena) Load(Orig, E0); - } - R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Store(Orig, E0, E1); - } - R_SExpr reduceArrayIndex(ArrayIndex &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) ArrayIndex(Orig, E0, E1); - } - R_SExpr reduceArrayAdd(ArrayAdd &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) ArrayAdd(Orig, E0, E1); - } - R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { - return new (Arena) UnaryOp(Orig, E0); - } - R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) BinaryOp(Orig, E0, E1); - } - R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { - return new (Arena) Cast(Orig, E0); - } - - R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> &Bbs) { - return nullptr; // FIXME: implement CFG rewriting - } - R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As, - Container<Variable *> &Is, R_SExpr T) { - return nullptr; // FIXME: implement CFG rewriting - } - R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) { - return new (Arena) Phi(Orig, std::move(As.Elems)); - } - R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) { - return new (Arena) Goto(Orig, B, 0); // FIXME: set index - } - R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { - return new (Arena) Branch(O, C, B0, B1, 0, 0); // FIXME: set indices - } - - R_SExpr reduceIdentifier(Identifier &Orig) { - return new (Arena) Identifier(Orig); - } - R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) { - return new (Arena) IfThenElse(Orig, C, T, E); - } - R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) { - return new (Arena) Let(Orig, Nvd, B); - } - - // Create a new variable from orig, and push it onto the lexical scope. - Variable *enterScope(Variable &Orig, R_SExpr E0) { - return new (Arena) Variable(Orig, E0); - } - // Exit the lexical scope of orig. - void exitScope(const Variable &Orig) {} - - void enterCFG(SCFG &Cfg) {} - void exitCFG(SCFG &Cfg) {} - void enterBasicBlock(BasicBlock &BB) {} - void exitBasicBlock(BasicBlock &BB) {} - - // Map Variable references to their rewritten definitions. - Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } - - // Map BasicBlock references to their rewritten definitions. - BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } -}; - - -class SExprCopier : public CopyReducer<SExprCopier> { -public: - typedef SExpr *R_SExpr; - - SExprCopier(MemRegionRef A) : CopyReducer(A) { } - - // Create a copy of e in region a. - static SExpr *copy(SExpr *E, MemRegionRef A) { - SExprCopier Copier(A); - return Copier.traverse(E, TRV_Normal); - } -}; - - - // Base class for visit traversals. class VisitReducerBase : public SimpleReducerBase { public: @@ -366,8 +226,8 @@ public: R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) { return Bbs.Success; } - R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As, - Container<Variable *> &Is, R_SExpr T) { + R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As, + Container<R_SExpr> &Is, R_SExpr T) { return (As.Success && Is.Success && T); } R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) { @@ -379,6 +239,9 @@ public: R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { return C; } + R_SExpr reduceReturn(Return &O, R_SExpr E) { + return E; + } R_SExpr reduceIdentifier(Identifier &Orig) { return true; @@ -423,7 +286,7 @@ protected: Self *self() { return reinterpret_cast<Self *>(this); } public: - bool compareByCase(SExpr *E1, SExpr* E2) { + bool compareByCase(const SExpr *E1, const SExpr* E2) { switch (E1->opcode()) { #define TIL_OPCODE_DEF(X) \ case COP_##X: \ @@ -431,6 +294,7 @@ public: #include "ThreadSafetyOps.def" #undef TIL_OPCODE_DEF } + return false; } }; @@ -449,38 +313,86 @@ public: bool compareStrings (StringRef s, StringRef r) { return s == r; } bool comparePointers(const void* P, const void* Q) { return P == Q; } - bool compare(SExpr *E1, SExpr* E2) { + bool compare(const SExpr *E1, const SExpr* E2) { if (E1->opcode() != E2->opcode()) return false; return compareByCase(E1, E2); } // TODO -- handle alpha-renaming of variables - void enterScope(Variable* V1, Variable* V2) { } + void enterScope(const Variable* V1, const Variable* V2) { } void leaveScope() { } - bool compareVariableRefs(Variable* V1, Variable* V2) { + bool compareVariableRefs(const Variable* V1, const Variable* V2) { return V1 == V2; } - static bool compareExprs(SExpr *E1, SExpr* E2) { + static bool compareExprs(const SExpr *E1, const SExpr* E2) { EqualsComparator Eq; return Eq.compare(E1, E2); } }; + +class MatchComparator : public Comparator<MatchComparator> { +public: + // Result type for the comparison, e.g. bool for simple equality, + // or int for lexigraphic comparison (-1, 0, 1). Must have one value which + // denotes "true". + typedef bool CType; + + CType trueResult() { return true; } + bool notTrue(CType ct) { return !ct; } + + bool compareIntegers(unsigned i, unsigned j) { return i == j; } + bool compareStrings (StringRef s, StringRef r) { return s == r; } + bool comparePointers(const void* P, const void* Q) { return P == Q; } + + bool compare(const SExpr *E1, const SExpr* E2) { + // Wildcards match anything. + if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard) + return true; + // otherwise normal equality. + if (E1->opcode() != E2->opcode()) + return false; + return compareByCase(E1, E2); + } + + // TODO -- handle alpha-renaming of variables + void enterScope(const Variable* V1, const Variable* V2) { } + void leaveScope() { } + + bool compareVariableRefs(const Variable* V1, const Variable* V2) { + return V1 == V2; + } + + static bool compareExprs(const SExpr *E1, const SExpr* E2) { + MatchComparator Matcher; + return Matcher.compare(E1, E2); + } +}; + + + +// inline std::ostream& operator<<(std::ostream& SS, StringRef R) { +// return SS.write(R.data(), R.size()); +// } + // Pretty printer for TIL expressions template <typename Self, typename StreamType> class PrettyPrinter { private: bool Verbose; // Print out additional information bool Cleanup; // Omit redundant decls. + bool CStyle; // Print exprs in C-like syntax. public: - PrettyPrinter(bool V = false, bool C = true) : Verbose(V), Cleanup(C) { } + PrettyPrinter(bool V = false, bool C = true, bool CS = true) + : Verbose(V), Cleanup(C), CStyle(CS) + {} - static void print(SExpr *E, StreamType &SS) { + static void print(const SExpr *E, StreamType &SS) { Self printer; printer.printSExpr(E, SS, Prec_MAX); } @@ -502,7 +414,7 @@ protected: static const unsigned Prec_MAX = 6; // Return the precedence of a given node, for use in pretty printing. - unsigned precedence(SExpr *E) { + unsigned precedence(const SExpr *E) { switch (E->opcode()) { case COP_Future: return Prec_Atom; case COP_Undefined: return Prec_Atom; @@ -529,13 +441,14 @@ protected: case COP_UnaryOp: return Prec_Unary; case COP_BinaryOp: return Prec_Binary; - case COP_Cast: return Prec_Unary; + case COP_Cast: return Prec_Atom; case COP_SCFG: return Prec_Decl; case COP_BasicBlock: return Prec_MAX; case COP_Phi: return Prec_Atom; case COP_Goto: return Prec_Atom; case COP_Branch: return Prec_Atom; + case COP_Return: return Prec_Other; case COP_Identifier: return Prec_Atom; case COP_IfThenElse: return Prec_Other; @@ -544,22 +457,29 @@ protected: return Prec_MAX; } - void printBlockLabel(StreamType & SS, BasicBlock *BB, unsigned index) { + void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) { if (!BB) { SS << "BB_null"; return; } SS << "BB_"; SS << BB->blockID(); - SS << ":"; - SS << index; + if (index >= 0) { + SS << ":"; + SS << index; + } } - void printSExpr(SExpr *E, StreamType &SS, unsigned P) { + + void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) { if (!E) { self()->printNull(SS); return; } + if (Sub && E->block() && E->opcode() != COP_Variable) { + SS << "_x" << E->id(); + return; + } if (self()->precedence(E) > P) { // Wrap expr in () if necessary. SS << "("; @@ -582,28 +502,28 @@ protected: SS << "#null"; } - void printFuture(Future *E, StreamType &SS) { + void printFuture(const Future *E, StreamType &SS) { self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom); } - void printUndefined(Undefined *E, StreamType &SS) { + void printUndefined(const Undefined *E, StreamType &SS) { SS << "#undefined"; } - void printWildcard(Wildcard *E, StreamType &SS) { - SS << "_"; + void printWildcard(const Wildcard *E, StreamType &SS) { + SS << "*"; } template<class T> - void printLiteralT(LiteralT<T> *E, StreamType &SS) { + void printLiteralT(const LiteralT<T> *E, StreamType &SS) { SS << E->value(); } - void printLiteralT(LiteralT<uint8_t> *E, StreamType &SS) { + void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) { SS << "'" << E->value() << "'"; } - void printLiteral(Literal *E, StreamType &SS) { + void printLiteral(const Literal *E, StreamType &SS) { if (E->clangExpr()) { SS << getSourceLiteralString(E->clangExpr()); return; @@ -685,25 +605,18 @@ protected: SS << "#lit"; } - void printLiteralPtr(LiteralPtr *E, StreamType &SS) { + void printLiteralPtr(const LiteralPtr *E, StreamType &SS) { SS << E->clangDecl()->getNameAsString(); } - void printVariable(Variable *V, StreamType &SS, bool IsVarDecl = false) { - if (!IsVarDecl && Cleanup) { - SExpr* E = getCanonicalVal(V); - if (E != V) { - printSExpr(E, SS, Prec_Atom); - return; - } - } - if (V->kind() == Variable::VK_LetBB) - SS << V->name() << V->getBlockID() << "_" << V->getID(); + void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) { + if (CStyle && V->kind() == Variable::VK_SFun) + SS << "this"; else - SS << V->name() << V->getID(); + SS << V->name() << V->id(); } - void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) { + void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) { switch (sugared) { default: SS << "\\("; // Lambda @@ -719,7 +632,7 @@ protected: SS << ": "; self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); - SExpr *B = E->body(); + const SExpr *B = E->body(); if (B && B->opcode() == COP_Function) self()->printFunction(cast<Function>(B), SS, 2); else { @@ -728,29 +641,29 @@ protected: } } - void printSFunction(SFunction *E, StreamType &SS) { + void printSFunction(const SFunction *E, StreamType &SS) { SS << "@"; self()->printVariable(E->variableDecl(), SS, true); SS << " "; self()->printSExpr(E->body(), SS, Prec_Decl); } - void printCode(Code *E, StreamType &SS) { + void printCode(const Code *E, StreamType &SS) { SS << ": "; self()->printSExpr(E->returnType(), SS, Prec_Decl-1); SS << " -> "; self()->printSExpr(E->body(), SS, Prec_Decl); } - void printField(Field *E, StreamType &SS) { + void printField(const Field *E, StreamType &SS) { SS << ": "; self()->printSExpr(E->range(), SS, Prec_Decl-1); SS << " = "; self()->printSExpr(E->body(), SS, Prec_Decl); } - void printApply(Apply *E, StreamType &SS, bool sugared = false) { - SExpr *F = E->fun(); + void printApply(const Apply *E, StreamType &SS, bool sugared = false) { + const SExpr *F = E->fun(); if (F->opcode() == COP_Apply) { printApply(cast<Apply>(F), SS, true); SS << ", "; @@ -763,7 +676,7 @@ protected: SS << ")$"; } - void printSApply(SApply *E, StreamType &SS) { + void printSApply(const SApply *E, StreamType &SS) { self()->printSExpr(E->sfun(), SS, Prec_Postfix); if (E->isDelegation()) { SS << "@("; @@ -772,14 +685,36 @@ protected: } } - void printProject(Project *E, StreamType &SS) { + void printProject(const Project *E, StreamType &SS) { + if (CStyle) { + // Omit the this-> + if (const SApply *SAP = dyn_cast<SApply>(E->record())) { + if (const Variable *V = dyn_cast<Variable>(SAP->sfun())) { + if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) { + SS << E->slotName(); + return; + } + } + } + if (isa<Wildcard>(E->record())) { + // handle existentials + SS << "&"; + SS << E->clangDecl()->getQualifiedNameAsString(); + return; + } + } self()->printSExpr(E->record(), SS, Prec_Postfix); - SS << "."; + if (CStyle && E->isArrow()) { + SS << "->"; + } + else { + SS << "."; + } SS << E->slotName(); } - void printCall(Call *E, StreamType &SS) { - SExpr *T = E->target(); + void printCall(const Call *E, StreamType &SS) { + const SExpr *T = E->target(); if (T->opcode() == COP_Apply) { self()->printApply(cast<Apply>(T), SS, true); SS << ")"; @@ -790,52 +725,60 @@ protected: } } - void printAlloc(Alloc *E, StreamType &SS) { + void printAlloc(const Alloc *E, StreamType &SS) { SS << "new "; self()->printSExpr(E->dataType(), SS, Prec_Other-1); } - void printLoad(Load *E, StreamType &SS) { + void printLoad(const Load *E, StreamType &SS) { self()->printSExpr(E->pointer(), SS, Prec_Postfix); - SS << "^"; + if (!CStyle) + SS << "^"; } - void printStore(Store *E, StreamType &SS) { + void printStore(const Store *E, StreamType &SS) { self()->printSExpr(E->destination(), SS, Prec_Other-1); SS << " := "; self()->printSExpr(E->source(), SS, Prec_Other-1); } - void printArrayIndex(ArrayIndex *E, StreamType &SS) { + void printArrayIndex(const ArrayIndex *E, StreamType &SS) { self()->printSExpr(E->array(), SS, Prec_Postfix); SS << "["; self()->printSExpr(E->index(), SS, Prec_MAX); SS << "]"; } - void printArrayAdd(ArrayAdd *E, StreamType &SS) { + void printArrayAdd(const ArrayAdd *E, StreamType &SS) { self()->printSExpr(E->array(), SS, Prec_Postfix); SS << " + "; self()->printSExpr(E->index(), SS, Prec_Atom); } - void printUnaryOp(UnaryOp *E, StreamType &SS) { + void printUnaryOp(const UnaryOp *E, StreamType &SS) { SS << getUnaryOpcodeString(E->unaryOpcode()); self()->printSExpr(E->expr(), SS, Prec_Unary); } - void printBinaryOp(BinaryOp *E, StreamType &SS) { + void printBinaryOp(const BinaryOp *E, StreamType &SS) { self()->printSExpr(E->expr0(), SS, Prec_Binary-1); SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " "; self()->printSExpr(E->expr1(), SS, Prec_Binary-1); } - void printCast(Cast *E, StreamType &SS) { - SS << "%"; + void printCast(const Cast *E, StreamType &SS) { + if (!CStyle) { + SS << "cast["; + SS << E->castOpcode(); + SS << "]("; + self()->printSExpr(E->expr(), SS, Prec_Unary); + SS << ")"; + return; + } self()->printSExpr(E->expr(), SS, Prec_Unary); } - void printSCFG(SCFG *E, StreamType &SS) { + void printSCFG(const SCFG *E, StreamType &SS) { SS << "CFG {\n"; for (auto BBI : *E) { printBasicBlock(BBI, SS); @@ -844,39 +787,45 @@ protected: newline(SS); } - void printBasicBlock(BasicBlock *E, StreamType &SS) { + + void printBBInstr(const SExpr *E, StreamType &SS) { + bool Sub = false; + if (E->opcode() == COP_Variable) { + auto *V = cast<Variable>(E); + SS << "let " << V->name() << V->id() << " = "; + E = V->definition(); + Sub = true; + } + else if (E->opcode() != COP_Store) { + SS << "let _x" << E->id() << " = "; + } + self()->printSExpr(E, SS, Prec_MAX, Sub); + SS << ";"; + newline(SS); + } + + void printBasicBlock(const BasicBlock *E, StreamType &SS) { SS << "BB_" << E->blockID() << ":"; if (E->parent()) SS << " BB_" << E->parent()->blockID(); newline(SS); - for (auto *A : E->arguments()) { - SS << "let "; - self()->printVariable(A, SS, true); - SS << " = "; - self()->printSExpr(A->definition(), SS, Prec_MAX); - SS << ";"; - newline(SS); - } - for (auto *I : E->instructions()) { - if (I->definition()->opcode() != COP_Store) { - SS << "let "; - self()->printVariable(I, SS, true); - SS << " = "; - } - self()->printSExpr(I->definition(), SS, Prec_MAX); - SS << ";"; - newline(SS); - } - SExpr *T = E->terminator(); + + for (auto *A : E->arguments()) + printBBInstr(A, SS); + + for (auto *I : E->instructions()) + printBBInstr(I, SS); + + const SExpr *T = E->terminator(); if (T) { - self()->printSExpr(T, SS, Prec_MAX); + self()->printSExpr(T, SS, Prec_MAX, false); SS << ";"; newline(SS); } newline(SS); } - void printPhi(Phi *E, StreamType &SS) { + void printPhi(const Phi *E, StreamType &SS) { SS << "phi("; if (E->status() == Phi::PH_SingleVal) self()->printSExpr(E->values()[0], SS, Prec_MAX); @@ -891,25 +840,38 @@ protected: SS << ")"; } - void printGoto(Goto *E, StreamType &SS) { + void printGoto(const Goto *E, StreamType &SS) { SS << "goto "; printBlockLabel(SS, E->targetBlock(), E->index()); } - void printBranch(Branch *E, StreamType &SS) { + void printBranch(const Branch *E, StreamType &SS) { SS << "branch ("; self()->printSExpr(E->condition(), SS, Prec_MAX); SS << ") "; - printBlockLabel(SS, E->thenBlock(), E->thenIndex()); + printBlockLabel(SS, E->thenBlock(), -1); SS << " "; - printBlockLabel(SS, E->elseBlock(), E->elseIndex()); + printBlockLabel(SS, E->elseBlock(), -1); } - void printIdentifier(Identifier *E, StreamType &SS) { + void printReturn(const Return *E, StreamType &SS) { + SS << "return "; + self()->printSExpr(E->returnValue(), SS, Prec_Other); + } + + void printIdentifier(const Identifier *E, StreamType &SS) { SS << E->name(); } - void printIfThenElse(IfThenElse *E, StreamType &SS) { + void printIfThenElse(const IfThenElse *E, StreamType &SS) { + if (CStyle) { + printSExpr(E->condition(), SS, Prec_Unary); + SS << " ? "; + printSExpr(E->thenExpr(), SS, Prec_Unary); + SS << " : "; + printSExpr(E->elseExpr(), SS, Prec_Unary); + return; + } SS << "if ("; printSExpr(E->condition(), SS, Prec_MAX); SS << ") then "; @@ -918,7 +880,7 @@ protected: printSExpr(E->elseExpr(), SS, Prec_Other); } - void printLet(Let *E, StreamType &SS) { + void printLet(const Let *E, StreamType &SS) { SS << "let "; printVariable(E->variableDecl(), SS, true); SS << " = "; @@ -929,6 +891,10 @@ protected: }; +class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> { }; + + + } // end namespace til } // end namespace threadSafety } // end namespace clang diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h index 31200a3a7253..ba3e0e519b09 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h @@ -11,19 +11,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_UTIL_H -#define LLVM_CLANG_THREAD_SAFETY_UTIL_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" -#include "clang/AST/ExprCXX.h" - #include <cassert> #include <cstddef> -#include <vector> +#include <ostream> #include <utility> +#include <vector> namespace clang { namespace threadSafety { @@ -142,18 +142,35 @@ public: assert(i < Size && "Array index out of bounds."); return Data[i]; } + T &back() { + assert(Size && "No elements in the array."); + return Data[Size - 1]; + } + const T &back() const { + assert(Size && "No elements in the array."); + return Data[Size - 1]; + } iterator begin() { return Data; } - iterator end() { return Data + Size; } + iterator end() { return Data + Size; } + + const_iterator begin() const { return Data; } + const_iterator end() const { return Data + Size; } const_iterator cbegin() const { return Data; } - const_iterator cend() const { return Data + Size; } + const_iterator cend() const { return Data + Size; } void push_back(const T &Elem) { assert(Size < Capacity); Data[Size++] = Elem; } + // drop last n elements from array + void drop(unsigned n = 0) { + assert(Size > n); + Size -= n; + } + void setValues(unsigned Sz, const T& C) { assert(Sz <= Capacity); Size = Sz; @@ -171,6 +188,37 @@ public: return J - Osz; } + // An adaptor to reverse a simple array + class ReverseAdaptor { + public: + ReverseAdaptor(SimpleArray &Array) : Array(Array) {} + // A reverse iterator used by the reverse adaptor + class Iterator { + public: + Iterator(T *Data) : Data(Data) {} + T &operator*() { return *Data; } + const T &operator*() const { return *Data; } + Iterator &operator++() { + --Data; + return *this; + } + bool operator!=(Iterator Other) { return Data != Other.Data; } + + private: + T *Data; + }; + Iterator begin() { return Array.end() - 1; } + Iterator end() { return Array.begin() - 1; } + const Iterator begin() const { return Array.end() - 1; } + const Iterator end() const { return Array.begin() - 1; } + + private: + SimpleArray &Array; + }; + + const ReverseAdaptor reverse() const { return ReverseAdaptor(*this); } + ReverseAdaptor reverse() { return ReverseAdaptor(*this); } + private: // std::max is annoying here, because it requires a reference, // thus forcing InitialCapacity to be initialized outside the .h file. @@ -185,6 +233,7 @@ private: size_t Capacity; }; + } // end namespace til @@ -310,6 +359,11 @@ private: }; +inline std::ostream& operator<<(std::ostream& ss, const StringRef str) { + return ss.write(str.data(), str.size()); +} + + } // end namespace threadSafety } // end namespace clang diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 188722d94b3a..53ff20c23560 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_UNINIT_VALS_H -#define LLVM_CLANG_UNINIT_VALS_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H #include "clang/AST/Stmt.h" #include "llvm/ADT/SmallVector.h" diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 08e335418ab7..0ebdf15f2c4e 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/CodeInjector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Allocator.h" @@ -143,6 +144,14 @@ public: /// \sa getBody bool isBodyAutosynthesized() const; + /// \brief Checks if the body of the Decl is generated by the BodyFarm from a + /// model file. + /// + /// Note, the lookup is not free. We are going to call getBody behind + /// the scenes. + /// \sa getBody + bool isBodyAutosynthesizedFromModelFile() const; + CFG *getCFG(); CFGStmtMap *getCFGStmtMap(); @@ -398,6 +407,10 @@ class AnalysisDeclContextManager { ContextMap Contexts; LocationContextManager LocContexts; CFG::BuildOptions cfgBuildOptions; + + /// Pointer to an interface that can provide function bodies for + /// declarations from external source. + std::unique_ptr<CodeInjector> Injector; /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. @@ -410,7 +423,8 @@ public: bool addTemporaryDtors = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, - bool addCXXNewAllocator = true); + bool addCXXNewAllocator = true, + CodeInjector* injector = nullptr); ~AnalysisDeclContextManager(); diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index 33c940e7bbf0..8d28971cfe5c 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H -#define LLVM_CLANG_DIAGNOSTICANALYSIS_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H +#define LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H #include "clang/Basic/Diagnostic.h" diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index 891fb90691f3..beea867228d6 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CFG_H -#define LLVM_CLANG_CFG_H +#ifndef LLVM_CLANG_ANALYSIS_CFG_H +#define LLVM_CLANG_ANALYSIS_CFG_H #include "clang/AST/Stmt.h" #include "clang/Analysis/Support/BumpVector.h" @@ -811,10 +811,9 @@ public: ImplTy I; }; - /// buildCFG - Builds a CFG from an AST. The responsibility to free the - /// constructed CFG belongs to the caller. - static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C, - const BuildOptions &BO); + /// buildCFG - Builds a CFG from an AST. + static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C, + const BuildOptions &BO); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. diff --git a/include/clang/Analysis/CFGStmtMap.h b/include/clang/Analysis/CFGStmtMap.h index 6e8e140afb23..4dfa91df0f42 100644 --- a/include/clang/Analysis/CFGStmtMap.h +++ b/include/clang/Analysis/CFGStmtMap.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CFGSTMTMAP_H -#define LLVM_CLANG_CFGSTMTMAP_H +#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H +#define LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H #include "clang/Analysis/CFG.h" diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h index 593ba575c78e..eda22a57e8a5 100644 --- a/include/clang/Analysis/CallGraph.h +++ b/include/clang/Analysis/CallGraph.h @@ -14,8 +14,8 @@ // edges to all externally available functions. //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH -#define LLVM_CLANG_ANALYSIS_CALLGRAPH +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H +#define LLVM_CLANG_ANALYSIS_CALLGRAPH_H #include "clang/AST/DeclBase.h" #include "clang/AST/RecursiveASTVisitor.h" diff --git a/include/clang/Analysis/CodeInjector.h b/include/clang/Analysis/CodeInjector.h new file mode 100644 index 000000000000..413a55b05b07 --- /dev/null +++ b/include/clang/Analysis/CodeInjector.h @@ -0,0 +1,46 @@ +//===-- CodeInjector.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 Defines the clang::CodeInjector interface which is responsible for +/// injecting AST of function definitions that may not be available in the +/// original source. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H +#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H + +namespace clang { + +class Stmt; +class FunctionDecl; +class ObjCMethodDecl; + +/// \brief CodeInjector is an interface which is responsible for injecting AST +/// of function definitions that may not be available in the original source. +/// +/// The getBody function will be called each time the static analyzer examines a +/// function call that has no definition available in the current translation +/// unit. If the returned statement is not a null pointer, it is assumed to be +/// the body of a function which will be used for the analysis. The source of +/// the body can be arbitrary, but it is advised to use memoization to avoid +/// unnecessary reparsing of the external source that provides the body of the +/// functions. +class CodeInjector { +public: + CodeInjector(); + virtual ~CodeInjector(); + + virtual Stmt *getBody(const FunctionDecl *D) = 0; + virtual Stmt *getBody(const ObjCMethodDecl *D) = 0; +}; +} + +#endif diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index e6a2f13a0b80..8b3fcff52d08 100644 --- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA -#define LLVM_CLANG_ANALYSIS_DS_COCOA +#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H +#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" diff --git a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h index 930c2bd0925b..f9e800a4a412 100644 --- a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h +++ b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN -#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN +#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H +#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H #include "clang/Basic/IdentifierTable.h" diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 57324d042908..f87271550c20 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT -#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT +#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H +#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index 6d0427ba92b5..841adf64557d 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -16,8 +16,8 @@ // refactor this core logic into something common that is shared between // the two. The main thing that is different is the allocation strategy. -#ifndef LLVM_CLANG_BUMP_VECTOR -#define LLVM_CLANG_BUMP_VECTOR +#ifndef LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H +#define LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Allocator.h" @@ -241,4 +241,4 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { } } // end: clang namespace -#endif // end: LLVM_CLANG_BUMP_VECTOR +#endif diff --git a/include/clang/Basic/ABI.h b/include/clang/Basic/ABI.h index 9e8ef2e3ee8e..bd246792fe24 100644 --- a/include/clang/Basic/ABI.h +++ b/include/clang/Basic/ABI.h @@ -13,8 +13,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef CLANG_BASIC_ABI_H -#define CLANG_BASIC_ABI_H +#ifndef LLVM_CLANG_BASIC_ABI_H +#define LLVM_CLANG_BASIC_ABI_H #include "llvm/Support/DataTypes.h" @@ -24,14 +24,15 @@ namespace clang { enum CXXCtorType { Ctor_Complete, ///< Complete object ctor Ctor_Base, ///< Base object ctor - Ctor_CompleteAllocating ///< Complete object allocating ctor + Ctor_Comdat ///< The COMDAT used for ctors }; /// \brief C++ destructor types. enum CXXDtorType { Dtor_Deleting, ///< Deleting dtor Dtor_Complete, ///< Complete object dtor - Dtor_Base ///< Base object dtor + Dtor_Base, ///< Base object dtor + Dtor_Comdat ///< The COMDAT used for dtors }; /// \brief A return adjustment. @@ -204,4 +205,4 @@ struct ThunkInfo { } // end namespace clang -#endif // CLANG_BASIC_ABI_H +#endif diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h index 4b1cea50f884..8dd75660c672 100644 --- a/include/clang/Basic/AddressSpaces.h +++ b/include/clang/Basic/AddressSpaces.h @@ -30,6 +30,7 @@ enum ID { opencl_global = Offset, opencl_local, opencl_constant, + opencl_generic, cuda_device, cuda_constant, diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h index 7304c8f673e6..18a2b8a31871 100644 --- a/include/clang/Basic/AllDiagnostics.h +++ b/include/clang/Basic/AllDiagnostics.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ALL_DIAGNOSTICS_H -#define LLVM_CLANG_ALL_DIAGNOSTICS_H +#ifndef LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H +#define LLVM_CLANG_BASIC_ALLDIAGNOSTICS_H #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CommentDiagnostic.h" diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 704a375ba291..843746111463 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -115,6 +115,10 @@ def DeclBase : AttrSubject; def FunctionLike : SubsetSubject<DeclBase, [{S->getFunctionType(false) != NULL}]>; +def OpenCLKernelFunction : SubsetSubject<Function, [{ + S->hasAttr<OpenCLKernelAttr>() +}]>; + // HasFunctionProto is a more strict version of FunctionLike, so it should // never be specified in a Subjects list along with FunctionLike (due to the // inclusive nature of subject testing). @@ -186,10 +190,11 @@ class Spelling<string name, string variety> { class GNU<string name> : Spelling<name, "GNU">; class Declspec<string name> : Spelling<name, "Declspec">; -class CXX11<string namespace, string name> : Spelling<name, "CXX11"> { +class CXX11<string namespace, string name, int version = 1> + : Spelling<name, "CXX11"> { string Namespace = namespace; -} -class Keyword<string name> : Spelling<name, "Keyword">; + int Version = version; +} class Keyword<string name> : Spelling<name, "Keyword">; class Pragma<string namespace, string name> : Spelling<name, "Pragma"> { string Namespace = namespace; } @@ -219,12 +224,14 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag, string CustomDiag = customDiag; } -class LangOpt<string name> { +class LangOpt<string name, bit negated = 0> { string Name = name; + bit Negated = negated; } def MicrosoftExt : LangOpt<"MicrosoftExt">; def Borland : LangOpt<"Borland">; def CUDA : LangOpt<"CUDA">; +def COnly : LangOpt<"CPlusPlus", 1>; // Defines targets for target-specific attributes. The list of strings should // specify architectures for which the target applies, based off the ArchType @@ -354,6 +361,24 @@ def Aligned : InheritableAttr { let Documentation = [Undocumented]; } +def AlignValue : Attr { + let Spellings = [ + // Unfortunately, this is semantically an assertion, not a directive + // (something else must ensure the alignment), so aligned_value is a + // probably a better name. We might want to add an aligned_value spelling in + // 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. + 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 Documentation = [AlignValueDocs]; +} + def AlignMac68k : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; @@ -434,7 +459,8 @@ def Bounded : IgnoredAttr { } def CarriesDependency : InheritableParamAttr { - let Spellings = [GNU<"carries_dependency">, CXX11<"","carries_dependency">]; + let Spellings = [GNU<"carries_dependency">, + CXX11<"","carries_dependency", 200809>]; let Subjects = SubjectList<[ParmVar, ObjCMethod, Function], ErrorDiag>; let Documentation = [CarriesDependencyDocs]; } @@ -541,6 +567,13 @@ def CUDAHost : InheritableAttr { let Documentation = [Undocumented]; } +def CUDAInvalidTarget : InheritableAttr { + let Spellings = []; + let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; + let Documentation = [Undocumented]; +} + def CUDALaunchBounds : InheritableAttr { let Spellings = [GNU<"launch_bounds">]; let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>]; @@ -568,7 +601,7 @@ def C11NoReturn : InheritableAttr { } def CXX11NoReturn : InheritableAttr { - let Spellings = [CXX11<"","noreturn">]; + let Spellings = [CXX11<"","noreturn", 200809>]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [CXX11NoReturnDocs]; } @@ -597,27 +630,32 @@ def OpenCLImageAccess : Attr { def OpenCLPrivateAddressSpace : TypeAttr { let Spellings = [Keyword<"__private">, Keyword<"private">]; - let Documentation = [Undocumented]; + let Documentation = [OpenCLAddressSpacePrivateDocs]; } def OpenCLGlobalAddressSpace : TypeAttr { let Spellings = [Keyword<"__global">, Keyword<"global">]; - let Documentation = [Undocumented]; + let Documentation = [OpenCLAddressSpaceGlobalDocs]; } def OpenCLLocalAddressSpace : TypeAttr { let Spellings = [Keyword<"__local">, Keyword<"local">]; - let Documentation = [Undocumented]; + let Documentation = [OpenCLAddressSpaceLocalDocs]; } def OpenCLConstantAddressSpace : TypeAttr { let Spellings = [Keyword<"__constant">, Keyword<"constant">]; - let Documentation = [Undocumented]; + let Documentation = [OpenCLAddressSpaceConstantDocs]; +} + +def OpenCLGenericAddressSpace : TypeAttr { + let Spellings = [Keyword<"__generic">, Keyword<"generic">]; + let Documentation = [OpenCLAddressSpaceGenericDocs]; } def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, - CXX11<"","deprecated">]; + CXX11<"","deprecated", 201309>]; let Args = [StringArgument<"Message", 1>]; let Documentation = [Undocumented]; } @@ -655,7 +693,7 @@ def FastCall : InheritableAttr { let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">, Keyword<"_fastcall">]; // let Subjects = [Function, ObjCMethod]; - let Documentation = [Undocumented]; + let Documentation = [FastCallDocs]; } def Final : InheritableAttr { @@ -671,6 +709,25 @@ def MinSize : InheritableAttr { let Documentation = [Undocumented]; } +def FlagEnum : InheritableAttr { + let Spellings = [GNU<"flag_enum">]; + let Subjects = SubjectList<[Enum]>; + let Documentation = [FlagEnumDocs]; + let LangOpts = [COnly]; + let AdditionalMembers = [{ +private: + llvm::APInt FlagBits; +public: + llvm::APInt &getFlagBits() { + return FlagBits; + } + + const llvm::APInt &getFlagBits() const { + return FlagBits; + } +}]; +} + def Flatten : InheritableAttr { let Spellings = [GCC<"flatten">]; let Subjects = SubjectList<[Function], ErrorDiag>; @@ -754,7 +811,7 @@ def MayAlias : InheritableAttr { def MSABI : InheritableAttr { let Spellings = [GCC<"ms_abi">]; // let Subjects = [Function, ObjCMethod]; - let Documentation = [Undocumented]; + let Documentation = [MSABIDocs]; } def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> { @@ -810,7 +867,7 @@ def NoCommon : InheritableAttr { } def NoDebug : InheritableAttr { - let Spellings = [GNU<"nodebug">]; + let Spellings = [GCC<"nodebug">]; let Documentation = [Undocumented]; } @@ -832,6 +889,38 @@ def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { let Documentation = [Undocumented]; } +// This is not a TargetSpecificAttr so that is silently accepted and +// ignored on other targets as encouraged by the OpenCL spec. +// +// See OpenCL 1.2 6.11.5: "It is our intention that a particular +// implementation of OpenCL be free to ignore all attributes and the +// resulting executable binary will produce the same result." +// +// However, only AMD GPU targets will emit the corresponding IR +// attribute. +// +// FIXME: This provides a sub-optimal error message if you attempt to +// use this in CUDA, since CUDA does not use the same terminology. +def AMDGPUNumVGPR : InheritableAttr { + let Spellings = [GNU<"amdgpu_num_vgpr">]; + let Args = [UnsignedArgument<"NumVGPR">]; + let Documentation = [AMDGPUNumVGPRDocs]; + +// FIXME: This should be for OpenCLKernelFunction, but is not to +// workaround needing to see kernel attribute before others to know if +// this should be rejected on non-kernels. + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedKernelFunction">; +} + +def AMDGPUNumSGPR : InheritableAttr { + let Spellings = [GNU<"amdgpu_num_sgpr">]; + let Args = [UnsignedArgument<"NumSGPR">]; + let Documentation = [AMDGPUNumSGPRDocs]; + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedKernelFunction">; +} + def NoSplitStack : InheritableAttr { let Spellings = [GCC<"no_split_stack">]; let Subjects = SubjectList<[Function], ErrorDiag>; @@ -845,11 +934,15 @@ def NonNull : InheritableAttr { let Args = [VariadicUnsignedArgument<"Args">]; let AdditionalMembers = [{bool isNonNull(unsigned idx) const { + if (!args_size()) + return true; for (const auto &V : args()) if (V == idx) return true; return false; } }]; + // FIXME: We should merge duplicates into a single nonnull attribute. + let DuplicatesAllowedWhileMerging = 1; let Documentation = [Undocumented]; } @@ -860,6 +953,13 @@ def ReturnsNonNull : InheritableAttr { let Documentation = [Undocumented]; } +def AssumeAligned : InheritableAttr { + let Spellings = [GCC<"assume_aligned">]; + let Subjects = SubjectList<[ObjCMethod, Function]>; + let Args = [ExprArgument<"Alignment">, ExprArgument<"Offset", 1>]; + let Documentation = [AssumeAlignedDocs]; +} + def NoReturn : InheritableAttr { let Spellings = [GCC<"noreturn">, Declspec<"noreturn">]; // FIXME: Does GCC allow this on the function instead? @@ -1068,7 +1168,7 @@ def Pure : InheritableAttr { def Regparm : TypeAttr { let Spellings = [GCC<"regparm">]; let Args = [UnsignedArgument<"NumParams">]; - let Documentation = [Undocumented]; + let Documentation = [RegparmDocs]; } def ReqdWorkGroupSize : InheritableAttr { @@ -1115,7 +1215,7 @@ def Sentinel : InheritableAttr { def StdCall : InheritableAttr { let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">]; // let Subjects = [Function, ObjCMethod]; - let Documentation = [Undocumented]; + let Documentation = [StdCallDocs]; } def SysVABI : InheritableAttr { @@ -1128,7 +1228,14 @@ def ThisCall : InheritableAttr { let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">, Keyword<"_thiscall">]; // let Subjects = [Function, ObjCMethod]; - let Documentation = [Undocumented]; + let Documentation = [ThisCallDocs]; +} + +def VectorCall : InheritableAttr { + let Spellings = [GNU<"vectorcall">, Keyword<"__vectorcall">, + Keyword<"_vectorcall">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [VectorCallDocs]; } def Pascal : InheritableAttr { @@ -1784,14 +1891,21 @@ def Unaligned : IgnoredAttr { } def LoopHint : Attr { - /// vectorize: vectorizes loop operations if 'value != 0'. - /// vectorize_width: vectorize loop operations with width 'value'. - /// interleave: interleave multiple loop iterations if 'value != 0'. - /// interleave_count: interleaves 'value' loop interations. - /// unroll: unroll loop if 'value != 0'. - /// unroll_count: unrolls loop 'value' times. - - let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">]; + /// #pragma clang loop <option> directive + /// vectorize: vectorizes loop operations if State == Enable. + /// vectorize_width: vectorize loop operations with width 'Value'. + /// interleave: interleave multiple loop iterations if State == Enable. + /// interleave_count: interleaves 'Value' loop interations. + /// unroll: fully unroll loop if State == Enable. + /// unroll_count: unrolls loop 'Value' times. + + /// #pragma unroll <argument> directive + /// <no arg>: fully unrolls loop. + /// boolean: fully unrolls loop if State == Enable. + /// expression: unrolls loop 'Value' times. + + let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">, + Pragma<"", "nounroll">]; /// State of the loop optimization specified by the spelling. let Args = [EnumArgument<"Option", "OptionType", @@ -1799,10 +1913,13 @@ def LoopHint : Attr { "unroll", "unroll_count"], ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount", "Unroll", "UnrollCount"]>, - DefaultIntArgument<"Value", 1>]; + EnumArgument<"State", "LoopHintState", + ["default", "enable", "disable"], + ["Default", "Enable", "Disable"]>, + ExprArgument<"Value">]; let AdditionalMembers = [{ - static StringRef getOptionName(int Option) { + static const char *getOptionName(int Option) { switch(Option) { case Vectorize: return "vectorize"; case VectorizeWidth: return "vectorize_width"; @@ -1814,59 +1931,68 @@ def LoopHint : Attr { llvm_unreachable("Unhandled LoopHint option."); } - static StringRef getValueName(int Value) { - if (Value) - return "enable"; - return "disable"; - } - void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { unsigned SpellingIndex = getSpellingListIndex(); - if (SpellingIndex == Pragma_unroll) { - // String "unroll" of "#pragma unroll" is already emitted as the - // pragma name. - if (option == UnrollCount) - printArgument(OS); + // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or + // "nounroll" is already emitted as the pragma name. + if (SpellingIndex == Pragma_nounroll) { OS << "\n"; return; } + else if (SpellingIndex == Pragma_unroll) { + OS << getValueString(Policy) << "\n"; + return; + } + assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); - OS << getOptionName(option); - printArgument(OS); - OS << "\n"; + OS << getOptionName(option) << getValueString(Policy) << "\n"; } - // Prints the loop hint argument including the enclosing parentheses to OS. - void printArgument(raw_ostream &OS) const { + // Return a string containing the loop hint argument including the + // enclosing parentheses. + std::string getValueString(const PrintingPolicy &Policy) const { + std::string ValueName; + llvm::raw_string_ostream OS(ValueName); OS << "("; if (option == VectorizeWidth || option == InterleaveCount || option == UnrollCount) - OS << value; - else if (value) - OS << "enable"; + value->printPretty(OS, nullptr, Policy); + else if (state == Default) + return ""; + else if (state == Enable) + OS << (option == Unroll ? "full" : "enable"); else OS << "disable"; OS << ")"; + return OS.str(); } // Return a string suitable for identifying this attribute in diagnostics. - std::string getDiagnosticName() const { - std::string DiagnosticName; - llvm::raw_string_ostream OS(DiagnosticName); + std::string getDiagnosticName(const PrintingPolicy &Policy) const { unsigned SpellingIndex = getSpellingListIndex(); - if (SpellingIndex == Pragma_unroll && option == Unroll) - OS << "#pragma unroll"; - else if (SpellingIndex == Pragma_unroll && option == UnrollCount) { - OS << "#pragma unroll"; - printArgument(OS); - } else { - assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); - OS << getOptionName(option); - printArgument(OS); - } - return OS.str(); + if (SpellingIndex == Pragma_nounroll) + return "#pragma nounroll"; + else if (SpellingIndex == Pragma_unroll) + return "#pragma unroll" + getValueString(Policy); + + assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); + return getOptionName(option) + getValueString(Policy); } }]; let Documentation = [LoopHintDocs, UnrollHintDocs]; } + +def CapturedRecord : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + +def OMPThreadPrivateDecl : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index e6d6a33d3b5d..918abb6072ea 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -72,9 +72,9 @@ def ThreadDocs : Documentation { let Content = [{ The ``__declspec(thread)`` attribute declares a variable with thread local storage. It is available under the ``-fms-extensions`` flag for MSVC -compatibility. Documentation for the Visual C++ attribute is available on MSDN_. +compatibility. See the documentation for `__declspec(thread)`_ on MSDN. -.. _MSDN: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx +.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the GNU ``__thread`` keyword. The variable must not have a destructor and must have @@ -154,6 +154,30 @@ def ReleaseCapabilityDocs : Documentation { Marks a function as releasing a capability. }]; } + +def AssumeAlignedDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((assume_aligned(<alignment>[,<offset>]))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) has the specified offset, in bytes, from an address with the +specified alignment. The offset is taken to be zero if omitted. + +.. code-block:: c++ + + // The returned pointer value has 32-byte alignment. + void *a() __attribute__((assume_aligned (32))); + + // The returned pointer value is 4 bytes greater than an address having + // 32-byte alignment. + void *b() __attribute__((assume_aligned (32, 4))); + +Note that this attribute provides information to the compiler regarding a +condition that the code already ensures is true. It does not cause the compiler +to enforce the provided alignment assumption. + }]; +} + def EnableIfDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -649,15 +673,180 @@ The semantics are as follows: }]; } +def DocCatAMDGPURegisterAttributes : + DocumentationCategory<"AMD GPU Register Attributes"> { + let Content = [{ +Clang supports attributes for controlling register usage on AMD GPU +targets. These attributes may be attached to a kernel function +definition and is an optimization hint to the backend for the maximum +number of registers to use. This is useful in cases where register +limited occupancy is known to be an important factor for the +performance for the kernel. + +The semantics are as follows: + +- The backend will attempt to limit the number of used registers to + the specified value, but the exact number used is not + guaranteed. The number used may be rounded up to satisfy the + allocation requirements or ABI constraints of the subtarget. For + example, on Southern Islands VGPRs may only be allocated in + increments of 4, so requesting a limit of 39 VGPRs will really + attempt to use up to 40. Requesting more registers than the + subtarget supports will truncate to the maximum allowed. The backend + may also use fewer registers than requested whenever possible. + +- 0 implies the default no limit on register usage. + +- Ignored on older VLIW subtargets which did not have separate scalar + and vector registers, R600 through Northern Islands. + +}]; +} + + +def AMDGPUNumVGPRDocs : Documentation { + let Category = DocCatAMDGPURegisterAttributes; + let Content = [{ +Clang supports the +``__attribute__((amdgpu_num_vgpr(<num_registers>)))`` attribute on AMD +Southern Islands GPUs and later for controlling the number of vector +registers. A typical value would be between 4 and 256 in increments +of 4. +}]; +} + +def AMDGPUNumSGPRDocs : Documentation { + let Category = DocCatAMDGPURegisterAttributes; + let Content = [{ + +Clang supports the +``__attribute__((amdgpu_num_sgpr(<num_registers>)))`` attribute on AMD +Southern Islands GPUs and later for controlling the number of scalar +registers. A typical value would be between 8 and 104 in increments of +8. + +Due to common instruction constraints, an additional 2-4 SGPRs are +typically required for internal use depending on features used. This +value is a hint for the total number of SGPRs to use, and not the +number of user SGPRs, so no special consideration needs to be given +for these. +}]; +} + +def DocCatCallingConvs : DocumentationCategory<"Calling Conventions"> { + let Content = [{ +Clang supports several different calling conventions, depending on the target +platform and architecture. The calling convention used for a function determines +how parameters are passed, how results are returned to the caller, and other +low-level details of calling a function. + }]; +} + def PcsDocs : Documentation { - let Category = DocCatFunction; + let Category = DocCatCallingConvs; let Content = [{ -On ARM targets, this can attribute can be used to select calling conventions, +On ARM targets, this attribute can be used to select calling conventions similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and "aapcs-vfp". }]; } +def RegparmDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, the regparm attribute causes the compiler to pass +the first three integer parameters in EAX, EDX, and ECX instead of on the +stack. This attribute has no effect on variadic functions, and all parameters +are passed via the stack as normal. + }]; +} + +def SysVABIDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On Windows x86_64 targets, this attribute changes the calling convention of a +function to match the default convention used on Sys V targets such as Linux, +Mac, and BSD. This attribute has no effect on other targets. + }]; +} + +def MSABIDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On non-Windows x86_64 targets, this attribute changes the calling convention of +a function to match the default convention used on Windows x86_64. This +attribute has no effect on Windows targets or non-x86_64 targets. + }]; +} + +def StdCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to clear parameters off of the stack on return. This convention does +not support variadic calls or unprototyped functions in C, and has no effect on +x86_64 targets. This calling convention is used widely by the Windows API and +COM applications. See the documentation for `__stdcall`_ on MSDN. + +.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + }]; +} + +def FastCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX and EDX as register parameters and clear parameters off of +the stack on return. This convention does not support variadic calls or +unprototyped functions in C, and has no effect on x86_64 targets. This calling +convention is supported primarily for compatibility with existing code. Users +seeking register parameters should use the ``regparm`` attribute, which does +not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN. + +.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx + }]; +} + +def ThisCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX for the first parameter (typically the implicit ``this`` +parameter of C++ methods) and clear parameters off of the stack on return. This +convention does not support variadic calls or unprototyped functions in C, and +has no effect on x86_64 targets. See the documentation for `__thiscall`_ on +MSDN. + +.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx + }]; +} + +def VectorCallDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On 32-bit x86 *and* x86_64 targets, this attribute changes the calling +convention of a function to pass vector parameters in SSE registers. + +On 32-bit x86 targets, this calling convention is similar to ``__fastcall``. +The first two integer parameters are passed in ECX and EDX. Subsequent integer +parameters are passed in memory, and callee clears the stack. On x86_64 +targets, the callee does *not* clear the stack, and integer parameters are +passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling +convention. + +On both 32-bit x86 and x86_64 targets, vector and floating point arguments are +passed in XMM0-XMM5. Homogenous vector aggregates of up to four elements are +passed in sequential SSE registers if enough are available. If AVX is enabled, +256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that +cannot be passed in registers for any reason is passed by reference, which +allows the caller to align the parameter memory. + +See the documentation for `__vectorcall`_ on MSDN for more details. + +.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx + }]; +} + def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> { let Content = [{ Clang supports additional attributes for checking basic resource management @@ -987,6 +1176,36 @@ Clang implements two kinds of checks with this attribute. }]; } +def AlignValueDocs : Documentation { + let Category = DocCatType; + let Content = [{ +The align_value attribute can be added to the typedef of a pointer type or the +declaration of a variable of pointer or reference type. It specifies that the +pointer will point to, or the reference will bind to, only objects with at +least the provided alignment. This alignment value must be some positive power +of 2. + + .. code-block:: c + + typedef double * aligned_double_ptr __attribute__((align_value(64))); + void foo(double & x __attribute__((align_value(128)), + aligned_double_ptr y) { ... } + +If the pointer value does not have the specified alignment at runtime, the +behavior of the program is undefined. + }]; +} + +def FlagEnumDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute can be added to an enumerator to signal to the compiler that it +is intended to be used as a flag type. This will cause the compiler to assume +that the range of the type includes all of the values that you can get by +manipulating bits of the enumerator when issuing warnings. + }]; +} + def MSInheritanceDocs : Documentation { let Category = DocCatType; let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance"; @@ -1045,12 +1264,14 @@ entire application without optimization. Avoiding optimization on the specified function can improve the quality of the debugging information for that function. -This attribute is incompatible with the ``always_inline`` attribute. +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. }]; } def LoopHintDocs : Documentation { let Category = DocCatStmt; + let Heading = "#pragma clang loop"; let Content = [{ The ``#pragma clang loop`` directive allows loop optimization hints to be specified for the subsequent loop. The directive allows vectorization, @@ -1064,10 +1285,11 @@ for details. def UnrollHintDocs : Documentation { let Category = DocCatStmt; + let Heading = "#pragma unroll, #pragma nounroll"; let Content = [{ -Loop unrolling optimization hints can be specified with ``#pragma unroll``. The -pragma is placed immediately before a for, while, do-while, or c++11 range-based -for loop. +Loop unrolling optimization hints can be specified with ``#pragma unroll`` and +``#pragma nounroll``. The pragma is placed immediately before a for, while, +do-while, or c++11 range-based for loop. Specifying ``#pragma unroll`` without a parameter directs the loop unroller to attempt to fully unroll the loop if the trip count is known at compile time: @@ -1095,11 +1317,107 @@ enclosed in parentheses: ... } +Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled: + +.. code-block:: c++ + + #pragma nounroll + for (...) { + ... + } + ``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to -``#pragma clang loop unroll(enable)`` and ``#pragma clang loop -unroll_count(_value_)`` respectively. See `language extensions +``#pragma clang loop unroll(full)`` and +``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll`` +is equivalent to ``#pragma clang loop unroll(disable)``. See +`language extensions <http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_ for further details including limitations of the unroll hints. }]; } +def DocOpenCLAddressSpaces : DocumentationCategory<"OpenCL Address Spaces"> { + let Content = [{ +The address space qualifier may be used to specify the region of memory that is +used to allocate the object. OpenCL supports the following address spaces: +__generic(generic), __global(global), __local(local), __private(private), +__constant(constant). + + .. code-block:: c + + __constant int c = ...; + + __generic int* foo(global int* g) { + __local int* l; + private int p; + ... + return l; + } + +More details can be found in the OpenCL C language Spec v2.0, Section 6.5. + }]; +} + +def OpenCLAddressSpaceGenericDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Heading = "__generic(generic)"; + let Content = [{ +The generic address space attribute is only available with OpenCL v2.0 and later. +It can be used with pointer types. Variables in global and local scope and +function parameters in non-kernel functions can have the generic address space +type attribute. It is intended to be a placeholder for any other address space +except for '__constant' in OpenCL code which can be used with multiple address +spaces. + }]; +} + +def OpenCLAddressSpaceConstantDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Heading = "__constant(constant)"; + let Content = [{ +The constant address space attribute signals that an object is located in +a constant (non-modifiable) memory region. It is available to all work items. +Any type can be annotated with the constant address space attribute. Objects +with the constant address space qualifier can be declared in any scope and must +have an initializer. + }]; +} + +def OpenCLAddressSpaceGlobalDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Heading = "__global(global)"; + let Content = [{ +The global address space attribute specifies that an object is allocated in +global memory, which is accessible by all work items. The content stored in this +memory area persists between kernel executions. Pointer types to the global +address space are allowed as function parameters or local variables. Starting +with OpenCL v2.0, the global address space can be used with global (program +scope) variables and static local variable as well. + }]; +} + +def OpenCLAddressSpaceLocalDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Heading = "__local(local)"; + let Content = [{ +The local address space specifies that an object is allocated in the local (work +group) memory area, which is accessible to all work items in the same work +group. The content stored in this memory region is not accessible after +the kernel execution ends. In a kernel function scope, any variable can be in +the local address space. In other scopes, only pointer types to the local address +space are allowed. Local address space variables cannot have an initializer. + }]; +} + +def OpenCLAddressSpacePrivateDocs : Documentation { + let Category = DocOpenCLAddressSpaces; + let Heading = "__private(private)"; + let Content = [{ +The private address space specifies that an object is allocated in the private +(work item) memory. Other work items cannot access the same memory area and its +content is destroyed after work item execution ends. Local variables can be +declared in the private address space. Function arguments are always in the +private address space. Kernel function arguments of a pointer or an array type +cannot point to the private address space. + }]; +} diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h index 150a30e73d3f..f0b0a6445d40 100644 --- a/include/clang/Basic/AttrKinds.h +++ b/include/clang/Basic/AttrKinds.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ATTRKINDS_H -#define LLVM_CLANG_ATTRKINDS_H +#ifndef LLVM_CLANG_BASIC_ATTRKINDS_H +#define LLVM_CLANG_BASIC_ATTRKINDS_H namespace clang { diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h index 5783b3bff510..a64dd5666b73 100644 --- a/include/clang/Basic/Attributes.h +++ b/include/clang/Basic/Attributes.h @@ -10,16 +10,14 @@ #ifndef LLVM_CLANG_BASIC_ATTRIBUTES_H #define LLVM_CLANG_BASIC_ATTRIBUTES_H -#include "llvm/ADT/Triple.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/Triple.h" namespace clang { class IdentifierInfo; enum class AttrSyntax { - /// Is the attribute identifier generally known for any syntax? - Generic, /// Is the identifier known as a GNU-style attribute? GNU, /// Is the identifier known as a __declspec-style attribute? @@ -30,11 +28,11 @@ enum class AttrSyntax { Pragma }; -/// \brief Return true if we recognize and implement the attribute specified by -/// the given information. -bool hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, - const IdentifierInfo *Attr, const llvm::Triple &T, - const LangOptions &LangOpts); +/// \brief Return the version number associated with the attribute if we +/// recognize and implement the attribute specified by the given information. +int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, + const IdentifierInfo *Attr, const llvm::Triple &T, + const LangOptions &LangOpts); } // end namespace clang diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index e705382e11ca..098f5dacacbd 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -412,6 +412,7 @@ BUILTIN(__builtin_va_start, "vA.", "nt") BUILTIN(__builtin_va_end, "vA", "n") BUILTIN(__builtin_va_copy, "vAA", "n") BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc") BUILTIN(__builtin_bcmp, "iv*v*z", "n") BUILTIN(__builtin_bcopy, "vv*v*z", "n") BUILTIN(__builtin_bzero, "vv*z", "nF") @@ -496,6 +497,7 @@ BUILTIN(__builtin_unreachable, "v", "nr") BUILTIN(__builtin_shufflevector, "v." , "nc") BUILTIN(__builtin_convertvector, "v." , "nct") BUILTIN(__builtin_alloca, "v*z" , "n") +BUILTIN(__builtin_call_with_static_chain, "v.", "nt") // "Overloaded" Atomic operator builtins. These are overloaded to support data // types of i8, i16, i32, i64, and i128. The front-end sees calls to the @@ -540,6 +542,12 @@ BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn") BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn") BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn") +BUILTIN(__sync_fetch_and_nand, "v.", "t") +BUILTIN(__sync_fetch_and_nand_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_nand_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_nand_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_nand_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLiD*LLLi.", "tn") BUILTIN(__sync_add_and_fetch, "v.", "t") BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn") @@ -576,6 +584,13 @@ BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn") BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn") BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") +BUILTIN(__sync_nand_and_fetch, "v.", "t") +BUILTIN(__sync_nand_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_nand_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_nand_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_nand_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + BUILTIN(__sync_bool_compare_and_swap, "v.", "t") BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn") BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn") @@ -689,6 +704,7 @@ LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES) // C99 library functions // C99 stdlib.h @@ -1173,6 +1189,9 @@ LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES) // Annotation function BUILTIN(__builtin_annotation, "v.", "tn") +// Invariants +BUILTIN(__builtin_assume, "vb", "n") + // Multiprecision Arithmetic Builtins. BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n") BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n") diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index f9d30e40560a..3ce2255c8646 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -29,7 +29,7 @@ namespace clang { class ASTContext; class QualType; class LangOptions; - + enum LanguageID { GNU_LANG = 0x1, // builtin requires GNU mode. C_LANG = 0x2, // builtin for c only. @@ -40,7 +40,7 @@ namespace clang { ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. }; - + namespace Builtin { enum ID { NotBuiltin = 0, // This is not a builtin function. diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def index 695ecf9da5f8..9d223c3e8516 100644 --- a/include/clang/Basic/BuiltinsAArch64.def +++ b/include/clang/Basic/BuiltinsAArch64.def @@ -50,4 +50,7 @@ BUILTIN(__builtin_arm_dmb, "vUi", "nc") BUILTIN(__builtin_arm_dsb, "vUi", "nc") BUILTIN(__builtin_arm_isb, "vUi", "nc") +// Prefetch +BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc") + #undef BUILTIN diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def index 2e5eac694fc2..9091ad4d7581 100644 --- a/include/clang/Basic/BuiltinsARM.def +++ b/include/clang/Basic/BuiltinsARM.def @@ -74,13 +74,19 @@ BUILTIN(__builtin_arm_wfe, "v", "") BUILTIN(__builtin_arm_wfi, "v", "") BUILTIN(__builtin_arm_sev, "v", "") BUILTIN(__builtin_arm_sevl, "v", "") +BUILTIN(__builtin_arm_dbg, "vUi", "") // Data barrier BUILTIN(__builtin_arm_dmb, "vUi", "nc") BUILTIN(__builtin_arm_dsb, "vUi", "nc") BUILTIN(__builtin_arm_isb, "vUi", "nc") +// Prefetch +BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc") + // MSVC +LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES) + LANGBUILTIN(__yield, "v", "", ALL_MS_LANGUAGES) LANGBUILTIN(__wfe, "v", "", ALL_MS_LANGUAGES) LANGBUILTIN(__wfi, "v", "", ALL_MS_LANGUAGES) diff --git a/include/clang/Basic/BuiltinsLe64.def b/include/clang/Basic/BuiltinsLe64.def new file mode 100644 index 000000000000..532860603c29 --- /dev/null +++ b/include/clang/Basic/BuiltinsLe64.def @@ -0,0 +1,19 @@ +//==- BuiltinsLe64.def - Le64 Builtin function 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 Le64-specific builtin function database. Users of this +// file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__clear_cache, "vv*v*", "i") + +#undef BUILTIN diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def index 7e9b5eea8325..9c920dce5cab 100644 --- a/include/clang/Basic/BuiltinsNVPTX.def +++ b/include/clang/Basic/BuiltinsNVPTX.def @@ -139,8 +139,8 @@ BUILTIN(__nvvm_brev64, "ULLiULLi", "") // Sad -BUILTIN(__nvvm_sad_i, "iii", "") -BUILTIN(__nvvm_sad_ui, "UiUiUi", "") +BUILTIN(__nvvm_sad_i, "iiii", "") +BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "") // Floor, Ceil @@ -255,19 +255,19 @@ BUILTIN(__nvvm_rsqrt_approx_d, "dd", "") // Add -BUILTIN(__nvvm_add_rn_ftz_f, "ff", "") -BUILTIN(__nvvm_add_rn_f, "ff", "") -BUILTIN(__nvvm_add_rz_ftz_f, "ff", "") -BUILTIN(__nvvm_add_rz_f, "ff", "") -BUILTIN(__nvvm_add_rm_ftz_f, "ff", "") -BUILTIN(__nvvm_add_rm_f, "ff", "") -BUILTIN(__nvvm_add_rp_ftz_f, "ff", "") -BUILTIN(__nvvm_add_rp_f, "ff", "") - -BUILTIN(__nvvm_add_rn_d, "dd", "") -BUILTIN(__nvvm_add_rz_d, "dd", "") -BUILTIN(__nvvm_add_rm_d, "dd", "") -BUILTIN(__nvvm_add_rp_d, "dd", "") +BUILTIN(__nvvm_add_rn_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rn_f, "fff", "") +BUILTIN(__nvvm_add_rz_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rz_f, "fff", "") +BUILTIN(__nvvm_add_rm_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rm_f, "fff", "") +BUILTIN(__nvvm_add_rp_ftz_f, "fff", "") +BUILTIN(__nvvm_add_rp_f, "fff", "") + +BUILTIN(__nvvm_add_rn_d, "ddd", "") +BUILTIN(__nvvm_add_rz_d, "ddd", "") +BUILTIN(__nvvm_add_rm_d, "ddd", "") +BUILTIN(__nvvm_add_rp_d, "ddd", "") // Convert diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index 8a751e4ce846..e42af4244160 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -204,6 +204,25 @@ BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "") BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "") BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") +// VSX built-ins. + +BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "") +BUILTIN(__builtin_vsx_lxvw4x, "V4iivC*", "") + +BUILTIN(__builtin_vsx_stxvd2x, "vV2div*", "") +BUILTIN(__builtin_vsx_stxvw4x, "vV4iiv*", "") + +BUILTIN(__builtin_vsx_xvmaxdp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvmaxsp, "V4fV4fV4f", "") +BUILTIN(__builtin_vsx_xsmaxdp, "ddd", "") + +BUILTIN(__builtin_vsx_xvmindp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvminsp, "V4fV4fV4f", "") +BUILTIN(__builtin_vsx_xsmindp, "ddd", "") + +BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "") +BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "") + // FIXME: Obviously incomplete. #undef BUILTIN diff --git a/include/clang/Basic/BuiltinsR600.def b/include/clang/Basic/BuiltinsR600.def index 49135ccb056d..84fc4fae4eab 100644 --- a/include/clang/Basic/BuiltinsR600.def +++ b/include/clang/Basic/BuiltinsR600.def @@ -16,8 +16,8 @@ BUILTIN(__builtin_amdgpu_div_scale, "dddbb*", "n") BUILTIN(__builtin_amdgpu_div_scalef, "fffbb*", "n") -BUILTIN(__builtin_amdgpu_div_fmas, "dddd", "nc") -BUILTIN(__builtin_amdgpu_div_fmasf, "ffff", "nc") +BUILTIN(__builtin_amdgpu_div_fmas, "ddddb", "nc") +BUILTIN(__builtin_amdgpu_div_fmasf, "ffffb", "nc") BUILTIN(__builtin_amdgpu_div_fixup, "dddd", "nc") BUILTIN(__builtin_amdgpu_div_fixupf, "ffff", "nc") BUILTIN(__builtin_amdgpu_trig_preop, "ddi", "nc") @@ -28,5 +28,9 @@ BUILTIN(__builtin_amdgpu_rsq, "dd", "nc") BUILTIN(__builtin_amdgpu_rsqf, "ff", "nc") BUILTIN(__builtin_amdgpu_rsq_clamped, "dd", "nc") BUILTIN(__builtin_amdgpu_rsq_clampedf, "ff", "nc") +BUILTIN(__builtin_amdgpu_ldexp, "ddi", "nc") +BUILTIN(__builtin_amdgpu_ldexpf, "ffi", "nc") +BUILTIN(__builtin_amdgpu_class, "bdi", "nc") +BUILTIN(__builtin_amdgpu_classf, "bfi", "nc") #undef BUILTIN diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 1f377a8ab1de..eb6803b141b7 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -187,13 +187,45 @@ BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "") BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "") BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "") BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "") +BUILTIN(__builtin_ia32_cmpeqps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpltps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpleps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpunordps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpneqps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpnltps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpnleps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpordps, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "") +BUILTIN(__builtin_ia32_cmpeqss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpltss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpless, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpunordss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpneqss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpnltss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpnless, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpordss, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "") BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "") +BUILTIN(__builtin_ia32_cmpeqpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmplepd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpunordpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpneqpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpnltpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpnlepd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpordpd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "") +BUILTIN(__builtin_ia32_cmpeqsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpltsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmplesd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpunordsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "") BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "") @@ -303,12 +335,12 @@ BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "") -BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") +BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fIc", "") BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "") -BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIi", "") -BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIi", "") -BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIi", "") +BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIc", "") +BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIc", "") +BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIc", "") BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "") BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "") @@ -339,13 +371,13 @@ BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "") BUILTIN(__builtin_ia32_roundss, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2di", "") BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "") -BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fi", "") -BUILTIN(__builtin_ia32_dppd, "V2dV2dV2di", "") +BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "") +BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "") BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "") BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "") BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "") BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "") -BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "") +BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16cIc", "") BUILTIN(__builtin_ia32_phminposuw128, "V8sV8s", "") // SSE 4.2 @@ -404,13 +436,13 @@ BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "") BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "") BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "") BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "") -BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIi", "") -BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIi", "") +BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIc", "") +BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIc", "") BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "") BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "") -BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIi", "") -BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dc", "") -BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fc", "") +BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIc", "") +BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dIc", "") +BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fIc", "") BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIc", "") BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIc", "") BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIc", "") @@ -472,7 +504,7 @@ BUILTIN(__builtin_ia32_maskstorepd256, "vV4d*V4dV4d", "") BUILTIN(__builtin_ia32_maskstoreps256, "vV8f*V8fV8f", "") // AVX2 -BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32ci", "") +BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32cIc", "") BUILTIN(__builtin_ia32_pabsb256, "V32cV32c", "") BUILTIN(__builtin_ia32_pabsw256, "V16sV16s", "") BUILTIN(__builtin_ia32_pabsd256, "V8iV8i", "") @@ -492,7 +524,7 @@ BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "") BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "") BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "") BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "") -BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIi", "") +BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIc", "") BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "") BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "") BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "") @@ -559,8 +591,8 @@ BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "") BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "") BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "") BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLi", "") -BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIi", "") -BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIi", "") +BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIc", "") +BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIc", "") BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "") BUILTIN(__builtin_ia32_pbroadcastw256, "V16sV8s", "") BUILTIN(__builtin_ia32_pbroadcastd256, "V8iV4i", "") @@ -615,14 +647,34 @@ BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "") // F16C BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "") BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "") +BUILTIN(__builtin_ia32_vcvtps2ph512, "V16sV16fIi", "") BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "") BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "") +BUILTIN(__builtin_ia32_vcvtph2ps512, "V16fV16s", "") // RDRAND BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "") BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "") BUILTIN(__builtin_ia32_rdrand64_step, "UiULLi*", "") +// FSGSBASE +BUILTIN(__builtin_ia32_rdfsbase32, "Ui", "") +BUILTIN(__builtin_ia32_rdfsbase64, "ULLi", "") +BUILTIN(__builtin_ia32_rdgsbase32, "Ui", "") +BUILTIN(__builtin_ia32_rdgsbase64, "ULLi", "") +BUILTIN(__builtin_ia32_wrfsbase32, "vUi", "") +BUILTIN(__builtin_ia32_wrfsbase64, "vULLi", "") +BUILTIN(__builtin_ia32_wrgsbase32, "vUi", "") +BUILTIN(__builtin_ia32_wrgsbase64, "vULLi", "") + +// ADX +BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "") +BUILTIN(__builtin_ia32_addcarryx_u64, "UcUcULLiULLiULLi*", "") +BUILTIN(__builtin_ia32_addcarry_u32, "UcUcUiUiUi*", "") +BUILTIN(__builtin_ia32_addcarry_u64, "UcUcULLiULLiULLi*", "") +BUILTIN(__builtin_ia32_subborrow_u32, "UcUcUiUiUi*", "") +BUILTIN(__builtin_ia32_subborrow_u64, "UcUcULLiULLiULLi*", "") + // RDSEED BUILTIN(__builtin_ia32_rdseed16_step, "UiUs*", "") BUILTIN(__builtin_ia32_rdseed32_step, "UiUi*", "") @@ -653,7 +705,7 @@ BUILTIN(__builtin_ia32_sha256rnds2, "V4iV4iV4iV4i", "") BUILTIN(__builtin_ia32_sha256msg1, "V4iV4iV4i", "") BUILTIN(__builtin_ia32_sha256msg2, "V4iV4iV4i", "") -// FMA4 +// FMA BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "") BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "") BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "") @@ -686,6 +738,12 @@ BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "") BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "") BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "") BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfmaddpd512_mask, "V8dV8dV8dV8dUci", "") +BUILTIN(__builtin_ia32_vfmsubpd512_mask, "V8dV8dV8dV8dUci", "") +BUILTIN(__builtin_ia32_vfnmaddpd512_mask, "V8dV8dV8dV8dUci", "") +BUILTIN(__builtin_ia32_vfmaddps512_mask, "V16fV16fV16fV16fUsi", "") +BUILTIN(__builtin_ia32_vfmsubps512_mask, "V16fV16fV16fV16fUsi", "") +BUILTIN(__builtin_ia32_vfnmaddps512_mask, "V16fV16fV16fV16fUsi", "") // XOP BUILTIN(__builtin_ia32_vpmacssww, "V8sV8sV8sV8s", "") @@ -761,4 +819,119 @@ BUILTIN(__builtin_ia32_rdpmc, "ULLii", "") BUILTIN(__builtin_ia32_rdtsc, "ULLi", "") BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "") +// AVX-512 +BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUciC", "") +BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsiC", "") +BUILTIN(__builtin_ia32_rsqrt14sd_mask, "V2dV2dV2dV2dUc", "") +BUILTIN(__builtin_ia32_rsqrt14ss_mask, "V4fV4fV4fV4fUc", "") +BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "") +BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "") +BUILTIN(__builtin_ia32_rsqrt28sd_mask, "V2dV2dV2dV2dUciC", "") +BUILTIN(__builtin_ia32_rsqrt28ss_mask, "V4fV4fV4fV4fUciC", "") +BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUciC", "") +BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsiC", "") +BUILTIN(__builtin_ia32_rcp14sd_mask, "V2dV2dV2dV2dUc", "") +BUILTIN(__builtin_ia32_rcp14ss_mask, "V4fV4fV4fV4fUc", "") +BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "") +BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "") +BUILTIN(__builtin_ia32_rcp28sd_mask, "V2dV2dV2dV2dUciC", "") +BUILTIN(__builtin_ia32_rcp28ss_mask, "V4fV4fV4fV4fUciC", "") +BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUciC", "") +BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsiC", "") +BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsiC", "") +BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsiC", "") +BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUciC", "") +BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUciC", "") +BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fiCUsi", "") +BUILTIN(__builtin_ia32_pcmpeqb512_mask, "LLiV64cV64cLLi", "") +BUILTIN(__builtin_ia32_pcmpeqd512_mask, "sV16iV16is", "") +BUILTIN(__builtin_ia32_pcmpeqq512_mask, "cV8LLiV8LLic", "") +BUILTIN(__builtin_ia32_pcmpeqw512_mask, "iV32sV32si", "") +BUILTIN(__builtin_ia32_pcmpeqb256_mask, "iV32cV32ci", "") +BUILTIN(__builtin_ia32_pcmpeqd256_mask, "cV8iV8ic", "") +BUILTIN(__builtin_ia32_pcmpeqq256_mask, "cV4LLiV4LLic", "") +BUILTIN(__builtin_ia32_pcmpeqw256_mask, "sV16sV16ss", "") +BUILTIN(__builtin_ia32_pcmpeqb128_mask, "sV16cV16cs", "") +BUILTIN(__builtin_ia32_pcmpeqd128_mask, "cV4iV4ic", "") +BUILTIN(__builtin_ia32_pcmpeqq128_mask, "cV2LLiV2LLic", "") +BUILTIN(__builtin_ia32_pcmpeqw128_mask, "cV8sV8sc", "") +BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8diCUci", "") +BUILTIN(__builtin_ia32_rndscaleps_mask, "V16fV16fiCV16fUsiC", "") +BUILTIN(__builtin_ia32_rndscalepd_mask, "V8dV8diCV8dUciC", "") +BUILTIN(__builtin_ia32_cvtps2dq512_mask, "V16iV16fV16iUsiC", "") +BUILTIN(__builtin_ia32_cvtpd2dq512_mask, "V8iV8dV8iUciC", "") +BUILTIN(__builtin_ia32_cvtps2udq512_mask, "V16iV16fV16iUsiC", "") +BUILTIN(__builtin_ia32_cvtpd2udq512_mask, "V8iV8dV8iUciC", "") +BUILTIN(__builtin_ia32_minps512_mask, "V16fV16fV16fV16fUsiC", "") +BUILTIN(__builtin_ia32_minpd512_mask, "V8dV8dV8dV8dUciC", "") +BUILTIN(__builtin_ia32_maxps512_mask, "V16fV16fV16fV16fUsiC", "") +BUILTIN(__builtin_ia32_maxpd512_mask, "V8dV8dV8dV8dUciC", "") +BUILTIN(__builtin_ia32_cvtdq2ps512_mask, "V16fV16iV16fUsiC", "") +BUILTIN(__builtin_ia32_cvtudq2ps512_mask, "V16fV16iV16fUsiC", "") +BUILTIN(__builtin_ia32_cvtdq2pd512_mask, "V8dV8iV8dUc", "") +BUILTIN(__builtin_ia32_cvtudq2pd512_mask, "V8dV8iV8dUc", "") +BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUciC", "") +BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fiCV16sUs", "") +BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsiC", "") +BUILTIN(__builtin_ia32_pabsd512_mask, "V16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_pabsq512_mask, "V8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pmaxsd512_mask, "V16iV16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_pmaxsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pmaxud512_mask, "V16iV16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_pmaxuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pminsd512_mask, "V16iV16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_pminsq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pminud512_mask, "V16iV16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_pminuq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pmuldq512_mask, "V8LLiV16iV16iV8LLiUc", "") +BUILTIN(__builtin_ia32_pmuludq512_mask, "V8LLiV16iV16iV8LLiUc", "") +BUILTIN(__builtin_ia32_blendmd_512_mask, "V16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_blendmq_512_mask, "V8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_blendmps_512_mask, "V16fV16fV16fUs", "") +BUILTIN(__builtin_ia32_blendmpd_512_mask, "V8dV8dV8dUc", "") +BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "") +BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "") +BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "") +BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "") +BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16ivC*V16iUs", "") +BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLivC*V8LLiUc", "") +BUILTIN(__builtin_ia32_loadups512_mask, "V16fvC*V16fUs", "") +BUILTIN(__builtin_ia32_loadupd512_mask, "V8dvC*V8dUc", "") +BUILTIN(__builtin_ia32_storedqudi512_mask, "vv*V8LLiUc", "") +BUILTIN(__builtin_ia32_storedqusi512_mask, "vv*V16iUs", "") +BUILTIN(__builtin_ia32_storeupd512_mask, "vv*V8dUc", "") +BUILTIN(__builtin_ia32_storeups512_mask, "vv*V16fUs", "") +BUILTIN(__builtin_ia32_vpermt2vard512_mask, "V16iV16iV16iV16iUs", "") +BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "") +BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "") +BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "") +BUILTIN(__builtin_ia32_alignq512_mask, "V8LLiV8LLiV8LLiUcV8LLiUc", "") +BUILTIN(__builtin_ia32_alignd512_mask, "V16iV16iV16iUcV16iUc", "") +BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8dvC*V8iUciC", "") +BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16fvC*UsiC", "") +BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8dvC*V8LLiUciC", "") +BUILTIN(__builtin_ia32_gatherdiv16sf, "V8fV8fvC*V8LLiUciC", "") +BUILTIN(__builtin_ia32_gathersiv8di, "V8LLiV8LLivC*V8iUciC", "") +BUILTIN(__builtin_ia32_gathersiv16si, "V16iV16ivC*UsiC", "") +BUILTIN(__builtin_ia32_gatherdiv8di, "V8LLiV8LLivC*V8LLiUciC", "") +BUILTIN(__builtin_ia32_gatherdiv16si, "V8iV8ivC*V8LLiUciC", "") +BUILTIN(__builtin_ia32_scattersiv8df, "vv*UcV8iV8diC", "") +BUILTIN(__builtin_ia32_scattersiv16sf, "vv*UsV16iV16fiC", "") +BUILTIN(__builtin_ia32_scatterdiv8df, "vv*UcV8LLiV8diC", "") +BUILTIN(__builtin_ia32_scatterdiv16sf, "vv*UcV8LLiV8fiC", "") +BUILTIN(__builtin_ia32_scattersiv8di, "vv*UcV8iV8LLiiC", "") +BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iiC", "") +BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8LLiV8LLiiC", "") +BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8LLiV8iiC", "") +BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*iCiC", "") +BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*iCiC", "") +BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8LLivC*iCiC", "") +BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8LLivC*iCiC", "") +BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*iCiC", "") +BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*iCiC", "") +BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8LLiv*iCiC", "") +BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8LLiv*iCiC", "") +BUILTIN(__builtin_ia32_knothi, "UsUs", "") + #undef BUILTIN diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h index d0afda43709a..dd9c55431e01 100644 --- a/include/clang/Basic/CharInfo.h +++ b/include/clang/Basic/CharInfo.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef CLANG_BASIC_CHARINFO_H -#define CLANG_BASIC_CHARINFO_H +#ifndef LLVM_CLANG_BASIC_CHARINFO_H +#define LLVM_CLANG_BASIC_CHARINFO_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" diff --git a/include/clang/Basic/CommentOptions.h b/include/clang/Basic/CommentOptions.h index 7991875838a4..92419f91b741 100644 --- a/include/clang/Basic/CommentOptions.h +++ b/include/clang/Basic/CommentOptions.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_COMMENTOPTIONS_H -#define LLVM_CLANG_COMMENTOPTIONS_H +#ifndef LLVM_CLANG_BASIC_COMMENTOPTIONS_H +#define LLVM_CLANG_BASIC_COMMENTOPTIONS_H #include <string> #include <vector> diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index a7b2ba270d46..91e94db802b1 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DIAGNOSTIC_H -#define LLVM_CLANG_DIAGNOSTIC_H +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_H #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" @@ -187,7 +187,7 @@ private: IntrusiveRefCntPtr<DiagnosticIDs> Diags; IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; DiagnosticConsumer *Client; - bool OwnsDiagClient; + std::unique_ptr<DiagnosticConsumer> Owner; SourceManager *SourceMgr; /// \brief Mapping information for diagnostics. @@ -302,7 +302,6 @@ private: unsigned NumWarnings; ///< Number of warnings reported unsigned NumErrors; ///< Number of errors reported - unsigned NumErrorsSuppressed; ///< Number of errors suppressed /// \brief A function pointer that converts an opaque diagnostic /// argument to a strings. @@ -369,14 +368,11 @@ public: const DiagnosticConsumer *getClient() const { return Client; } /// \brief Determine whether this \c DiagnosticsEngine object own its client. - bool ownsClient() const { return OwnsDiagClient; } - + bool ownsClient() const { return Owner != nullptr; } + /// \brief Return the current diagnostic client along with ownership of that /// client. - DiagnosticConsumer *takeClient() { - OwnsDiagClient = false; - return Client; - } + std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); } bool hasSourceManager() const { return SourceMgr != nullptr; } SourceManager &getSourceManager() const { diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 8d5a1c77233b..d353b451aaa7 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -141,6 +141,13 @@ def note_constexpr_calls_suppressed : Note< "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " "see all)">; def note_constexpr_call_here : Note<"in call to '%0'">; +def note_constexpr_baa_insufficient_alignment : Note< + "%select{alignment of|offset of the aligned pointer from}0 the base pointee " + "object (%1 %plural{1:byte|:bytes}1) is %select{less than|not a multiple of}0 the " + "asserted %2 %plural{1:byte|:bytes}2">; +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 warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index b3c77b8f5f36..ff9ed69022ec 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -81,6 +81,8 @@ def err_deleted_non_function : Error< "only functions can have deleted definitions">; def err_module_not_found : Error<"module '%0' not found">, DefaultFatal; def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal; +def err_module_lock_failure : Error< + "could not acquire lock file for module '%0'">, DefaultFatal; def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, DefaultFatal; def note_pragma_entered_here : Note<"#pragma entered here">; @@ -102,10 +104,12 @@ def ext_cxx11_longlong : Extension< def warn_cxx98_compat_longlong : Warning< "'long long' is incompatible with C++98">, InGroup<CXX98CompatPedantic>, DefaultIgnore; -def err_integer_too_large : Error< - "integer constant is larger than the largest unsigned integer type">; -def ext_integer_too_large_for_signed : ExtWarn< - "integer constant is larger than the largest signed integer type">, +def err_integer_literal_too_large : Error< + "integer literal is too large to be represented in any %select{signed |}0" + "integer type">; +def ext_integer_literal_too_large_for_signed : ExtWarn< + "integer literal is too large to be represented in a signed integer type, " + "interpreting as unsigned">, InGroup<DiagGroup<"implicitly-unsigned-literal">>; // Sema && AST @@ -121,6 +125,8 @@ def err_target_unknown_abi : Error<"unknown target ABI '%0'">; def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">; def err_target_unsupported_fpmath : Error< "the '%0' unit is not supported with this instruction set">; +def err_target_unsupported_unaligned : Error< + "the %0 sub-architecture does not support unaligned accesses">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index cd26a6a4dd70..41c78ee669dc 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -22,6 +22,8 @@ def err_drv_unknown_stdin_type_clang_cl : Error< def err_drv_unknown_language : Error<"language not recognized: '%0'">; def err_drv_invalid_arch_name : Error< "invalid arch name '%0'">; +def err_drv_invalid_thread_model_for_target : Error< + "invalid thread model '%0' in '%1' for this target">; def err_drv_invalid_linker_name : Error< "invalid linker name in argument '%0'">; def err_drv_invalid_rtlib_name : Error< @@ -100,10 +102,6 @@ def err_drv_cc_print_options_failure : Error< "unable to open CC_PRINT_OPTIONS file: %0">; def err_drv_preamble_format : Error< "incorrect format for -preamble-bytes=N,END">; -def err_drv_conflicting_deployment_targets : Error< - "conflicting deployment targets, both '%0' and '%1' are present in environment">; -def err_drv_invalid_arch_for_deployment_target : Error< - "invalid architecture '%0' for deployment target '%1'">; def err_drv_objc_gc_arr : Error< "cannot specify both '-fobjc-arc' and '%0'">; def err_arc_unsupported_on_runtime : Error< @@ -124,7 +122,7 @@ def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>; def warn_drv_optimization_value : Warning<"optimization level '%0' is not supported; using '%1%2' instead">, InGroup<InvalidCommandLineArgument>; def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">, - InGroup<InvalidCommandLineArgument>; + InGroup<IgnoredOptimizationArgument>; def warn_c_kext : Warning< "ignoring -fapple-kext which is valid for C++ and Objective-C++ only">; def warn_drv_input_file_unused : Warning< @@ -165,9 +163,11 @@ def warn_debug_compression_unavailable : Warning<"cannot compress debug sections def note_drv_command_failed_diag_msg : Note< "diagnostic msg: %0">; -def note_drv_t_option_is_global : - Note<"The last /TC or /TP option takes precedence over earlier instances">; - +def note_drv_t_option_is_global : Note< + "The last /TC or /TP option takes precedence over earlier instances">; +def note_drv_address_sanitizer_debug_runtime : Note< + "AddressSanitizer doesn't support linking with debug runtime libraries yet">; + def err_analyzer_config_no_value : Error< "analyzer-config option '%0' has a key but no value">; def err_analyzer_config_multiple_values : Error< @@ -175,7 +175,7 @@ def err_analyzer_config_multiple_values : Error< def err_drv_modules_validate_once_requires_timestamp : Error< "option '-fmodules-validate-once-per-build-session' requires " - "'-fbuild-session-timestamp=<seconds since Epoch>'">; + "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">; def warn_drv_invoking_fallback : Warning<"falling back to %0">, InGroup<Fallback>; diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index ae704c49150b..15f74b11698f 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -46,6 +46,16 @@ def warn_fe_backend_optimization_failure : Warning<"%0">, BackendInfo, def note_fe_backend_optimization_remark_invalid_loc : Note<"could " "not determine the original source location for %0:%1:%2">; +def remark_sanitize_address_insert_extra_padding_accepted : Remark< + "-fsanitize-address-field-padding applied to %0">, ShowInSystemHeader, + InGroup<SanitizeAddressRemarks>; +def remark_sanitize_address_insert_extra_padding_rejected : Remark< + "-fsanitize-address-field-padding ignored for %0 because it " + "%select{is not C++|is packed|is a union|is trivially copyable|" + "has trivial destructor|is standard layout|is in a blacklisted file|" + "is blacklisted}1">, ShowInSystemHeader, + InGroup<SanitizeAddressRemarks>; + def err_fe_invalid_code_complete_file : Error< "cannot locate code-completion file %0">, DefaultFatal; def err_fe_stdout_binary : Error<"unable to change standard output to binary">, @@ -85,9 +95,12 @@ def err_fe_no_pch_in_dir : Error< def err_fe_action_not_available : Error< "action %0 not compiled in">; +def warn_fe_serialized_diag_merge_failure : Warning< + "unable to merge a subprocess's serialized diagnostics">, + InGroup<SerializedDiagnostics>; def warn_fe_serialized_diag_failure : Warning< "unable to open file %0 for serializing diagnostics (%1)">, - InGroup<DiagGroup<"serialized-diagnostics">>; + InGroup<SerializedDiagnostics>; def err_verify_missing_line : Error< "missing or invalid line number following '@' in expected %0">; @@ -135,12 +148,15 @@ def warn_unknown_warning_specifier : Warning< def err_unknown_analyzer_checker : Error< "no analyzer checkers are associated with '%0'">; +def note_suggest_disabling_all_checkers : Note< + "use -analyzer-disable-all-checks to disable all static analyzer checkers">; + def warn_incompatible_analyzer_plugin_api : Warning< "checker plugin '%0' is not compatible with this version of the analyzer">, InGroup<DiagGroup<"analyzer-incompatible-plugin"> >; def note_incompatible_analyzer_plugin_api : Note< "current API version is '%0', but plugin was compiled with version '%1'">; - + def err_module_map_not_found : Error<"module map file '%0' not found">, DefaultFatal; def err_missing_module_name : Error< @@ -167,7 +183,19 @@ def warn_module_config_macro_undef : Warning< def note_module_def_undef_here : Note< "macro was %select{defined|#undef'd}0 here">; def remark_module_build : Remark<"building module '%0' as '%1'">, - InGroup<DiagGroup<"module-build">>; + InGroup<ModuleBuild>; +def remark_module_build_done : Remark<"finished building module '%0'">, + InGroup<ModuleBuild>; + +def err_conflicting_module_names : Error< + "conflicting module names specified: '-fmodule-name=%0' and " + "'-fmodule-implementation-of %1'">; +def err_conflicting_module_files : Error< + "module '%0' is defined in both '%1' and '%2'">; +def err_module_file_not_found : Error< + "file '%0' is not a precompiled module file">, DefaultFatal; +def err_module_file_not_module : Error< + "AST file '%0' was not built as a module">, DefaultFatal; def err_missing_vfs_overlay_file : Error< "virtual filesystem overlay file '%0' not found">, DefaultFatal; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 58dee482b627..75d40b17a67c 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -60,7 +60,7 @@ def ExternCCompat : DiagGroup<"extern-c-compat">; def KeywordCompat : DiagGroup<"keyword-compat">; def GNUCaseRange : DiagGroup<"gnu-case-range">; def CastAlign : DiagGroup<"cast-align">; -def : DiagGroup<"cast-qual">; +def CastQual : DiagGroup<"cast-qual">; def : DiagGroup<"char-align">; def Comment : DiagGroup<"comment">; def GNUComplexInteger : DiagGroup<"gnu-complex-integer">; @@ -71,6 +71,7 @@ def GNUDesignator : DiagGroup<"gnu-designator">; def GNUStringLiteralOperatorTemplate : DiagGroup<"gnu-string-literal-operator-template">; +def DeleteIncomplete : DiagGroup<"delete-incomplete">; def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; def AbstractFinalClass : DiagGroup<"abstract-final-class">; @@ -118,9 +119,9 @@ def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; // Warnings for C++1y code which is not compatible with prior C++ standards. -def CXXPre1yCompat : DiagGroup<"c++98-c++11-compat">; -def CXXPre1yCompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", - [CXXPre1yCompat]>; +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]>; @@ -133,19 +134,21 @@ def CXX98CompatUnnamedTypeTemplateArgs : DiagGroup<"c++98-compat-unnamed-type-template-args">; def CXX98Compat : DiagGroup<"c++98-compat", - [CXX98CompatBindToTemporaryCopy, - CXX98CompatLocalTypeTemplateArgs, + [CXX98CompatLocalTypeTemplateArgs, CXX98CompatUnnamedTypeTemplateArgs, - CXXPre1yCompat, + CXXPre14Compat, CXXPre1zCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, - CXXPre1yCompatPedantic, + CXX98CompatBindToTemporaryCopy, + CXXPre14CompatPedantic, CXXPre1zCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; +def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">; + // Original name of this warning in Clang def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>; @@ -162,11 +165,11 @@ def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing, CXX11CompatReservedUserDefinedLiteral, CXX11CompatDeprecatedWritableStr, - CXXPre1yCompat, + CXXPre14Compat, CXXPre1zCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", - [CXXPre1yCompatPedantic, + [CXXPre14CompatPedantic, CXXPre1zCompatPedantic]>; def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; @@ -187,6 +190,7 @@ def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">; def DanglingElse: DiagGroup<"dangling-else">; def DanglingField : DiagGroup<"dangling-field">; def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; +def FlagEnum : DiagGroup<"flag-enum">; def InfiniteRecursion : DiagGroup<"infinite-recursion">; def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">; def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; @@ -198,11 +202,13 @@ def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types", [IncompatiblePointerTypesDiscardsQualifiers]>; def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; -def IncompleteModule : DiagGroup<"incomplete-module", [IncompleteUmbrella]>; def NonModularIncludeInFrameworkModule : DiagGroup<"non-modular-include-in-framework-module">; def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module", [NonModularIncludeInFrameworkModule]>; +def IncompleteModule : DiagGroup<"incomplete-module", + [IncompleteUmbrella, NonModularIncludeInModule]>; + def InvalidNoreturn : DiagGroup<"invalid-noreturn">; def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">; def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">; @@ -231,6 +237,7 @@ def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def ModuleBuild : DiagGroup<"module-build">; def ModuleConflict : DiagGroup<"module-conflict">; def NewlineEOF : DiagGroup<"newline-eof">; def NullArithmetic : DiagGroup<"null-arithmetic">; @@ -267,7 +274,9 @@ def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">; 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 DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; +def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; def Packed : DiagGroup<"packed">; def Padded : DiagGroup<"padded">; def PointerArith : DiagGroup<"pointer-arith">; @@ -285,6 +294,7 @@ def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy", [CXX98CompatBindToTemporaryCopy]>; def SelfAssignmentField : DiagGroup<"self-assign-field">; def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>; +def SelfMove : DiagGroup<"self-move">; def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; def Sentinel : DiagGroup<"sentinel">; def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; @@ -329,6 +339,8 @@ def : DiagGroup<"sequence-point", [Unsequenced]>; // Preprocessor warnings. def AmbiguousMacro : DiagGroup<"ambiguous-macro">; +def KeywordAsMacro : DiagGroup<"keyword-macro">; +def ReservedIdAsMacro : DiagGroup<"reserved-id-macro">; // Just silence warnings about -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; @@ -349,6 +361,7 @@ def InvalidOffsetof : DiagGroup<"invalid-offsetof">; def : DiagGroup<"strict-prototypes">; def StrictSelector : DiagGroup<"strict-selector-match">; def MethodDuplicate : DiagGroup<"duplicate-method-match">; +def ObjCCStringFormat : DiagGroup<"cstring-format-directive">; def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; def SwitchBool : DiagGroup<"switch-bool">; def SwitchEnum : DiagGroup<"switch-enum">; @@ -383,7 +396,9 @@ def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", def UnsupportedFriend : DiagGroup<"unsupported-friend">; def UnusedArgument : DiagGroup<"unused-argument">; def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument">; -def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument">; +def IgnoredOptimizationArgument : DiagGroup<"ignored-optimization-argument">; +def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument", + [IgnoredOptimizationArgument]>; def UnusedComparison : DiagGroup<"unused-comparison">; def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">; def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">; @@ -395,11 +410,17 @@ def UnusedMemberFunction : DiagGroup<"unused-member-function", def UnusedLabel : DiagGroup<"unused-label">; def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedResult : DiagGroup<"unused-result">; -def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>; +def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">; +def UnevaluatedExpression : DiagGroup<"unevaluated-expression", + [PotentiallyEvaluatedExpression]>; +def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult, + UnevaluatedExpression]>; def UnusedConstVariable : DiagGroup<"unused-const-variable">; def UnusedVariable : DiagGroup<"unused-variable", [UnusedConstVariable]>; +def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">; def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">; +def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">; def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; def UserDefinedLiterals : DiagGroup<"user-defined-literals">; def Reorder : DiagGroup<"reorder">; @@ -408,8 +429,6 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; def CustomAtomic : DiagGroup<"custom-atomic-properties">; def AtomicProperties : DiagGroup<"atomic-properties", [ImplicitAtomic, CustomAtomic]>; -// FIXME: Remove arc-abi once an Xcode is released that doesn't pass this flag. -def : DiagGroup<"arc-abi">; def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">; def ARCRetainCycles : DiagGroup<"arc-retain-cycles">; def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">; @@ -426,6 +445,9 @@ def DeallocInCategory:DiagGroup<"dealloc-in-category">; def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">; def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>; def Protocol : DiagGroup<"protocol">; +def AtProtocol : DiagGroup<"at-protocol">; +def PropertyAccessDotSyntax: DiagGroup<"property-access-dot-syntax">; +def PropertyAttr : DiagGroup<"property-attribute-mismatch">; def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; def VariadicMacros : DiagGroup<"variadic-macros">; @@ -520,7 +542,7 @@ def Unused : DiagGroup<"unused", [UnusedArgument, UnusedFunction, UnusedLabel, // UnusedParameter, (matches GCC's behavior) // UnusedMemberFunction, (clean-up llvm before enabling) - UnusedPrivateField, + UnusedPrivateField, UnusedLocalTypedef, UnusedValue, UnusedVariable, UnusedPropertyIvar]>, DiagCategory<"Unused Entity Issue">; @@ -565,6 +587,7 @@ def Most : DiagGroup<"most", [ Reorder, ReturnType, SelfAssignment, + SelfMove, SizeofArrayArgument, SizeofArrayDecay, StringPlusInt, @@ -585,10 +608,14 @@ def Most : DiagGroup<"most", [ def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">; def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">; def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">; +def ThreadSafetyReference : DiagGroup<"thread-safety-reference">; +def ThreadSafetyNegative : DiagGroup<"thread-safety-negative">; def ThreadSafety : DiagGroup<"thread-safety", [ThreadSafetyAttributes, ThreadSafetyAnalysis, - ThreadSafetyPrecise]>; + ThreadSafetyPrecise, + ThreadSafetyReference]>; +def ThreadSafetyVerbose : DiagGroup<"thread-safety-verbose">; def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">; // Uniqueness Analysis warnings @@ -614,6 +641,8 @@ def : DiagGroup<"int-conversions", [IntConversion]>; // -Wint-conversions = -Wint-conversion def : DiagGroup<"vector-conversions", [VectorConversion]>; // -Wvector-conversions = -Wvector-conversion +def : DiagGroup<"unused-local-typedefs", [UnusedLocalTypedef]>; + // -Wunused-local-typedefs = -Wunused-local-typedef // A warning group for warnings that we want to have on by default in clang, // but which aren't on by default in GCC. @@ -624,15 +653,17 @@ def NonGCC : DiagGroup<"non-gcc", // earlier C++ versions. def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>; -// A warning group for warnings about using C++1y features as extensions in +// A warning group for warnings about using C++14 features as extensions in // earlier C++ versions. -def CXX1y : DiagGroup<"c++1y-extensions">; +def CXX14 : DiagGroup<"c++14-extensions">; // A warning group for warnings about using C++1z features as extensions in // earlier C++ versions. def CXX1z : DiagGroup<"c++1z-extensions">; def : DiagGroup<"c++0x-extensions", [CXX11]>; +def : DiagGroup<"c++1y-extensions", [CXX14]>; + def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; @@ -710,6 +741,12 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">; def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; +// AddressSanitizer frontent instrumentation remarks. +def SanitizeAddressRemarks : DiagGroup<"sanitize-address">; + +// Issues with serialized diagnostics. +def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">; + // A warning group for warnings about code that clang accepts when // compiling CUDA C/C++ but which is not compatible with the CUDA spec. def CudaCompat : DiagGroup<"cuda-compat">; diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index bfb0f0d1ee5d..99b469d70e78 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DIAGNOSTICIDS_H -#define LLVM_CLANG_DIAGNOSTICIDS_H +#ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H +#define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -33,7 +33,7 @@ namespace clang { DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100, DIAG_START_LEX = DIAG_START_SERIALIZATION + 120, DIAG_START_PARSE = DIAG_START_LEX + 300, - DIAG_START_AST = DIAG_START_PARSE + 400, + DIAG_START_AST = DIAG_START_PARSE + 500, DIAG_START_COMMENT = DIAG_START_AST + 100, DIAG_START_SEMA = DIAG_START_COMMENT + 100, DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000, diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 86def878834f..93cc7c297813 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -161,8 +161,8 @@ def err_invalid_suffix_integer_constant : Error< def err_invalid_suffix_float_constant : Error< "invalid suffix '%0' on floating constant">; def warn_cxx11_compat_digit_separator : Warning< - "digit separators are incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompat>, DefaultIgnore; + "digit separators are incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; def err_digit_separator_not_between_digits : Error< "digit separator cannot appear at %select{start|end}0 of digit sequence">; def warn_extraneous_char_constant : Warning< @@ -182,11 +182,11 @@ def ext_hexconstant_invalid : Extension< "hexadecimal floating constants are a C99 feature">, InGroup<C99>; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>; -def ext_binary_literal_cxx1y : Extension< - "binary integer literals are a C++1y extension">, InGroup<CXX1y>; +def ext_binary_literal_cxx14 : Extension< + "binary integer literals are a C++14 extension">, InGroup<CXX14>; def warn_cxx11_compat_binary_literal : Warning< - "binary integer literals are incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompatPedantic>, DefaultIgnore; + "binary integer literals are incompatible with C++ standards before C++14">, + InGroup<CXXPre14CompatPedantic>, DefaultIgnore; def err_pascal_string_too_long : Error<"Pascal string is too long">; def err_octal_escape_too_large : Error<"octal escape sequence out of range">; def err_hex_escape_too_large : Error<"hex escape sequence out of range">; @@ -201,6 +201,9 @@ def warn_c99_compat_unicode_literal : Warning< def warn_cxx98_compat_unicode_literal : Warning< "unicode literals are incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx14_compat_u8_character_literal : Warning< + "unicode literals are incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, 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; @@ -287,6 +290,11 @@ def note_pp_ambiguous_macro_chosen : Note< "expanding this definition of %0">; def note_pp_ambiguous_macro_other : Note< "other definition of %0">; +def warn_pp_macro_hides_keyword : Extension< + "keyword is hidden by macro definition">, InGroup<KeywordAsMacro>; +def warn_pp_macro_is_reserved_id : Warning< + "macro name is a reserved identifier">, DefaultIgnore, + InGroup<ReservedIdAsMacro>; def pp_invalid_string_literal : Warning< "invalid string literal, ignoring final '\\'">; @@ -324,7 +332,7 @@ def warn_cxx98_compat_variadic_macro : Warning< InGroup<CXX98CompatPedantic>, DefaultIgnore; def ext_named_variadic_macro : Extension< "named variadic macros are a GNU extension">, InGroup<VariadicMacros>; -def err_embedded_include : Error< +def err_embedded_directive : Error< "embedding a #%0 directive within macro arguments is not supported">; def ext_embedded_directive : Extension< "embedding a directive within macro arguments has undefined behavior">, @@ -615,9 +623,6 @@ def warn_auto_module_import : Warning< def warn_uncovered_module_header : Warning< "umbrella header for module '%0' does not include header '%1'">, InGroup<IncompleteUmbrella>; -def warn_forgotten_module_header : Warning< - "header '%0' is included in module '%1' but not listed in module map">, - InGroup<IncompleteModule>, DefaultIgnore; def err_expected_id_building_module : Error< "expected a module name in '__building_module' expression">; def error_use_of_private_header_outside_module : Error< diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def index a360a5a84e98..fdd325446e27 100644 --- a/include/clang/Basic/DiagnosticOptions.def +++ b/include/clang/Basic/DiagnosticOptions.def @@ -81,6 +81,8 @@ VALUE_DIAGOPT(MacroBacktraceLimit, 32, DefaultMacroBacktraceLimit) VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit) /// Limit depth of constexpr backtrace. VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit) +/// Limit number of times to perform spell checking. +VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit) VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops. /// Column limit for formatting message diagnostics, or 0 if unused. @@ -92,4 +94,3 @@ VALUE_DIAGOPT(MessageLength, 32, 0) #undef SEMANTIC_DIAGOPT #undef SEMANTIC_ENUM_DIAGOPT #undef SEMANTIC_VALUE_DIAGOPT - diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h index 3e4d0eefbcf9..058e00f73e77 100644 --- a/include/clang/Basic/DiagnosticOptions.h +++ b/include/clang/Basic/DiagnosticOptions.h @@ -33,7 +33,8 @@ public: enum { DefaultTabStop = 8, MaxTabStop = 100, DefaultMacroBacktraceLimit = 6, DefaultTemplateBacktraceLimit = 10, - DefaultConstexprBacktraceLimit = 10 }; + DefaultConstexprBacktraceLimit = 10, + DefaultSpellCheckingLimit = 50 }; // Define simple diagnostic options (with no accessors). #define DIAGOPT(Name, Bits, Default) unsigned Name : Bits; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index b1305e182f0b..239d4d20bb72 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -108,6 +108,9 @@ def ext_alignof_expr : ExtWarn< def warn_microsoft_dependent_exists : Warning< "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, InGroup<DiagGroup<"microsoft-exists">>; +def warn_microsoft_qualifiers_ignored : Warning< + "qualifiers after comma in declarator list are ignored">, + InGroup<IgnoredAttributes>; def ext_c11_generic_selection : Extension< "generic selections are a C11-specific feature">, InGroup<C11>; @@ -121,11 +124,15 @@ def ext_c11_alignment : Extension< def ext_c11_noreturn : Extension< "_Noreturn functions are a C11-specific feature">, InGroup<C11>; +def err_c11_noreturn_misplaced : Error< + "'_Noreturn' keyword must precede function declarator">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup<GNULabelsAsValue>; def ext_gnu_address_of_label : Extension< "use of GNU address-of-label extension">, InGroup<GNULabelsAsValue>; +def err_stmtexpr_file_scope : Error< + "statement expression not allowed at file scope">; def ext_gnu_statement_expr : Extension< "use of GNU statement expression extension">, InGroup<GNUStatementExpression>; def ext_gnu_conditional_expr : Extension< @@ -167,6 +174,9 @@ def err_expected_fn_body : Error< def warn_attribute_on_function_definition : Warning< "GCC does not allow %0 attribute in this position on a function definition">, InGroup<GccCompat>; +def warn_gcc_attribute_location : Warning< + "GCC does not allow an attribute in this position on a function declaration">, + InGroup<GccCompat>; def warn_attribute_no_decl : Warning< "attribute %0 ignored, because it is not attached to a declaration">, InGroup<IgnoredAttributes>; @@ -194,11 +204,19 @@ def err_expected_semi_after_namespace_name : Error< "expected ';' after namespace name">; def err_unexpected_namespace_attributes_alias : Error< "attributes cannot be specified on namespace alias">; +def err_unexpected_nested_namespace_attribute : Error< + "attributes cannot be specified on a nested namespace definition">; def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; def err_namespace_nonnamespace_scope : Error< "namespaces can only be defined in global or namespace scope">; -def err_nested_namespaces_with_double_colon : Error< - "nested namespace definition must define each namespace separately">; +def ext_nested_namespace_definition : ExtWarn< + "nested namespace definition is a C++1z extension; " + "define each namespace separately">, InGroup<CXX1z>; +def warn_cxx14_compat_nested_namespace_definition : Warning< + "nested namespace definition is incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_inline_nested_namespace_definition : Error< + "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< "expected ';' after attribute list">; def err_expected_semi_after_static_assert : Error< @@ -268,22 +286,17 @@ def ext_auto_storage_class : ExtWarn< "'auto' storage class specifier is not permitted in C++11, and will not " "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>; def ext_decltype_auto_type_specifier : ExtWarn< - "'decltype(auto)' type specifier is a C++1y extension">, InGroup<CXX1y>; + "'decltype(auto)' type specifier is a C++14 extension">, InGroup<CXX14>; def warn_cxx11_compat_decltype_auto_type_specifier : Warning< "'decltype(auto)' type specifier is incompatible with C++ standards before " - "C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore; + "C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup<CXX11>; def warn_cxx98_compat_for_range : Warning< "range-based for loop is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -def ext_for_range_identifier : ExtWarn< - "range-based for loop with implicit deduced type is a C++1z extension">, - InGroup<CXX1z>; -def warn_cxx1y_compat_for_range_identifier : Warning< - "range-based for loop with implicit deduced type is incompatible with " - "C++ standards before C++1z">, - InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_for_range_identifier : Error< + "range-based for loop requires type for loop variable">; def err_for_range_expected_decl : Error< "for range declaration must declare a variable">; def err_argument_required_after_attribute : Error< @@ -303,6 +316,8 @@ def err_expected_class_name_not_template : Error<"'typename' is redundant; base classes are implicitly types">; def err_unspecified_vla_size_with_static : Error< "'static' may not be used with an unspecified variable length array size">; +def err_unspecified_size_with_static : Error< + "'static' may not be used without an array size">; def warn_deprecated_register : Warning< "'register' storage class specifier is deprecated">, InGroup<DeprecatedRegister>; @@ -332,10 +347,12 @@ def err_invalid_vector_decl_spec_combination : Error< def err_invalid_pixel_decl_spec_combination : Error< "'__pixel' must be preceded by '__vector'. " "'%0' declaration specifier not allowed here">; -def err_invalid_vector_decl_spec : Error< - "cannot use '%0' with '__vector'">; def err_invalid_vector_bool_decl_spec : Error< "cannot use '%0' with '__vector bool'">; +def err_invalid_vector_double_decl_spec : Error < + "use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)">; +def err_invalid_vector_long_double_decl_spec : Error< + "cannot use 'long double' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>; def err_friend_invalid_in_context : Error< @@ -363,6 +380,8 @@ def err_function_definition_not_allowed : Error< "function definition is not allowed here">; def err_expected_end_of_enumerator : Error< "expected '= constant-expression' or end of enumerator definition">; +def err_expected_coloncolon_after_super : Error< + "expected '::' after '__super'">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< @@ -477,6 +496,8 @@ def ext_ellipsis_exception_spec : Extension< InGroup<Microsoft>; def err_dynamic_and_noexcept_specification : Error< "cannot have both throw() and noexcept() clause on the same function">; +def err_except_spec_unparsed : Error< + "unexpected end of exception specification">; def warn_cxx98_compat_noexcept_decl : Warning< "noexcept specifications are incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; @@ -487,6 +508,8 @@ def err_constructor_bad_name : Error< "missing return type for function %0; did you mean the constructor name %1?">; def err_destructor_tilde_identifier : Error< "expected a class name after '~' to name a destructor">; +def err_destructor_tilde_scope : Error< + "'~' in destructor name should be after nested name specifier">; def err_destructor_template_id : Error< "destructor name %0 does not refer to a template">; def err_default_arg_unparsed : Error< @@ -498,11 +521,24 @@ def note_bracket_depth : Note< def err_misplaced_ellipsis_in_declaration : Error< "'...' must %select{immediately precede declared identifier|" "be innermost component of anonymous pack declaration}0">; +def warn_misplaced_ellipsis_vararg : Warning< + "'...' in this location creates a C-style varargs function" + "%select{, not a function parameter pack|}0">, + InGroup<DiagGroup<"ambiguous-ellipsis">>; +def note_misplaced_ellipsis_vararg_existing_ellipsis : Note< + "preceding '...' declares a function parameter pack">; +def note_misplaced_ellipsis_vararg_add_ellipsis : Note< + "place '...' %select{immediately before declared identifier|here}0 " + "to declare a function parameter pack">; +def note_misplaced_ellipsis_vararg_add_comma : Note< + "insert ',' before '...' to silence this warning">; def ext_abstract_pack_declarator_parens : ExtWarn< "ISO C++11 requires a parenthesized pack declaration to have a name">, InGroup<DiagGroup<"anonymous-pack-parens">>; def err_function_is_not_record : Error< "unexpected %0 in function call; perhaps remove the %0?">; +def err_super_in_using_declaration : Error< + "'__super' cannot be used with a using declaration">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; @@ -529,6 +565,10 @@ 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< + "attributes on %select{a namespace|an enumerator}0 declaration are " + "incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def warn_cxx98_compat_attribute : Warning< @@ -564,6 +604,8 @@ def err_ms_property_expected_accessor_name : Error< "expected name of accessor method">; def err_ms_property_expected_comma_or_rparen : Error< "expected ',' or ')' at end of property accessor list">; +def err_ms_property_initializer : Error< + "property declaration cannot have an in-class initializer">; /// C++ Templates def err_expected_template : Error<"expected template">; @@ -576,7 +618,7 @@ def err_class_on_template_template_param : Error< def ext_template_template_param_typename : ExtWarn< "template template parameter using 'typename' is a C++1z extension">, InGroup<CXX1z>; -def warn_cxx1y_compat_template_template_param_typename : Warning< +def warn_cxx14_compat_template_template_param_typename : Warning< "template template parameter using 'typename' is " "incompatible with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; @@ -597,14 +639,16 @@ def warn_cxx11_right_shift_in_template_arg : Warning< def warn_cxx98_compat_two_right_angle_brackets : Warning< "consecutive right angle brackets are incompatible with C++98 (use '> >')">, InGroup<CXX98Compat>, DefaultIgnore; +def err_templated_invalid_declaration : Error< + "a static_assert declaration cannot be a template">; def err_multiple_template_declarators : Error< - "%select{|a template declaration|an explicit template specialization|" - "an explicit template instantiation}0 can " - "only %select{|declare|declare|instantiate}0 a single entity">; + "%select{|a template declaration|an explicit template specialization|" + "an explicit template instantiation}0 can " + "only %select{|declare|declare|instantiate}0 a single entity">; def err_explicit_instantiation_with_definition : Error< - "explicit template instantiation cannot have a definition; if this " - "definition is meant to be an explicit specialization, add '<>' after the " - "'template' keyword">; + "explicit template instantiation cannot have a definition; if this " + "definition is meant to be an explicit specialization, add '<>' after the " + "'template' keyword">; def err_template_defn_explicit_instantiation : Error< "%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this " "declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">; @@ -612,7 +656,7 @@ def err_friend_explicit_instantiation : Error< "friend cannot be declared in an explicit instantiation; if this " "declaration is meant to be a friend declaration, remove the 'template' keyword">; def err_explicit_instantiation_enum : Error< - "enumerations cannot be explicitly instantiated">; + "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; def err_missing_dependent_template_keyword : Error< @@ -654,7 +698,18 @@ def err_explicit_spec_non_template : Error< def err_default_template_template_parameter_not_template : Error< "default template argument for a template template parameter must be a class " "template">; - + +def ext_fold_expression : ExtWarn< + "pack fold expression is a C++1z extension">, + InGroup<CXX1z>; +def warn_cxx14_compat_fold_expression : Warning< + "pack fold expression is incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; +def err_expected_fold_operator : Error< + "expected a foldable binary operator in fold expression">; +def err_fold_operator_mismatch : Error< + "operators in fold expression must be the same">; + def err_ctor_init_missing_comma : Error< "missing ',' between base or member initializers">; @@ -699,7 +754,7 @@ def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; def err_alias_declaration_specialization : Error< "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; - + // C++11 override control def ext_override_control_keyword : ExtWarn< "'%0' keyword is a C++11 extension">, InGroup<CXX11>; @@ -751,6 +806,9 @@ def err_lambda_missing_parens : Error< // Availability attribute def err_expected_version : Error< "expected a version of the form 'major[.minor[.subminor]]'">; +def warn_expected_consistent_version_separator : Warning< + "use same version number separators '_' or '.'; as in " + "'major[.minor[.subminor]]'">, InGroup<Availability>; def err_zero_version : Error< "version number must have non-zero major, minor, or sub-minor version">; def err_availability_expected_platform : Error< @@ -818,7 +876,7 @@ def warn_pragma_expected_non_wide_string : Warning< "expected non-wide string literal in '#pragma %0'">, InGroup<IgnoredPragmas>; // - Generic errors def err_pragma_missing_argument : Error< - "missing argument to '#pragma %0'; expected %1">; + "missing argument to '#pragma %0'%select{|; expected %2}1">; // - #pragma options def warn_pragma_options_expected_align : Warning< "expected 'align' following '#pragma options' - ignored">, @@ -878,8 +936,8 @@ def err_pragma_optimize_extra_argument : Error< "unexpected extra argument '%0' to '#pragma clang optimize'">; // OpenCL Section 6.8.g -def err_not_opencl_storage_class_specifier : Error< - "OpenCL does not support the '%0' storage class specifier">; +def err_opencl_unknown_type_specifier : Error< + "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">; // OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) def warn_pragma_expected_colon : Warning< @@ -923,9 +981,14 @@ def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; // Pragma loop support. +def err_pragma_loop_missing_argument : Error< + "missing argument; expected %select{an integer value|" + "'%select{enable|full}1' or 'disable'}0">; def err_pragma_loop_invalid_option : Error< "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, " "vectorize_width, interleave, interleave_count, unroll, or unroll_count">; +def err_pragma_invalid_keyword : Error< + "invalid argument; expected '%select{enable|full}0' or 'disable'">; // Pragma unroll support. def warn_pragma_unroll_cuda_value_in_parens : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1665a45e2cbf..8966c55d0963 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -64,6 +64,9 @@ def err_typecheck_converted_constant_expression : Error< "value of type %0 is not implicitly convertible to %1">; def err_typecheck_converted_constant_expression_disallowed : Error< "conversion from %0 to %1 is not allowed in a converted constant expression">; +def err_typecheck_converted_constant_expression_indirect : Error< + "conversion from %0 to %1 in converted constant expression would " + "bind reference to a temporary">; def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|array size}0 " "is not a constant expression">; @@ -84,6 +87,9 @@ def note_ice_conversion_here : Note< def err_ice_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; +def err_ice_too_large : Error< + "integer constant expression evaluates to value %0 that cannot be " + "represented in a %1-bit %select{signed|unsigned}2 integer type">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< @@ -172,6 +178,9 @@ def warn_unused_parameter : Warning<"unused parameter %0">, InGroup<UnusedParameter>, DefaultIgnore; def warn_unused_variable : Warning<"unused variable %0">, InGroup<UnusedVariable>, DefaultIgnore; +def warn_unused_local_typedef : Warning< + "unused %select{typedef|type alias}0 %1">, + InGroup<UnusedLocalTypedef>, DefaultIgnore; def warn_unused_property_backing_ivar : Warning<"ivar %0 which backs the property is not " "referenced in this property's accessor">, @@ -445,9 +454,13 @@ def note_strncat_wrong_size : Note< "the terminating null byte">; def warn_assume_side_effects : Warning< - "the argument to __assume has side effects that will be discarded">, + "the argument to %0 has side effects that will be discarded">, InGroup<DiagGroup<"assume">>; +def warn_memcpy_chk_overflow : Warning< + "%0 will always overflow destination buffer">, + InGroup<DiagGroup<"builtin-memcpy-chk-size">>; + /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, @@ -521,6 +534,11 @@ def warn_cxx_ms_struct : "with base classes or virtual functions">, DefaultError, InGroup<IncompatibleMSStruct>; def err_section_conflict : Error<"%0 causes a section type conflict with %1">; +def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; +def err_invalid_super_scope : Error<"invalid use of '__super', " + "this keyword can only be used inside class or member function scope">; +def err_super_in_lambda_unsupported : Error< + "use of '__super' inside a lambda is unsupported">; def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, @@ -536,10 +554,10 @@ def err_pragma_pop_visibility_mismatch : Error< "#pragma visibility pop with no matching #pragma visibility push">; def note_surrounding_namespace_starts_here : Note< "surrounding namespace with visibility attribute starts here">; -def err_pragma_loop_invalid_value : Error< - "invalid argument; expected a positive integer value">; -def err_pragma_loop_invalid_keyword : Error< - "invalid argument; expected 'enable' or 'disable'">; +def err_pragma_loop_invalid_argument_type : Error< + "invalid argument of type %0; expected an integer type">; +def err_pragma_loop_invalid_argument_value : Error< + "%select{invalid value '%0'; must be positive|value '%0' is too large}1">; def err_pragma_loop_compatibility : Error< "%select{incompatible|duplicate}0 directives '%1' and '%2'">; def err_pragma_loop_precedes_nonloop : Error< @@ -563,14 +581,19 @@ def err_protocol_has_circular_dependency : Error< "protocol has circular dependency">; def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; +def warn_atprotocol_protocol : Warning< + "@protocol is using a forward protocol declaration of %0">, InGroup<AtProtocol>; def warn_readonly_property : Warning< "attribute 'readonly' of property %0 restricts attribute " - "'readwrite' of property inherited from %1">; + "'readwrite' of property inherited from %1">, + InGroup<PropertyAttr>; def warn_property_attribute : Warning< - "'%1' attribute on property %0 does not match the property inherited from %2">; + "'%1' attribute on property %0 does not match the property inherited from %2">, + InGroup<PropertyAttr>; def warn_property_types_are_incompatible : Warning< - "property type %0 is incompatible with type %1 inherited from %2">; + "property type %0 is incompatible with type %1 inherited from %2">, + InGroup<DiagGroup<"incompatible-property-type">>; def warn_protocol_property_mismatch : Warning< "property of type %0 was selected for synthesis">, InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>; @@ -587,6 +610,8 @@ def note_class_declared : Note< "class is declared here">; def note_receiver_class_declared : Note< "receiver is instance of class declared here">; +def note_receiver_expr_here : Note< + "receiver expression is here">; def note_receiver_is_id : Note< "receiver is treated with 'id' type for purpose of method lookup">; def note_suppressed_class_declare : Note< @@ -696,7 +721,8 @@ def warn_implements_nscopying : Warning< "default assign attribute on property %0 which implements " "NSCopying protocol is not appropriate with -fobjc-gc[-only]">; -def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; +def warn_multiple_method_decl : Warning<"multiple methods named %0 found">, + InGroup<ObjCMultipleMethodNames>; def warn_strict_multiple_method_decl : Warning< "multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore; def warn_accessor_property_type_mismatch : Warning< @@ -710,6 +736,11 @@ def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_duplicate_method_decl : Warning<"multiple declarations of method %0 found and ignored">, InGroup<MethodDuplicate>, DefaultIgnore; +def warn_objc_cdirective_format_string : + Warning<"using %0 directive in %select{NSString|CFString}1 " + "which is being passed as a formatting argument to the formatting " + "%select{method|CFfunction}2">, + InGroup<ObjCCStringFormat>, DefaultIgnore; def err_objc_var_decl_inclass : Error<"cannot declare variable inside @interface or @protocol">; def error_missing_method_context : Error< @@ -738,7 +769,8 @@ def warn_objc_property_default_assign_on_object : Warning< "default property attribute 'assign' not appropriate for non-GC object">, InGroup<ObjCPropertyNoAttribute>; def warn_property_attr_mismatch : Warning< - "property attribute in class extension does not match the primary class">; + "property attribute in class extension does not match the primary class">, + InGroup<PropertyAttr>; def warn_property_implicitly_mismatched : Warning < "primary property declaration is implicitly strong while redeclaration " "in class extension is weak">, @@ -778,6 +810,11 @@ def warn_no_autosynthesis_property : Warning< "%0 because it is 'readwrite' but it will be synthesized 'readonly' " "via another property">, InGroup<ObjCNoPropertyAutoSynthesis>; +def warn_autosynthesis_property_in_superclass : Warning< + "auto property synthesis will not synthesize property " + "%0; it will be implemented by its superclass, use @dynamic to " + "acknowledge intention">, + InGroup<ObjCNoPropertyAutoSynthesis>; def warn_autosynthesis_property_ivar_match :Warning< "autosynthesized property %0 will use %select{|synthesized}1 instance variable " "%2, not existing instance variable %3">, @@ -927,7 +964,7 @@ def err_static_assert_expression_is_not_constant : Error< def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; def ext_static_assert_no_message : ExtWarn< "static_assert with no message is a C++1z extension">, InGroup<CXX1z>; -def warn_cxx1y_compat_static_assert_no_message : Warning< +def warn_cxx14_compat_static_assert_no_message : Warning< "static_assert with no message is incompatible with C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>; @@ -1085,6 +1122,8 @@ def warn_missing_exception_specification : Warning< "%0 is missing exception specification '%1'">; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; +def err_exception_spec_not_parsed : Error< + "exception specification is not available until end of class definition">; // C++ access checking def err_class_redeclared_with_different_access : Error< @@ -1098,7 +1137,7 @@ def ext_ms_using_declaration_inaccessible : ExtWarn< def err_access_ctor : Error< "calling a %select{private|protected}0 constructor of class %2">, AccessControl; -def ext_rvalue_to_reference_access_ctor : ExtWarn< +def ext_rvalue_to_reference_access_ctor : Extension< "C++98 requires an accessible copy constructor for class %2 when binding " "a reference to a temporary; was %select{private|protected}0">, AccessControl, InGroup<BindToTemporaryCopy>; @@ -1462,6 +1501,9 @@ def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">, InGroup<Uninitialized>; +def warn_base_class_is_uninit : Warning< + "base class %0 is uninitialized when used here to access %q1">, + InGroup<Uninitialized>; def warn_reference_field_is_uninit : Warning< "reference %0 is not yet bound to a value when used here">, InGroup<Uninitialized>; @@ -1505,6 +1547,9 @@ def note_block_var_fixit_add_initialization : Note< def note_in_omitted_aggregate_initializer : Note< "in implicit initialization of %select{array element %1|field %1}0 " "with omitted initializer">; +def note_in_reference_temporary_list_initializer : Note< + "in initialization of temporary of type %0 created to " + "list-initialize this reference">; def note_var_fixit_add_initialization : Note< "initialize the variable %0 to silence this warning">; def note_uninit_fixit_remove_cond : Note< @@ -1522,7 +1567,7 @@ def err_temp_copy_no_viable : Error< "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1">; -def ext_rvalue_to_reference_temp_copy_no_viable : ExtWarn< +def ext_rvalue_to_reference_temp_copy_no_viable : Extension< "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" @@ -1594,9 +1639,9 @@ def err_auto_new_ctor_multiple_expressions : Error< "new expression for type %0 contains multiple constructor arguments">; def err_auto_missing_trailing_return : Error< "'auto' return without trailing return type; deduced return types are a " - "C++1y extension">; + "C++14 extension">; def err_deduced_return_type : Error< - "deduced return types are a C++1y extension">; + "deduced return types are a C++14 extension">; def err_trailing_return_without_auto : Error< "function with trailing return type must specify return type 'auto', not %0">; def err_trailing_return_in_parens : Error< @@ -1656,6 +1701,9 @@ def override_keyword_hides_virtual_member_function : Error< "%select{function|functions}1">; def err_function_marked_override_not_overriding : Error< "%0 marked 'override' but does not override any member functions">; +def warn_function_marked_not_override_overriding : Warning < + "%0 overrides a member function but is not marked 'override'">, + InGroup<CXX11WarnOverrideMethod>; def err_class_marked_final_used_as_base : Error< "base %0 is marked '%select{final|sealed}1'">; def warn_abstract_final_class : Warning< @@ -1745,10 +1793,10 @@ def note_for_range_begin_end : Note< def warn_cxx98_compat_constexpr : Warning< "'constexpr' specifier is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; -// FIXME: Maybe this should also go in -Wc++1y-compat? -def warn_cxx1y_compat_constexpr_not_const : Warning< +// FIXME: Maybe this should also go in -Wc++14-compat? +def warn_cxx14_compat_constexpr_not_const : Warning< "'constexpr' non-static member function will not be implicitly 'const' " - "in C++1y; add 'const' to avoid a change in behavior">, + "in C++14; add 'const' to avoid a change in behavior">, InGroup<DiagGroup<"constexpr-not-const">>; def err_invalid_constexpr : Error< "%select{function parameter|typedef|non-static data member}0 " @@ -1790,28 +1838,28 @@ def err_constexpr_body_invalid_stmt : Error< "statement not allowed in constexpr %select{function|constructor}0">; def ext_constexpr_body_invalid_stmt : ExtWarn< "use of this statement in a constexpr %select{function|constructor}0 " - "is a C++1y extension">, InGroup<CXX1y>; + "is a C++14 extension">, InGroup<CXX14>; def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning< "use of this statement in a constexpr %select{function|constructor}0 " - "is incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompat>, DefaultIgnore; + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; def ext_constexpr_type_definition : ExtWarn< "type definition in a constexpr %select{function|constructor}0 " - "is a C++1y extension">, InGroup<CXX1y>; + "is a C++14 extension">, InGroup<CXX14>; def warn_cxx11_compat_constexpr_type_definition : Warning< "type definition in a constexpr %select{function|constructor}0 " - "is incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompat>, DefaultIgnore; + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; def err_constexpr_vla : Error< "variably-modified type %0 cannot be used in a constexpr " "%select{function|constructor}1">; def ext_constexpr_local_var : ExtWarn< "variable declaration in a constexpr %select{function|constructor}0 " - "is a C++1y extension">, InGroup<CXX1y>; + "is a C++14 extension">, InGroup<CXX14>; def warn_cxx11_compat_constexpr_local_var : Warning< "variable declaration in a constexpr %select{function|constructor}0 " - "is incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompat>, DefaultIgnore; + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; def err_constexpr_local_var_static : Error< "%select{static|thread_local}1 variable not permitted in a constexpr " "%select{function|constructor}0">; @@ -1828,16 +1876,18 @@ def err_enable_if_never_constant_expr : Error< "'enable_if' attribute expression never produces a constant expression">; def err_constexpr_body_no_return : Error< "no return statement in constexpr function">; +def err_constexpr_return_missing_expr : Error< + "non-void constexpr function %0 should return a value">; def warn_cxx11_compat_constexpr_body_no_return : Warning< "constexpr function with no return statements is incompatible with C++ " - "standards before C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore; + "standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; def ext_constexpr_body_multiple_return : ExtWarn< - "multiple return statements in constexpr function is a C++1y extension">, - InGroup<CXX1y>; + "multiple return statements in constexpr function is a C++14 extension">, + InGroup<CXX14>; def warn_cxx11_compat_constexpr_body_multiple_return : Warning< "multiple return statements in constexpr function " - "is incompatible with C++ standards before C++1y">, - InGroup<CXXPre1yCompat>, DefaultIgnore; + "is incompatible with C++ standards before C++14">, + InGroup<CXXPre14Compat>, DefaultIgnore; def note_constexpr_body_previous_return : Note< "previous return statement is here">; def err_constexpr_function_try_block : Error< @@ -1848,8 +1898,6 @@ def err_constexpr_ctor_missing_init : Error< "constexpr constructor must initialize all members">; def note_constexpr_ctor_missing_init : Note< "member not initialized by constructor">; -def err_constexpr_method_non_literal : Error< - "non-literal type %0 cannot have constexpr members">; def note_non_literal_no_constexpr_ctors : Note< "%0 is not literal because it is not an aggregate and has no constexpr " "constructors other than copy or move constructors">; @@ -1897,8 +1945,12 @@ def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; def err_attribute_unsupported : Error< "%0 attribute is not supported for this target">; +// The err_*_attribute_argument_not_int are seperate because they're used by +// VerifyIntegerConstantExpression. def err_aligned_attribute_argument_not_int : Error< "'aligned' attribute requires integer constant">; +def err_align_value_attribute_argument_not_int : Error< + "'align_value' attribute requires integer constant">; def err_alignas_attribute_wrong_decl_type : Error< "%0 attribute cannot be applied to a %select{function parameter|" "variable with 'register' storage class|'catch' variable|bit-field}1">; @@ -1934,12 +1986,22 @@ def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>; def warn_attribute_return_pointers_only : Warning< "%0 attribute only applies to return values that are pointers">, InGroup<IgnoredAttributes>; +def warn_attribute_return_pointers_refs_only : Warning< + "%0 attribute only applies to return values that are pointers or references">, + InGroup<IgnoredAttributes>; +def warn_attribute_pointer_or_reference_only : Warning< + "%0 attribute only applies to a pointer or reference (%1 is invalid)">, + InGroup<IgnoredAttributes>; def err_attribute_no_member_pointers : Error< "%0 attribute cannot be used with pointers to members">; def err_attribute_invalid_implicit_this_argument : Error< "%0 attribute is invalid for the implicit this argument">; def err_ownership_type : Error< "%0 attribute only applies to %select{pointer|integer}1 arguments">; +def err_ownership_returns_index_mismatch : Error< + "'ownership_returns' attribute index does not match; here it is %0">; +def note_ownership_returns_index_mismatch : Note< + "declared with index %0 here">; def err_format_strftime_third_parameter : Error< "strftime format attribute requires 3rd parameter to be 0">; def err_format_attribute_requires_variadic : Error< @@ -2054,14 +2116,22 @@ def err_no_accessor_for_property : Error< def error_cannot_find_suitable_accessor : Error< "cannot find suitable %select{getter|setter}0 for property %1">; -def err_attribute_aligned_not_power_of_two : Error< +def err_alignment_not_power_of_two : Error< "requested alignment is not a power of 2">; + def err_attribute_aligned_too_great : Error< "requested alignment must be %0 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< - "%q0 redeclared without %1 attribute: previous %1 ignored">; + "%q0 redeclared without %1 attribute: previous %1 ignored">, + InGroup<DiagGroup<"inconsistent-dllimport">>; +def warn_dllimport_dropped_from_inline_function : Warning< + "%q0 redeclared inline; %1 attribute ignored">, + InGroup<IgnoredAttributes>; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup<IgnoredAttributes>; +def warn_attribute_ignored_on_inline : + Warning<"%0 attribute ignored on inline function">, + InGroup<IgnoredAttributes>; def warn_attribute_after_definition_ignored : Warning< "attribute %0 after definition is ignored">, InGroup<IgnoredAttributes>; @@ -2110,6 +2180,8 @@ def err_declspec_thread_on_thread_variable : Error< "thread-local storage specifier">; def err_attribute_dll_not_extern : Error< "%q0 must have external linkage when declared %q1">; +def err_attribute_dll_thread_local : Error< + "%q0 cannot be thread local when declared %q1">; def warn_attribute_invalid_on_definition : Warning< "'%0' attribute cannot be specified on a definition">, InGroup<IgnoredAttributes>; @@ -2139,7 +2211,7 @@ def warn_attribute_dll_instantiated_base_class : Warning< "propagating dll attribute to %select{already instantiated|explicitly specialized}0 " "base class template " "%select{without dll attribute|with different dll attribute}1 is not supported">, - InGroup<DiagGroup<"unsupported-dll-base-class-template">>; + InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore; def err_attribute_weakref_not_static : Error< "weakref declaration must have internal linkage">; def err_attribute_weakref_not_global_context : Error< @@ -2164,22 +2236,25 @@ def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{functions|unions|" "variables and functions|functions and methods|parameters|" "functions, methods and blocks|functions, methods, and classes|" - "functions, methods, and parameters|classes|variables|methods|" + "functions, methods, and parameters|classes|enums|variables|methods|" "variables, functions and labels|fields and global variables|structs|" - "variables, functions and tag types|thread-local variables|" + "variables and typedefs|thread-local variables|" "variables and fields|variables, data members and tag types|" "types and namespaces|Objective-C interfaces|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|Objective-C protocols|" "functions and global variables|structs or typedefs|" - "interface or protocol declarations}1">, + "interface or protocol declarations|kernel functions}1">, InGroup<IgnoredAttributes>; def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>; def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, InGroup<IgnoredAttributes>; +def warn_incomplete_encoded_type : Warning< + "encoding of %0 type is incomplete because %1 component has unknown encoding">, + InGroup<DiagGroup<"encode-type">>; def warn_attribute_requires_functions_or_static_globals : Warning< "%0 only applies to variables with static storage duration and functions">, InGroup<IgnoredAttributes>; @@ -2197,7 +2272,10 @@ def err_cconv_change : Error< def warn_cconv_ignored : Warning< "calling convention %0 ignored for this target">, InGroup<IgnoredAttributes>; def err_cconv_knr : Error< - "function with no prototype cannot use %0 calling convention">; + "function with no prototype cannot use the %0 calling convention">; +def warn_cconv_knr : Warning< + err_cconv_knr.Text>, + InGroup<DiagGroup<"missing-prototype-for-cc">>; def err_cconv_varargs : Error< "variadic function cannot use %0 calling convention">; def warn_cconv_varargs : Warning< @@ -2307,6 +2385,21 @@ def warn_cannot_resolve_lock : Warning< "cannot resolve lock expression">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; +// Thread safety warnings negative capabilities +def warn_acquire_requires_negative_cap : Warning< + "acquiring %0 '%1' requires negative capability '%2'">, + InGroup<ThreadSafetyNegative>, DefaultIgnore; + +// Thread safety warnings on pass by reference +def warn_guarded_pass_by_reference : Warning< + "passing variable '%1' by reference requires holding %0 " + "%select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyReference>, DefaultIgnore; +def warn_pt_guarded_pass_by_reference : Warning< + "passing the value that '%1' points to by reference requires holding %0 " + "%select{'%2'|'%2' exclusively}3">, + InGroup<ThreadSafetyReference>, DefaultIgnore; + // Imprecise thread safety warnings def warn_variable_requires_lock : Warning< "%select{reading|writing}3 variable '%1' requires holding %0 " @@ -2332,9 +2425,15 @@ def warn_fun_requires_lock_precise : InGroup<ThreadSafetyPrecise>, DefaultIgnore; def note_found_mutex_near_match : Note<"found near match '%0'">; +// Verbose thread safety warnings +def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, + InGroup<ThreadSafetyVerbose>, DefaultIgnore; +def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">; +def note_guarded_by_declared_here : Note<"Guarded_by declared here.">; + // Dummy warning that will trigger "beta" warnings from the analysis if enabled. -def warn_thread_safety_beta : Warning< - "Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore; +def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, + InGroup<ThreadSafetyBeta>, DefaultIgnore; // Consumed warnings def warn_use_in_invalid_state : Warning< @@ -2408,7 +2507,7 @@ def warn_non_literal_null_pointer : Warning< "expression which evaluates to zero treated as a null pointer constant of " "type %0">, InGroup<NonLiteralNullConversion>; def warn_impcast_null_pointer_to_integer : Warning< - "implicit conversion of NULL constant to %0">, + "implicit conversion of %select{NULL|nullptr}0 constant to %1">, InGroup<NullConversion>; def warn_impcast_floating_point_to_bool : Warning< "implicit conversion turns floating-point number into bool: %0 to %1">, @@ -2418,6 +2517,10 @@ def warn_impcast_pointer_to_bool : Warning< "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup<PointerBoolConversion>; +def warn_cast_nonnull_to_bool : Warning< + "nonnull parameter '%0' will evaluate to " + "'true' on first encounter">, + InGroup<PointerBoolConversion>; def warn_this_bool_conversion : Warning< "'this' pointer cannot be null in well-defined C++ code; pointer may be " "assumed to always convert to true">, InGroup<UndefinedBoolConversion>; @@ -2430,6 +2533,10 @@ def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup<TautologicalPointerCompare>; +def warn_nonnull_parameter_compare : Warning< + "comparison of nonnull parameter '%0' %select{not |}1" + "equal to a null pointer is %select{true|false}1 on first encounter">, + InGroup<TautologicalPointerCompare>; def warn_this_null_compare : Warning< "'this' pointer cannot be null in well-defined C++ code; comparison may be " "assumed to always evaluate to %select{true|false}0">, @@ -2500,6 +2607,7 @@ def warn_attribute_protected_visibility : InGroup<DiagGroup<"unsupported-visibility">>; def err_mismatched_visibility: Error<"visibility does not match previous declaration">; def note_previous_attribute : Note<"previous attribute is here">; +def note_conflicting_attribute : Note<"conflicting attribute is here">; def note_attribute : Note<"attribute is here">; def err_mismatched_ms_inheritance : Error< "inheritance model does not match %select{definition|previous declaration}0">; @@ -2739,6 +2847,9 @@ def note_ovl_candidate : Note<"candidate " "|volatile and restrict|const, volatile, and restrict}4)}2">; def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; +def note_ovl_candidate_illegal_constructor : Note< + "candidate %select{constructor|template}0 ignored: " + "instantiation %select{takes|would take}0 its own class type by value">; def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " @@ -2756,7 +2867,7 @@ def note_ovl_candidate_instantiation_depth : Note< "candidate template ignored: substitution exceeded maximum template " "instantiation depth">; def note_ovl_candidate_underqualified : Note< - "candidate template ignored: can't deduce a type for %0 which would " + "candidate template ignored: can't deduce a type for %0 that would " "make %2 equal %1">; def note_ovl_candidate_substitution_failure : Note< "candidate template ignored: substitution failure%0%1">; @@ -2962,8 +3073,18 @@ def note_ovl_candidate_bad_target : Note< "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0 not viable: call to " - "%select{__device__|__gl |